Search code examples
http-postdelphi-2010indy10

How to post binary jpg file using Indy10 Http?


I have to post a jpg file using TIdHTTP component (Indy 10). What I need is to upload a file to a Drupal 8 field. I can do it with Advanced Rest Client following this documentation:

https://www.drupal.org/docs/8/core/modules/jsonapi-module/file-uploads

https://www.drupal.org/node/3024331#comment-13387295

But I'm tring to do it with Delphi 2010 and Indy 10 without success. I always get a "415 Unsupported media type" error with this detail:

"No route found that matches "Content-Type: multipart/form-data".

This is the code I use:

var
    response: string;
    Params: TIdMultiPartFormDataStream;
begin
    Result := '';

    IdHTTP1.ConnectTimeout := 10000;
    IdHTTP1.Request.Clear;
    IdHTTP1.Request.CustomHeaders.Clear;
    IdHTTP1.Request.BasicAuthentication := false;
    IdHTTP1.Request.ContentType := 'application/octet-stream';
    IdHTTP1.Request.Accept := 'application/vnd.api+json';
    IdHTTP1.Request.ContentLanguage := 'es';
    IdHTTP1.Request.CustomHeaders.AddValue('api-key', 'my_api_key_here');
    IdHTTP1.Request.ContentDisposition:= 'file; filename="testimage.jpg"';

    IdHTTP1.Request.Charset := 'utf-8';
    IdHTTP1.AllowCookies := True;
    IdHTTP1.Request.UserAgent := 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.115 Safari/537.36';
    IdHTTP1.HandleRedirects := True;

    Params := TIdMultiPartFormDataStream.Create;
    try
        try
            Params.AddFile('testimage.jpg','c:\tmp\testimage.jpg','application/octet-stream').ContentTransfer:='binary';
            response:= IdHTTP1.Post('<my_url_to_the_field_as_instructions>', Params);
        except
            on E: Exception do
            begin
                memo1.Lines.add('Error ' + E.message);
            end;
        end;
    finally
        Params.Free;
    end;

Solution

  • You can't post the file using TIdMultiPartFormDataStream, because the server is explicitly telling you that it does not support multipart/form-data requests (calling TIdHTTP.Post() with a TIdMultiPartFormDataStream overwrites the Request.ContentType).

    You will have to post the file use a plain vanilla TStream instead, such as TFileStream:

    var
      response: string;
      PostData: TStream;
    begin
      Result := '';
    
      IdHTTP1.ConnectTimeout := 10000;
      IdHTTP1.Request.Clear;
      IdHTTP1.Request.BasicAuthentication := false;
      IdHTTP1.Request.ContentType := 'application/octet-stream';
      IdHTTP1.Request.Accept := 'application/vnd.api+json';
      IdHTTP1.Request.ContentLanguage := 'es';
      IdHTTP1.Request.CustomHeaders.AddValue('api-key', 'my_api_key_here');
      IdHTTP1.Request.ContentDisposition := 'file; filename="testimage.jpg"';
    
      IdHTTP1.AllowCookies := True;
      IdHTTP1.Request.UserAgent := 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.115 Safari/537.36';
      IdHTTP1.HandleRedirects := True;
    
      PostData := TFileStream.Create('<path_to>\testimage.jpg', fmOpenRead or fmShareDenyWrite);
      try
        try
          response := IdHTTP1.Post('<my_url_to_the_field_as_instructions>', PostData);
        except
          on E: Exception do
          begin
            Memo1.Lines.Add('Error ' + E.message);
          end;
        end;
      finally
        PostData.Free;
      end;
    end;
    

    Alternatively, TIdHTTP has an overload of Post() that takes a file path as input:

    var
      response: string;
    begin
      Result := '';
    
      IdHTTP1.ConnectTimeout := 10000;
      IdHTTP1.Request.Clear;
      IdHTTP1.Request.BasicAuthentication := false;
      IdHTTP1.Request.ContentType := 'application/octet-stream';
      IdHTTP1.Request.Accept := 'application/vnd.api+json';
      IdHTTP1.Request.ContentLanguage := 'es';
      IdHTTP1.Request.CustomHeaders.AddValue('api-key', 'my_api_key_here');
      IdHTTP1.Request.ContentDisposition := 'file; filename="testimage.jpg"';
    
      IdHTTP1.AllowCookies := True;
      IdHTTP1.Request.UserAgent := 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.115 Safari/537.36';
      IdHTTP1.HandleRedirects := True;
    
      try
        response := IdHTTP1.Post('<my_url_to_the_field_as_instructions>', '<path_to>\testimage.jpg');
      except
        on E: Exception do
        begin
          Memo1.Lines.Add('Error ' + E.message);
        end;
      end;
    end;