RepeatUntil
RepeatUntil

Reputation: 2320

Delphi - idHTTP upload file using TIdMultipartFormDataStream

I'm trying to upload a file using TIdHTTP. The problem is the access token gets changed when the request is sent to the server.

The access token that I'm using is fJNhDM6TlcpeVmD8h3jFuPJS71sxwZB8bZBXajTRB5TNAcRa6PNXfv4J7mPxIvMdMhjy7oKdTLbsRYthpBCCqGVkj4vlojJ4BRBkLAVIBJ1DZAnMZD

The API returns

HTTP/1.1 400 Bad Request OAuth "invalid_token" "Malformed access token fJNhDM6TlcpeVmD8h3jFu=\r\nPJS71sxwZB8bZBXajTRB5TNAcRa6PNXfv4J7mPxIvMdMhjy7oKdTLbsRYthpBCCqGVkj4v=\r\nlojJ4BRBkLAVIBJ1DZAnMZD"

There is =\r\n added to my token twice.

My code is:

function TFoo.Post(const AToken, guID, AMessage, AImageFileName: string): Boolean;
var
  lParam : TIdMultipartFormDataStream;
begin
  Result := False;
  if not FileExists(AImageFileName) then begin
    LastError := 'File not found ' + AImageFileName;
    Exit;
  end;
  ProxyCheck;
  lParam := TIdMultipartFormDataStream.Create;
  try
    lParam.AddFormField('message', AMessage);
    lParam.AddFormField('access_token', AToken);
    lParam.AddFile('source', AImageFileName);
    idHTTP.Request.ContentType := 'application/x-www-form-urlencoded';
    try
      idHTTP.Post( UrlAPI + guID + '/photos', lParam);
      Result := True;
    except;
      LastError := idHTTP.ResponseText + sLineBreak + idHTTP.Response.WWWAuthenticate.Text;
    end;
  finally
    lParam.Free;
  end;
end;   

What am I missing here ?

Upvotes: 1

Views: 7681

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 595320

By default, AddFormField() sets the TIdFormDataField.ContentTransfer property to MIME's quoted-printable format. That is where the extra =\r\n is coming from. It is a "soft" line break being inserted by quoted-printable every 76 characters. Any server that supports quoted-printable would remove "soft" line breaks during decoding. But maybe your server does not.

If you want to disable the quoted-printable behavior, you can set the ContentTransfer property to either:

  1. a blank string:

    lParam.AddFormField('access_token', AToken).ContentTransfer := '';
    
  2. '7bit' (since it does not contain any non-ASCII characters):

    lParam.AddFormField('access_token', AToken).ContentTransfer := '7bit';
    
  3. '8bit' or binary:

    lParam.AddFormField('access_token', AToken).ContentTransfer := '8bit';
    

    lParam.AddFormField('access_token', AToken).ContentTransfer := 'binary';
    

In this case, I would suggest #1.

On a side note, do not set the HTTP content type when posting a TIdMultipartFormDataStream. Not only are you using the wrong media type to begin with (it should be multipart/form-data instead), but the TIdMultipartFormDataStream version of Post() will simply overwrite it anyway.

function TFoo.Post(const AToken, guID, AMessage, AImageFileName: string): Boolean;
var
  lParam : TIdMultipartFormDataStream;
begin
  Result := False;
  if not FileExists(AImageFileName) then begin
    LastError := 'File not found ' + AImageFileName;
    Exit;
  end;
  ProxyCheck;
  lParam := TIdMultipartFormDataStream.Create;
  try
    lParam.AddFormField('message', AMessage);
    lParam.AddFormField('access_token', AToken).ContentTransfer := '';
    lParam.AddFile('source', AImageFileName);
    try
      idHTTP.Post(UrlAPI + guID + '/photos', lParam);
      Result := True;
    except;
      LastError := idHTTP.ResponseText + sLineBreak + idHTTP.Response.WWWAuthenticate.Text;
    end;
  finally
    lParam.Free;
  end;
end;   

Upvotes: 4

Related Questions