Replacing Indy Client

In my application I use Remote DB and Indy HTTP Client simultaneously  and the Server is Sparkle/RemoteDB. This works fine but I would like to replace the Indy stuff on the windows client by the spakle client. I think I do not need to deploy open ssl libs then and can rely on windwos.


I stumpled upon the problem with FOrm Data I send to the server. How can I replace this Indy code 

 params := TIdMultipartFormDataStream.create;
 params.AddFormField('userident', edUser.Text);
 params.AddFormField('password', edPassword.Text);
 ssl := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  try
    http := TIdHTTP.Create(nil);
    try
      http.IOHandler := ssl;
      http.ConnectTimeout := 1000;
      if assigned(params) then
        result := http.post('https://' + Url, params)
      else
        result := http.GET('https://' + Url);
    finally
      http.free;
    end;
  finally
    ssl.free;
    params.free
  end;

Any help is very appreciated. I would like to have no technology mix.

michael

In this case you would have to build the form data content yourself. 

You can still use Indy to build the request content (just use the TIdMultipartFormDataStream class), and then perform the HTTP request using Sparkle sending the content built by the Indy class.

Do you have a tipp how the content is buildt? I also would like to send and receive binary files.

You are already doing that using TIdMultipartFormDataStream. That's simply a stream with the content you need to send. You can then save it to bytes to send to the server:




var
 params: TIdMultipartFormDataStream;
 content: TBytes;
 req: THttpRequest;
 resp: THttpResponse;
 client: THttpClient;
begin
  params := TIdMultipartFormDataStream.create;
  try
    params.AddFormField('userident', edUser.Text);
    params.AddFormField('password', edPassword.Text);
    req := nil;
    resp := nil;
    client := THttpClient.Create;
    try
      req := client.CreateRequest;
      req.Method := 'POST';
      req.Uri := 'https://' + Url;
      SetLength(content, params.Size);
      params.Write(content[0], params.Size);
      req.SetContent(content);
      resp := client.Send(req);
    finally
      client.Free;
      req.Free;
      resp.Free;
    end;
  finally
    params.free
  end;
end;

Wagner R. Landgraf2019-12-13 19:11:30

Thanks a lot!

Sorry for buggng again - This is my translation of one of my indy based access routines, something goes wrong when COntent is filled from Params. I am sure this is obious for you... Thanks for Help:


function SimpleHTTPSRequest(const Url: String; Params: TIdMultipartFormDataStream = nil): String;
var
  Content: TBytes;
  Request: THttpRequest;
  Response: THttpResponse;
  Client: THttpClient;
begin
  Client := THttpClient.Create;
  try
    Request := Client.CreateRequest;
    try
      Request.Uri := 'https://' + Url;
      If Params = nil then
        Request.Method := 'GET'
      else
      begin
        Request.Method := 'POST';
        SetLength(Content, Params.Size);
        Params.Write(Content[0], Params.Size);
        Request.SetContent(Content);
      end;
      try
        Response := Client.Send(Request);
        if Response.StatusCode = 200 then
          result := TEncoding.UTF8.GetString(Response.ContentAsBytes)
        else
          result := '';
      finally
        Response.free;
      end;
    finally
      Request.free;
    end;
  finally
    Client.free;
  end;
end;

Something was lost above: On Params.Write(COntent... the Error occurs: "Operation not supported."

Found the cause in the Indy source - writing the stream is not supported:


function TIdMultiPartFormDataStream.IdWrite(const ABuffer: TIdBytes; AOffset, ACount: Longint): Longint;
begin
  raise EIdUnsupportedOperation.Create(RSUnsupportedOperation);
end;

Is there any Tutorial on how to build the content for mutilform data from scrantch including sending a file?

Your original code didn't use Write. From what I see, TidMultiPartFormDataStream doesn't allow you to write to the stream directly, but instead you should use the higher level methods, like you did in your first post:




    function AddFormField(const AFieldName, AFieldValue: string; const ACharset: string = ''; const AContentType: string = ''; const AFileName: string = ''): TIdFormDataField; overload;
    function AddFormField(const AFieldName, AContentType, ACharset: string; AFieldValue: TStream; const AFileName: string = ''): TIdFormDataField; overload;
    function AddObject(const AFieldName, AContentType, ACharset: string; AFileData: TObject; const AFileName: string = ''): TIdFormDataField; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use overloaded version of AddFormField()'{$ENDIF};{$ENDIF}
    function AddFile(const AFieldName, AFileName: String; const AContentType: string = ''): TIdFormDataField;