filehttpdelphipostararat-synapse

How to send a file AND other POST data with Synapse


Delphi used: 2007.

Hello,

I have a simple web page with two text input and one file input. Now, for the form to be sent, both the text inputs and the file input have to be filled. With Synapse, I know how to upload a file (HttpPostFile) and how to post data (HttpMethod). However, I don't know how to do both.

After looking at the source code of Synapse, I guess I have to "format" my data with boundaries or something like that. I guess I should have one boundary for my input file and another boundary for my text inputs. I found an article on the subject, but it's about sending email attachments. I tried to reproduce what they said with Synapse, with no results.

Code for HttpPostFile:

function HttpPostFile(const URL, FieldName, FileName: string;
  const Data: TStream; const ResultData: TStrings): Boolean;
var
  HTTP: THTTPSend;
  Bound, s: string;
begin
  Bound := IntToHex(Random(MaxInt), 8) + '_Synapse_boundary';
  HTTP := THTTPSend.Create;
  try
    s := '--' + Bound + CRLF;
    s := s + 'content-disposition: form-data; name="' + FieldName + '";';
    s := s + ' filename="' + FileName +'"' + CRLF;
    s := s + 'Content-Type: Application/octet-string' + CRLF + CRLF;
    WriteStrToStream(HTTP.Document, s);
    HTTP.Document.CopyFrom(Data, 0);
    s := CRLF + '--' + Bound + '--' + CRLF;
    WriteStrToStream(HTTP.Document, s);
    HTTP.MimeType := 'multipart/form-data; boundary=' + Bound;
    Result := HTTP.HTTPMethod('POST', URL);
    if Result then
      ResultData.LoadFromStream(HTTP.Document);
  finally
    HTTP.Free;
  end;
end;

Thank you.


Solution

  • Your code is close. You are only sending your file field but not your text fields. To do all three, try this instead:

    function HttpPostFile(const URL, InputText1FieldName, InputText1, InputText2FieldName, InputText2, InputFileFieldName, InputFileName: string; InputFileData: TStream; ResultData: TStrings): Boolean; 
    var 
      HTTP: THTTPSend; 
      Bound: string; 
    begin 
      Bound := IntToHex(Random(MaxInt), 8) + '_Synapse_boundary'; 
      HTTP := THTTPSend.Create; 
      try 
        WriteStrToStream(HTTP.Document,
          '--' + Bound + CRLF +
          'Content-Disposition: form-data; name=' + AnsiQuotedStr(InputText1FieldName, '"') + CRLF +
          'Content-Type: text/plain' + CRLF +
          CRLF); 
        WriteStrToStream(HTTP.Document, InputText1); 
        WriteStrToStream(HTTP.Document,
          CRLF +
          '--' + Bound + CRLF +
          'Content-Disposition: form-data; name=' + AnsiQuotedStr(InputText2FieldName, '"') + CRLF +
          'Content-Type: text/plain' + CRLF +
          CRLF); 
        WriteStrToStream(HTTP.Document, InputText2); 
        WriteStrToStream(HTTP.Document,
          CRLF +
          '--' + Bound + CRLF +
          'Content-Disposition: form-data; name=' + AnsiQuotedStr(InputFileFieldName, '"') + ';' + CRLF + 
          #9'filename=' + AnsiQuotedStr(InputFileName, '"') + CRLF +
          'Content-Type: application/octet-string' + CRLF +
          CRLF); 
        HTTP.Document.CopyFrom(InputFileData, 0); 
        WriteStrToStream(HTTP.Document,
          CRLF +
          '--' + Bound + '--' + CRLF); 
        HTTP.MimeType := 'multipart/form-data; boundary=' + Bound; 
        Result := HTTP.HTTPMethod('POST', URL); 
        if Result then 
          ResultData.LoadFromStream(HTTP.Document); 
      finally 
        HTTP.Free; 
      end; 
    end; 
    

    If you switch to Indy, you can use its TIdMultipartFormDataStream class:

    function HttpPostFile(const URL, InputText1FieldName, InputText1, InputText2FieldName, InputText2, InputFileFieldName, InputFileName: string; InputFileData: TStream; ResultData: TStrings): Boolean; 
    var 
      HTTP: TIdHTTP; 
      Input: TIdMultipartFormDataStream;
      Output: TMemoryStream;
    begin 
      Result := False;
      try
        Output := TMemoryStream.Create;
        try
          HTTP := TIdHTTP.Create; 
          try 
            Input := TIdMultipartFormDataStream.Create;
            try
              Input.AddFormField(InputText1FieldName, InputText1);
              Input.AddFormField(InputText2FieldName, InputText2);
              Input.AddFormField(InputFileFieldName, 'application/octet-stream', '', InputFileData, InputFileName);
              HTTP.Post(URL, Input, Output);
            finally
              Input.Free;
            end;
          finally
            HTTP.Free;
          end;
          Output.Position := 0;
          ResultData.LoadFromStream(Output);
          Result := True; 
        finally
          Output.Free;
        end;
      except
      end; 
    end;