Search code examples
web-servicesdelphihttpindydelphi-xe3

Error on TIdHTTP on Setting Host and Port at Runtime for SMS web service delivery


I am trying to use an SMS API for Delphi from http://www.human.com.br but I get an 'access violation' error when the component tries to set the host and port of the webservice after creating an instance of Indy's TIdHTTP.

host := TidHTTP.Create; 
host.Socket.Port := 80; // error right here!
host.Socket.Host := 'system.human.com.br';
uri := TidURI.Create();

The original component was created in Indy60 and I have Indy170, so the was no Socket between host and Port and I had to put it.

What is wrong? I tried to put the component directly on the form and in the button code I did the Socket settings and I get the same error too!


The send method they use is this:

 data := TIdMultiPartFormDataStream.Create;
 host.Request.ContentType := 'application/x-www-form-urlencoded';
 host.Post(strSMStext , data);

Solution

  • The Socket property is a special property that provides easier access to socket-specific functionality when the current IOHandler property value points at a TIdIOHandlerSocket descendant component. It is nil otherwise. You should NOT be setting the Socket.Host and Socket.Port properties directly. TIdTCPClient.Connect() handles that internally for you. To set a Host/Port, you need to use the TIdTCPClient.Host and TIdTCPClient.Port properties instead. However, TIdHTTP is an exception to that rule, because TIdHTTP sets the Host/Port properties internally for you based on the URL you pass to it, eg:

    host := TidHTTP.Create; 
    host.Get('http://system.human.com.br/', ...); // <-- sets Host and Port for you!
    

    host := TidHTTP.Create; 
    host.Post('http://system.human.com.br/', ...); // <-- sets Host and Port for you!
    

    So DO NOT set the Host/Port properties manually at all. That has always been true in every Indy version that has a TIdHTTP component.

    Posting a TIdMultiPartFormDataStream object forces the Content-Type header to be multipart/form-data. You cannot override that. Trying to send MIME-encoded data using application/x-www-form-urlencoded is just plain wrong. If you really want to send application/x-www-form-urlencoded data, you need to post a TStrings object instead, eg:

    data := TStringList.Create;
    data.Add('name=value');
    ...
    host.Post(strSMStext , data);
    

    When posting a TIdMultipartFormDataStream or a TStrings, let TIdHTTP.Post() decide which Content-Type value to use, don't set it manually.

    Looking at the library code you provided a link to, the following changes need to be made:

    1. Remove the assignment of the http.Port and http.Host properties from the TSMSSender constructor.

    2. in TSMSSender.SimpleSend(), prepend the desired Host to the URL being created:

      //StrEnvio := '/GatewayIntegration/msgSms.do?dispatch=send' +
      StrEnvio := 'http://system.human.com.br/GatewayIntegration/msgSms.do?dispatch=send' +
      
    3. in TSMSSender.MultipleSend(), remove the assignment of the http.Request.ContentType property.