Загрузить файл с помощью IdHTTP на указанный хост на основе вызова curl - PullRequest
1 голос
/ 16 июня 2020

Я пытаюсь создать приложение FMX Android, которому необходимо загрузить файл на данный хост.

Владелец хоста предоставил мне следующий оператор curl для загрузки файла:

curl -T http://<ip-address>:<port> file.txt

И при вызове из Windows командной строки он производит следующий вывод (IP и порт отредактированы):

*   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

и файл виден в ожидаемом каталоге на хост-машине.

Теперь я пытаюсь добиться того же поведения с помощью Indy, но либо на стороне сервера возникает какой-то маги черного ящика c, либо есть проблема с моим кодом - с некоторыми решениями запрос кажется завершенным, но в указанном каталоге нет файла (и возвращается код состояния 200).

Я также пробовал использовать Fiddler для воспроизведения вызова curl и в ответе на составленный запрос также получил код состояния 200, но все же - ни один файл не был загружен должным образом.

При проверке пакетов Wireshark для этих решений все они казались похожими на вызов curl - однако я не являюсь экспертом в использовании этого инструмента , так что, возможно, есть проблемы, которые не видны моему новичку ie глазу.

Я пробовал использовать следующие решения:
- Как загрузить файл с помощью http post? Delphi 2009 - но с использованием PUT вместо POST
- Пример загрузки одного файла
- Разместите файл через https, используя indy / delphi components

И в моем случае они не работают - так что я предполагаю, что сервер почему-то не принимает их.

Я знаю, что очень сложно сказать, что я делаю не так, если я на самом деле не вставил какой-то код, но сейчас это полный беспорядок - но, возможно, нетрудно как-то показать мне, как преобразовать этот вызов curl в работать с TIdHttp?

Если нет, я постараюсь вскоре изменить свой вопрос, добавив дополнительную информацию.

РЕДАКТИРОВАТЬ: По запросу, я добавляю образец код:

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;

1 Ответ

3 голосов
/ 16 июня 2020

Вам не нужен TStringStream, так как вы его не используете. В этом параметре можно передать TStream(nil).

Кроме того, вы вызываете FHTTP.Put() безоговорочно, даже если OpenDialog.Execute() возвращает false.

Кроме того, убедитесь, что URL-адрес, который вы передаете FHTTP.Put() is 'http://<ip-address>:<port>/file.txt' not 'http://<ip-address>:<port>'.

Также рассмотрите возможность установки FHTTP.Request.UserAgent, поскольку некоторые веб-серверы отклоняют значение Indy по умолчанию UserAgent.

Также учитывайте Free 'ing ваши объекты, особенно если вы когда-либо планируете обновить до 10.4 Sydney или новее, так как AR C для управления жизненным циклом объекта был удален в 10.4.

Попробуйте что-то вроде этого:

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;
...