0

I am trying to post a file and some other data to a website in an App that I am writing using Delphi XE8 but it is not working. When I monitor the network traffic using "Microsoft Network Monitor 3.4", the file is only partially sent and none of the other data is sent. I have tried both Indy 10 and the new TNetHTTPClient and got the same result which tells me I am doing something wrong. please help.

Indy Way

procedure TMyClass.SendFile(aUrl: String);
var
  mCookies: TIdCookieManager;
  pHttp: TIdHTTP;
  PostStream: TIdMultiPartFormDataStream;
  ResponseStream: TStringStream;
  fName, mimeStr: String;
begin
  fName := 'Image000.jpg';
  mCookies := TIdCookieManager.Create(nil);
  pHttp := TIdHTTP.Create(nil);
  pHttp.CookieManager := mCookies;
  PostStream:= TIdMultiPartFormDataStream.Create();
  ResponseStream := TStringStream.Create('');
  mimeStr := GetMIMETypeFromFile(fieldValue); // This returns 'image/pjpeg' instead of 'image/jpeg'. I have manually fixed it and it did not change the result
  PostStream.AddFile('sourceFile', fName, mimeStr);
  PostStream.AddFormField('name1', 'value1');
  PostStream.AddFormField('name2', 'value2');
  PostStream.AddFormField('name3', 'value3');
  PostStream.AddFormField('name4', 'value4');
  PostStream.AddFormField('name5', 'value5');
  .
  .
  .
  pHttp.Request.ContentType := PostStream.RequestContentType;
  pHttp.Request.Accept := '*/*';
  pHttp.Request.AcceptLanguage := 'en-us,en';
  pHttp.Request.AcceptEncoding := 'gzip, deflate';
  pHttp.Post(aUrl, PostStream, ResponseStream); // Get a 500 error from server for bad data
  .
  .
  .
  PostStream.Free();
  ResponseStream.Free();
  mCookies.Free();
  pHttp.Free();
end;

by the way GetMIMETypeFromFile returns the wrong value but even if I hardcode the correct one, it does not make any different.

the new XE8 way

procedure TMyClass.SendFile(aUrl: String);
var
  mCookies: TCookieManager;
  pHttp: TNetHTTPClient;
  fName: String;
  mpFormData: TMultipartFormData;
  respData: IHTTPResponse;
begin
  fName := 'Image000.jpg';
  mCookies := TCookieManager.Create();
  pHttp := TNetHTTPClient.Create(nil);
  pHttp.CookieManager := mCookies;
  mpFormData := TMultipartFormData.Create();
  mpFormData.AddFile('sourceFile', fName);
  mpFormData.AddField('name1', 'value1');
  mpFormData.AddField('name2', 'value2');
  mpFormData.AddField('name3', 'value3');
  mpFormData.AddField('name4', 'value4');
  mpFormData.AddField('name5', 'value5');
  .
  .
  .
  pHttp.ContentType := 'multipart/form-data';
  pHttp.Accept := '*/*';
  pHttp.AcceptLanguage := 'en-us,en';
  pHttp.AcceptEncoding := 'gzip, deflate';
  mpFormData.Stream.Position := 0;
  respData := pHttp.Post(aUrl, mpFormData.Stream); //Same problem, error 500 here
  .
  .
  .
  mpFormData.Free();
  pHttp.Free();
  mCookies.Free();
end;

I know the server is working correctly because another application (written in Intel XDA) works just fine. the image is valid, and all the Get calls that I make before this works as well. I really need help. Thank you in advance

TLama
  • 75,147
  • 17
  • 214
  • 392
Sam
  • 2,473
  • 3
  • 18
  • 29

1 Answers1

3

When I monitor the network traffic using "Microsoft Network Monitor 3.4", the file is only partially sent and none of the other data is sent.

Are you sure the monitor is simply not displaying partial data in its UI? A packet sniffer like Wireshark would be more reliable (or attach a TIdLog... component to TIdHTTP), as it will show you everything that is actually being transmitted. The only possible way that posting a TIdMultipartFormDataStream would only send a portion of the file and skip the other fields altogether is if the socket is disconnected while transmitting the file.

mimeStr := GetMIMETypeFromFile(fieldValue); // This returns 'image/pjpeg' instead of 'image/jpeg'.

Internally, GetMIMETypeFromFile() builds its own list of hard-coded MIME types and then uses OS information to overwrite that list. The default value that is hard-coded for .jpg is image/jpeg. When it then queries the OS, it sees image/jpeg and image/pjpeg (in that order) are registered for .jpg, so image/pjpeg was the last MIME type seen for .jpg and that is what GetMIMETypeFromFile() ends up returning.

pHttp.Request.ContentType := PostStream.RequestContentType;

You do not need that, Post() handles that internally for you.

pHttp.Request.AcceptEncoding := 'gzip, deflate';

Do not do that at all. Post() handles that internally for you, based on whether TIdHTTP.Compressor is assigned and ready.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • I created a 'TIdZLibCompressorBase' and assigned it to the 'pHttp.Compressor' and also downloaded and used **Wireshark**. Now I can see that all of the fields are going thru but I am still having issue with the code 500 that is returned by server. you mentioned that image/pjpeg comes from OS. Do you know were I can find and correct that? Thank you – Sam May 15 '15 at 19:37
  • `TIdZLibCompressorBase` is an abstract base class, you cannot use it directly. You need to use a descendant instead, such as `TIdCompressorZLib`. As for the 500 error, there is no way to diagnose that without seeing the actual HTTP request being sent, but it would generally mean that you probably sent a parameter value, or omitted a required parameter, that caused the receiving script to fail. What does the actual HTML webform look like that the script is expecting you to submit? – Remy Lebeau May 15 '15 at 19:39
  • Do you know were I can find and correct the setting that causes the incorrect mime type? – Sam May 15 '15 at 22:20
  • On Windows, Indy gets MIME info from the Registry, in particular from the `HKEY_CLASSES_ROOT\` and `HKEY_CLASSES_ROOT\Mime\Database\Content Type` keys. In this case, `HKEY_CLASSES_ROOT\.jpg` has a `Content Type` value of `image/jpeg`, but `HKEY_CLASSES_ROOT\Mime\Database\Content Type` has both `image/jpeg` and `image/pjpeg` subkeys that both map to the `.jpg` extension. When Indy enumerates `HKEY_CLASSES_ROOT\Mime\Database\Content Type`, the info from the `image/pjpeg` subkey overwrites the info from the `image/jpeg` subkey. – Remy Lebeau May 15 '15 at 22:28