I am trying to create an FMX Android application that needs to upload a file to given host.
The host owner provided me with a following curl
statement to upload a file:
curl -T http://<ip-address>:<port> file.txt
And when called from Windows Command Prompt it produces the following output (IP and port redacted):
* Trying <ip-address>...
* TCP_NODELAY set
* Connected to <ip-address> (<ip-address>) port <port> (#0)
> PUT /file.txt HTTP/1.1
> Host: <ip-address>:<port>
> User-Agent: curl/7.55.1
> Accept: */*
> Content-Length: 682
> Expect: 100-continue
>
* Done waiting for 100-continue
* We are completely uploaded and fine
< HTTP/1.1 200 OK
< content-length: 0
< date: Tue, 16 Jun 2020 19:24:18 GMT
< connection: close
<
* Closing connection 0
and file is visible in the expected directory on the host machine.
Now I'm trying to have the same behavior using Indy, but either there is some black-box magic occurring on the server-side, or there is an issue with my code - with some solutions the request seems to finalize, but there is no file in the specified directory (and status code 200 is returned).
I have also tried using Fiddler to reproduce the curl
call, and in the response of a composed query also received 200 status code, but still - no file was properly uploaded.
When inspecting Wireshark packets for these solutions they all seemed similar to the curl call - however, I am not an expert in using this tool, so maybe there are issues not visible to my newbie eye.
I tried using following solutions:
- How do I upload a file using http post? Delphi 2009 - but using PUT instead of POST
- Single file upload example
- Post a file through https using indy / delphi components
And in my case they do not work - so my guess is that the server is somehow not accepting these.
I know it's very hard to say what I'm doing wrong without me actually putting some code, but right now it's a total mess - but maybe it's not hard to somehow show me how to convert this curl call to work with TIdHttp
?
If not, I will try to modify my question soon with more information.
EDIT: As requested, I'm adding some sample code:
var
FHTTP: TIdHTTP;
file2send: string;
sr: TStringStream;
FPutData : TFileStream;
begin
sr := TStringStream.Create;
if OpenDialog1.Execute then
file2send := OpenDialog1.FileName;
FHTTP := TIdHTTP.Create(self);
FPutData := TFileStream.Create(file2send, fmOpenRead or
fmShareDenyWrite);
FHTTP.Put(PutURL.text, FPutData, sr);
end;
You don't need the TStringStream
since you don't use it. You can pass TStream(nil)
in that parameter.
Also, you are calling FHTTP.Put()
unconditionally, even if OpenDialog.Execute()
returns false.
Also, make sure the URL you pass to FHTTP.Put()
is 'http://<ip-address>:<port>/file.txt'
not 'http://<ip-address>:<port>'
.
Also, consider setting FHTTP.Request.UserAgent
, as some web servers reject Indy's default UserAgent
.
Also, consider Free
'ing your objects, especially if you ever plan to upgrade to 10.4 Sydney or later, since ARC for object lifetime management was removed in 10.4.
Try something more like this:
var
FHTTP: TIdHTTP;
file2send: string;
FPutData : TFileStream;
begin
if not OpenDialog1.Execute then Exit;
file2send := OpenDialog1.FileName;
FHTTP := TIdHTTP.Create(nil);
try
FHTTP.Request.UserAgent := 'curl/7.55.1';
FPutData := TFileStream.Create(file2send, fmOpenRead or fmShareDenyWrite);
try
FHTTP.Put(PutURL.Text, FPutData, TStream(nil));
{ or, maybe something like:
URL := PutURL.Text + '/' + ExtractFileName(file2send);
FHTTP.Put(URL, FPutData, TStream(nil));
}
finally
FPutData.Free;
end;
finally
FHTTP.Free;
end;
end;