TIdHTTPServer是否与Microsoft BITS兼容

时间:2010-12-10 10:43:19

标签: delphi http indy httpserver microsoft-bits

我们正在尝试使用TIdHTTPServer组件为我们的软件编写更新服务器。目前我们正在提供一个XML文件,列出可用的更新及其文件版本等。当客户端程序找到更新版本时,它应该开始使用BITS下载它。

现在这是我们遇到问题的地方,我们的程序正在请求XML文件并看到有可用的更新。然后它创建一个BITS作业来下载它,但是BITS一直报告下载失败。我们可以使用相同的URL和IE / Firefox / Chrome下载文件。

所以我的问题:

TIdHTTPServer与BITS兼容吗?

我问这个,因为我发现有一些下载要求可以使用。
HTTP Requirements for BITS Downloads

  

BITS支持HTTP和HTTPS下载和上传,并要求服务器支持HTTP / 1.1协议。对于下载,HTTP服务器的Head方法必须返回文件大小,其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个字节的其他标头。   在HTTP标头和第一个边界字符串之间最多允许两个CR / LF。

3 个答案:

答案 0 :(得分:6)

在indy中发现了一个错误,它阻止了在使用范围请求时传输超过2.1GB的文件。

这里是

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;

一个让Remy修复

答案 1 :(得分:4)

当您处理OnCommandGet事件时,您将获得TIdRequestHeaderInfo,其来自TIdEntityHeaderInfo;它包含请求包含的所有标头,甚至会解析一些标头值以作为属性读取,包括ContentRangeStartContentRangeEndContentLength

您可以使用这些属性填充分配给TIdHTTPResponseInfo.ContentStream属性的流。 整个流将被发送。

区分GET和HEAD请求是你的工作; OnCommandGet将以任一方式触发。检查IdHTTPRequestInfo.CommandType属性。

因此,尽管Indy可能不支持BITS,但它提供了编写支持支持BITS的程序所需的所有工具。

答案 2 :(得分:4)

所以这个问题的答案是:

是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的范围请求的基础知识。最重要的是它有效。

任何关于代码的评论都会受到赞赏,建设性批评总是受到欢迎。