Jump to content
philipp.hofmann

curl-example for POST works, Delphi code throws an 404

Recommended Posts

The following curl-test works fine on my machine:

curl -X POST https://pushinglimits.club/api/oauth/upload_single_fit_file -H 'Content-Type: multipart/form-data' -H 'Authorization: Bearer ...' -F 'file=@Philipp_(SF6KICKR)_20231003_1941_Freies_Training_Training.fit'

 

But the corresponding Delphi-Code will return 

10:29:08.213 16488-Info Response: 404 Not Found: <!DOCTYPE html>
<html lang="en"><head><meta charset="utf-8"><title>Error</title></head><body><pre>Cannot POST /oauth/upload_single_fit_file</pre></body></html>

 

What could be a difference between both calls?
I try to join the GenerateBoundary in System.Net.Mime but it's still not working.

Http: TNetHTTPClient;
formData: TMultipartFormData;
headers: TNetHeaders;

Http:=TNetHTTPClient.create(nil);
Http.SecureProtocols := [THTTPSecureProtocol.TLS12];
formData:=TMultipartFormData.create();
headers:=TNetHeaders.create();
setLength(headers, 2);
headers[0]:=TNameValuePair.create('Content-Type', 'multipart/form-data');
headers[1]:=TNameValuePair.create('Authorization', 'Bearer ' + bearer);
formData.AddFile('file', filename);
Http.Post('https://pushinglimits.club/api/oauth/upload_single_fit_file',formData,nil,headers);

 

HttpDiff.png

Share this post


Link to post

Info: I was successful with the following code (using Indy now):

 

      with TIdHTTP.Create(nil) do
      try
        var FIdSSLIOHandlerSocketOpenSSL:TIdSSLIOHandlerSocketOpenSSL:=TIdSSLIOHandlerSocketOpenSSL.Create(nil);
        var Params: TIdMultiPartFormDataStream;
        filename:=StringReplace(Training.filename, '.ictt', '.fit', [rfIgnoreCase]);
        FIdSSLIOHandlerSocketOpenSSL.SSLOptions.Method := sslvTLSv1_2;
        FIdSSLIOHandlerSocketOpenSSL.SSLOptions.SSLVersions := [sslvTLSv1_2];
        IOHandler := FIdSSLIOHandlerSocketOpenSSL;
        Request.ContentType := 'multipart/form-data';
        Request.CustomHeaders.add('Authorization: Bearer ' + bearer);
        Params := TIdMultiPartFormDataStream.Create;
        try
          params.AddFile('file', filename, GetMIMETypeFromFile(filename));
          ResponseStr := Post('https://pushinglimits.club/api/oauth/upload_single_fit_file', Params);
        finally
          Params.Free;
        end;
      finally
        Free;
      end;

  • Like 1

Share this post


Link to post

Is it only me wondering why people are using more and more inline variable declarations in Delphi code?

 

with TIdHTTP.Create(nil) do

try

  var FIdSSLIOHandlerSocketOpenSSL:TIdSSLIOHandlerSocketOpenSSL:=TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  var Params: TIdMultiPartFormDataStream;

Share this post


Link to post

Sorry, this was copy and paste from an example and it's only to demonstrate that there is an alternative approach.

I won't use inline variables in my projects normally.

Share this post


Link to post
11 hours ago, philipp.hofmann said:

What could be a difference between both calls?

Did you notice the URL is different in the response HTML?  The leading /api was removed.  That implies to me (without proof to the contrary - does TNetHTTPClient offer any kind of debug output?) that the server probably didn't like something about the initial request and issued an HTTP redirect to a new URL that happens to not exist.  Sounds like a problem with the way the server is processing TNetHTTPClient's reequest, considering the same request in TIdHTTP works.

Edited by Remy Lebeau
  • Like 2

Share this post


Link to post
11 hours ago, philipp.hofmann said:

Info: I was successful with the following code (using Indy now):

On a side note, you are leaking the SSLIOHandler object.  You are not assigning it an Owner, so you need to Free() it.  Otherwise, I suggest assigning the TIdHTTP at its Owner, eg:

var HTTP := TIdHTTP.Create(nil);
try
  var SSL := TIdSSLIOHandlerSocketOpenSSL.Create(HTTP);
  SSL.SSLOptions.SSLVersions := [sslvTLSv1_2];
  HTTP.IOHandler := SSL;
  HTTP.Request.CustomHeaders.Values['Authorization'] := 'Bearer ' + bearer;
  var Params := TIdMultiPartFormDataStream.Create;
  try
    filename := StringReplace(Training.filename, '.ictt', '.fit', [rfIgnoreCase]);
    params.AddFile('file', filename);
    ResponseStr := HTTP.Post('https://pushinglimits.club/api/oauth/upload_single_fit_file', Params);
  finally
    Params.Free;
  end;
finally
  HTTP.Free;
end;

 

Edited by Remy Lebeau
  • Like 1

Share this post


Link to post
On 10/10/2023 at 6:42 PM, philipp.hofmann said:

headers[1]:=TNameValuePair.create('Authorization', 'Bearer ' + bearer);

I am trying the same and with TNetHttpClient and getting an error:

Error adding header: (87) The parameter is incorrect

 

when I have an authorization header.
 

Share this post


Link to post

I've used TNetHTTPRequest to setup a request with headers successfully like this:

NetHTTPRequest1.CustomHeaders['Content-Type'] = 'text/html';

 

Typical object setup is like this

  NetHTTPClient1 :=  TNetHTTPClient.create(nil);
  NetHTTPRequest1 := TNetHTTPRequest .create(nil);
  NetHTTPRequest1.Client := NetHTTPClient1;

Usage

 

NetHTTPRequest1.post( url , data , outcome );

Edited by hsvandrew

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×