Совместим ли TIdHTTPServer с Microsoft BITS - PullRequest
10 голосов
/ 10 декабря 2010

Мы пытаемся написать сервер обновлений для нашего программного обеспечения, используя компонент TIdHTTPServer.В настоящее время мы обслуживаем XML-файл, в котором перечислены доступные обновления, их версии и т. Д., Когда клиентская программа находит обновленную версию, она должна начать загружать ее с помощью BITS.

Теперь у нас проблема, наши программы запрашивают файл XML и видят, что доступно обновление.Затем он создает задание BITS для его загрузки, однако BITS продолжает сообщать, что загрузка не удалась.Мы можем загрузить файл, используя тот же URL и IE / Firefox / Chrome.

, поэтому мой вопрос:

Совместим ли TIdHTTPServer с BITS?

Я спрашиваю об этом, поскольку обнаружил, что существуют требования к загрузке для работы битов.
Требования HTTP для загрузок BITS

BITS поддерживает HTTPHTTPS загружает и выгружает и требует, чтобы сервер поддерживал протокол HTTP / 1.1.Для загрузки метод HTTP-сервера HTTP должен возвращать размер файла, а метод Get должен поддерживать заголовки Content-Range и Content-Length.В результате BITS передает только статическое содержимое файла и выдает ошибку, если вы пытаетесь передать динамическое содержимое, если только сценарии ASP, ISAPI или CGI не поддерживают заголовки Content-Range и Content-Length.

BITS можетиспользуйте сервер HTTP / 1.0, если он соответствует требованиям метода Head и Get.

Для поддержки диапазонов загрузки файла сервер должен поддерживать следующие требования:

Разрешить заголовкам MIMEвключают стандартные заголовки Content-Range и Content-Type, а также максимум 180 байтов других заголовков.Разрешить не более двух CR / LF между заголовками HTTP и первой строкой границы.

Ответы [ 3 ]

6 голосов
/ 11 декабря 2010

Только что обнаружил в indy ошибку, которая препятствует передаче файлов более 2,1 ГБ при использовании запросов диапазона.

вот оно

IdHTTPHeaderInfo.pas aprox line 770

procedure TIdEntityRange.SetText(const AValue: String);
var
  LValue, S: String;
begin
  LValue := Trim(AValue);
  if LValue <> '' then
  begin
    S := Fetch(LValue, '-'); {do not localize}
    if S <> '' then begin
      FStartPos := StrToIntDef(S, -1);
      FEndPos := StrToIntDef(Fetch(LValue), -1);
      FSuffixLength := -1;
    end else begin
      FStartPos := -1;
      FEndPos := -1;
      FSuffixLength := StrToIntDef(Fetch(LValue), -1);
    end;
  end else begin
    FStartPos := -1;
    FEndPos := -1;
    FSuffixLength := -1;
  end;
end;

Это должно быть

procedure TIdEntityRange.SetText(const AValue: String);
var
  LValue, S: String;
begin
  LValue := Trim(AValue);
  if LValue <> '' then
  begin
    S := Fetch(LValue, '-'); {do not localize}
    if S <> '' then begin
      FStartPos := StrToInt64Def(S, -1);
      FEndPos := StrToInt64Def(Fetch(LValue), -1);
      FSuffixLength := -1;
    end else begin
      FStartPos := -1;
      FEndPos := -1;
      FSuffixLength := StrToInt64Def(Fetch(LValue), -1);
    end;
  end else begin
    FStartPos := -1;
    FEndPos := -1;
    FSuffixLength := -1;
  end;
end;

Один для Реми, чтобы исправить

4 голосов
/ 11 декабря 2010

Итак, ответ на этот вопрос:

Да TIdHTTPServer совместим с битами.

Но только если вы готовы выполнить работу самостоятельно.

По предложению @Rob Kennedy и Myself можно читать заголовки и отправлять данные обратно, используя запрошенные диапазоны, по одному фрагменту за раз.

Вот пример того, что я делаю в OnCommandGet событии

procedure TForm3.IdHTTPServer1CommandGet(AContext: TIdContext;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
  Ranges : TIdEntityRanges;
  DataChunk: TMemoryStream;
  ReqFile: TFileStream;
  ChunkLength: Int64;
  Directory, FileName: string;
begin
  Directory := 'H:';

  case ARequestInfo.Ranges.Count of
  0:
    begin
      //serve file normally
    end;
  1:
    begin
      //serve range of bytes specified for file

      filename := Directory + ARequestInfo.Document;

      if FileExists(FileName) then
      begin
        ReqFile := TFileStream.Create(FileName, fmOpenRead);
        try
          ChunkLength := Succ(ARequestInfo.Ranges.Ranges[0].EndPos - ARequestInfo.Ranges.Ranges[0].StartPos);

          if ChunkLength > ReqFile.Size then
            ChunkLength := ReqFile.Size;

          DataChunk := TMemoryStream.Create;
          DataChunk.Posistion := ARequestInfo.Ranges.Ranges[0].StartPos;  
          DataChunk.CopyFrom(ReqFile, ChunkLength);

          AResponseInfo.ContentStream := DataChunk;
          AResponseInfo.ContentType := IdHTTPServer1.MIMETable.GetFileMIMEType(FileName);
          AResponseInfo.ContentRangeUnits := ARequestInfo.Ranges.Units;
          AResponseInfo.ContentRangeStart := ARequestInfo.Ranges.Ranges[0].StartPos;
          AResponseInfo.ContentRangeEnd := ARequestInfo.Ranges.Ranges[0].StartPos + Pred(ChunkLength);
          AResponseInfo.ContentRangeInstanceLength := ReqFile.Size;
          AResponseInfo.ResponseNo := 206;
        finally
          ReqFile.Free;
        end;
      end
      else
        AResponseInfo.ResponseNo := 404;

    end
  else
    begin
      //serve the file as multipart/byteranges
    end;
  end;

end;

Это ни в коем случае не закончено, но показывает основы реагирования на запросы диапазона от BITS. Самое главное, что это работает.

Любые комментарии по коду приветствуются, конструктивная критика всегда приветствуется.

4 голосов
/ 10 декабря 2010

Когда вы обрабатываете событие OnCommandGet, вам дается TIdRequestHeaderInfo, которое убывает с TIdEntityHeaderInfo; он содержит все заголовки, содержащиеся в запросе, и даже анализирует некоторые значения заголовков для чтения как свойства, включая ContentRangeStart, ContentRangeEnd и ContentLength.

Вы можете использовать эти свойства для заполнения потока, который вы назначаете свойству TIdHTTPResponseInfo.ContentStream. весь поток будет отправлен.

Ваша задача - различать запросы GET и HEAD; OnCommandGet сработает в любом случае. Проверьте IdHTTPRequestInfo.CommandType свойство.

Итак, хотя Indy может не поддерживать BITS, он предоставляет все инструменты, необходимые для написания программы, которая поддерживает поддержку BITS.

...