Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Post a file through https using indy / delphi components

Tags:

https

delphi

indy

I'm trying to upload a file through https by using Indy components in delphi. Here is my code:

HTTP := TIdHTTP.Create(Self)
IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create;   

HTTP.Request.Host           := RemoteHost;
HTTP.Request.Connection     := 'keep-alive';
HTTP.Request.Accept         := 'multipart/mixed';

HTTP.IOHandler              := IOHandler;
HTTP.ConnectTimeout         := 0;
HTTP.ReadTimeout            := 0;


//### CREATE FILE TO SEND           
TestStream := TIdMultipartFormDataStream.Create;
try

  //### POST PARAMETERS
  TestStream.AddFormField('ReceiverId','LOOPTEST');
  TestStream.AddFormField('FileType','LOOPBACK');

  //### ADD FILE        
  TestStream.AddFile('filename','C:\PRUEBA.txt',GetMIMETypeFromFile('C:\PRUEBA.txt'));

  HTTP.Request.ContentType := TestStream.RequestContentType;


  HTTP.Post('https://www.remotehost.com/controller?function=submitfile',TestStream, Resultado);


  memResultado.Lines.Add(Resultado.DataString);


finally
    FreeAndNil(TestStream);
    FreeAndNil(HTTP);
    FreeAndNil(IOHandler);
end;

The server does not send any error. Just the file is not uploaded. Is there something wrong with my code?.

I've spent two days trying to make it work :S.

Any help will be appreciated. I'm using Delphi XE with Indy version 10.1.1.

Update: I used the Indy TIdLog component and here is the result. I cannot find nothing strange:

Stat Connected.
Sent 05/09/2013 12:52:00 p.m.: POST /servlet/controller HTTP/1.1<EOL>Content-Type: application/x-www-form-urlencoded<EOL>Content-Length: 47<EOL>Host: ebmx.extra.client.com<EOL>Accept: text/html, /*<EOL>Accept-Encoding: identity<EOL>User-Agent: Mozilla/3.0 (compatible; Indy Library)<EOL><EOL>
Sent 05/09/2013 12:52:00 p.m.: function=login&username=******&password=******
Recv 05/09/2013 12:52:01 p.m.: HTTP/1.1 200 OK<EOL>Server: Sun-ONE-Web-Server/6.1<EOL>Date: Thu, 05 Sep 2013 17:51:22 GMT<EOL>Content-type: text/html<EOL>Set-cookie: JSESSIONID=8035B4F90EBA1A337E4923520558E5DC;Path=/servlet<EOL>Transfer-encoding: chunked<EOL><EOL>001a<EOL>Success! Member Type is 0<LF><EOL>
Recv 05/09/2013 12:52:01 p.m.: 0<EOL><EOL>
Stat Disconnected.

Stat Connected.
Sent 05/09/2013 12:52:11 p.m.: POST /servlet/controller?function=submitfile HTTP/1.1<EOL>Content-Type: multipart/form-data; boundary=--------090513125207913<EOL>Content-Length: 525<EOL>Host: ebmx.extra.client.com<EOL>Accept: text/html, */*<EOL>Accept-Encoding: identity<EOL>User-Agent: Mozilla/3.0 (compatible; Indy Library)<EOL>Cookie: JSESSIONID=8035B4F90EBA1A337E4923520558E5DC<EOL>Cookie2: $Version="1"<EOL><EOL>
Sent 05/09/2013 12:52:11 p.m.: ----------090513125207913<EOL>Content-Disposition: form-data; name="ReceiverId"<EOL>Content-Type: text/plain<EOL>Content-Transfer-Encoding: quoted-printable<EOL><EOL>LOOPTEST<EOL>----------090513125207913<EOL>Content-Dis‌​position: form-data; name="FileType"<EOL>Content-Type: text/plain<EOL>Content-Transfer-Encoding: quoted-printable<EOL><EOL>LOOPBACK<EOL>----------090513125207913<EOL>Content-Dis‌​position: form-data; name="filename"; filename="PRUEBA.txt"<EOL>Content-Type: text/plain<EOL>Content-Transfer-Encoding: binary<EOL><EOL>UKELELE 2013<EOL>----------090513125207913--<EOL>
Recv 05/09/2013 12:52:15 p.m.: HTTP/1.1 200 OK<EOL>Server: Sun-ONE-Web-Server/6.1<EOL>Date: Thu, 05 Sep 2013 17:51:36 GMT<EOL>Content-type: text/html<EOL>Transfer-encoding: chunked<EOL><EOL>0009<EOL>Failure!<LF><EOL>
Recv 05/09/2013 12:52:16 p.m.: 0<EOL><EOL>  
like image 356
user2730930 Avatar asked Feb 15 '23 10:02

user2730930


1 Answers

HTTP.Request.Host := RemoteHost;

Don't set that manually. TIdHTTP will manage that for you.

HTTP.Request.Accept := 'multipart/mixed';

You are telling the server that you will only accept responses that are multipart/mixed, is that what you really want?

HTTP.Request.ContentType := TestStream.RequestContentType;

Don't set that manually when sending a TIdMultipartFormDataStream, Post() will handle that for you.

HTTP.Post('https://www.remotehost.com/controller?function=submitfile',TestStream, Resultado); memResultado.Lines.Add(Resultado.DataString);

Is the server sending the response in the same charset that you initialized Resultado with? If not, then reading the DataString property may fail and return a blank string (TEncoding does not raise an exception when it fails to encode/decode a string). You should let Indy decode the response data for you, since it knows the response's type and charset:

var
  Resultado: string;

Resultado := HTTP.Post('https://www.remotehost.com/controller?function=submitfile', TestStream);
memResultado.Lines.Add(Resultado);

The server does not send any error. Just the file is not uploaded.

If the server is not sending back an HTTP error response (which would cause TIdHTTP to raise an exception), then it is either:

  1. sending back an HTTP success response, but sending an error message in the response data.

  2. accepting the file, but then discarding it

  3. accepting the file, but saving it under a different path/name than you are expecting.

Hard to say for sure since you did not show the actual HTTP request/response data that is being transmitted.

Update: The server IS sending back an error, using #1 above. The server is sending back an HTTP 200 OK reply, but the content of the reply says 'Failure!' (in fact, your original code should have been logging that message in your TMemo). That is why TIdHTTP is not raising an exception. It only looks for HTTP errors, not error messages in body content. You will have to add extra code to account for that possibility, eg:

Resultado := HTTP.Post('https://www.remotehost.com/controller?function=submitfile', TestStream);
if TextStartsWith(Resultado, 'Failure') then
begin
  // Upload failed, do something...
end;

As for why the server is failing in the first place, you will have to contact the server admin and ask about that. The admin will likely have server-side logs to troubleshoot with.

However, I will mention that TIdMultipartFormDataStream does currently send a Content-Type: text/plain header for text fields, which is fine (even encouraged) for HTML 4 forms, but is not OK (it is forbidden) for HTML 5 forms, and some servers do fail if a Content-Type header is present for a text field. HTML5 only allows it on file fields. This is a known issue with TIdMultipartFormDataStream that is already being worked on, but there is no ETA on when the fix will be available. But you can ask the server admin how the server reacts to that condition.

like image 150
Remy Lebeau Avatar answered Feb 23 '23 12:02

Remy Lebeau