Возобновить HTTP Post / загрузить с Indy - PullRequest
3 голосов
/ 07 марта 2012

Я пытаюсь возобновить загрузку с помощью indy (HTTP Post), код выглядит так (с использованием Delphi 2010, Indy 10.4736):

 IdHttp.Head('http://localhost/_tests/resume/large-file.bin');
 ByteRange           := IdHttp.Response.ContentLength + 1;

 // Attach the file to post/upload
 Stream              := TIdMultipartFormDataStream.Create;
 with Stream.AddFile('upload_file', 'D:\large-file.bin', 'application/octet-stream') do
 begin
      HeaderCharset  := 'utf-8';
      HeaderEncoding := '8';
 end;    // with

 with IdHTTP do
 begin
      IOHandler.LargeStream           := True;

      with Request do
      begin
           ContentRangeStart          := ByteRange;
           ContentRangeEnd            := (Stream.Size - ByteRange);
           ContentLength              := ContentRangeEnd;
           ContentRangeInstanceLength := ContentLength;
      end;    // with

      Post('http://localhost/_tests/resume/t1.php', Stream);
 end;    // with

но загрузка резюме не работает: (

Я посмотрел код Indy, похоже, что эта функция в IdIOHandler.pas

TIdIOHandler.Write ()

всегда имеет дело с полными потоками / файлами (поскольку параметр ASize: TIdStreamSize, кажется, всегда равен 0, что в соответствии с кодом означает отправку полного файла / потока).

Это не позволяет indy возобновить загрузку.

У меня вопрос: возможно ли избежать отправки полного файла?

Настройка диапазона содержимого ничего не изменила. Я также подправил код инди (измененные 3 строки), чтобы инди подчинялся диапазону содержимого / позиции потока, но он глючит, и инди всегда заканчивается зависанием IdStackWindows.pas из-за бесконечного времени ожидания здесь:

TIdSocketListWindows.FDSelect ()

1 Ответ

4 голосов
/ 07 марта 2012

Как я уже говорил вам в вашем предыдущем вопросе , вы должны опубликовать TStream, содержащий оставшиеся данные файла для загрузки. Не используйте TIdMultipartFormDataStream.AddFile(), так как это отправит весь файл. Вместо этого используйте перегруженную версию TStream TIdMultipartFormDataStream.AddFormField().

И TIdHTTP не предназначены для соблюдения свойств ContentRange.... Большинство свойств Request просто устанавливают только соответствующие заголовки HTTP, они не влияют на данные. Вот почему ваши правки сломали его.

Попробуйте это:

IdHttp.Head('http://localhost/_tests/resume/large-file.bin');
FileSize := IdHttp.Response.ContentLength;

FileStrm := TFileStream.Create('D:\large-file.bin', fmOpenRead or fmShareDenyWrite);
try
  if FileSize < FileStrm.Size then
  begin
    FileStrm.Position := FileSize;

    Stream := TIdMultipartFormDataStream.Create;
    try
      with Stream.AddFormField('upload_file', 'application/octet-stream', '', FileStrm, 'large-file.bin') do
      begin
        HeaderCharset  := 'utf-8';
        HeaderEncoding := '8';
      end;

      with IdHTTP do
      begin
        with Request do
        begin
          ContentRangeStart := FileSize + 1;
          ContentRangeEnd   := FileStrm.Size;
        end;

        Post('http://localhost/_tests/resume/t1.php', Stream);
      end;
    finally
      Stream.Free;
    end;
  end;
finally
  FileStrm.Free;
end;

С учетом сказанного, это БОЛЬШАЯ НЕПРАВИЛЬНАЯ HTTP и multipart/form-data. Для начала значения ContentRange находятся не в том месте. Вы применяете их ко всему Request в целом, что неправильно. Вместо этого их нужно будет применять на FormField, но TIdMultipartFormDataStream в настоящее время не поддерживает это. Во-вторых, multipart/form-data не был предназначен для использования в любом случае. Это хорошо для загрузки файла с самого начала, но не для возобновления прерванной загрузки. Вы действительно должны прекратить использование TIdMultipartFormDataStream и просто передать данные файла непосредственно в TIdHTTP.Post(), как я предложил ранее , например:

FileStrm := TFileStream.Create('D:\large-file.bin', fmOpenRead or fmShareDenyWrite);
try
  IdHTTP.Post('http://localhost/_tests/upload.php?name=large-file.bin', FileStrm);
finally
  FileStrm.Free;
end;

.

IdHTTP.Head('http://localhost/_tests/files/large-file.bin');
FileSize := IdHTTP.Response.ContentLength;

FileStrm := TFileStream.Create('D:\large-file.bin', fmOpenRead or fmShareDenyWrite);
try
  if FileSize < FileStrm.Size then
  begin
    FileStrm.Position := FileSize;
    IdHTTP.Post('http://localhost/_tests/resume.php?name=large-file.bin', FileStrm);
  end;
finally
  FileStrm.Free;
end;

Я уже объяснил ранее , как получить доступ к необработанным POST данным в PHP.

...