10

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

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

所以我的问题:

TIdHTTPServer 与 BITS 兼容吗?

我问这个问题是因为我发现要让 bit 工作有这些下载要求。
BITS 下载的 HTTP 要求

BITS 支持 HTTP 和 HTTPS 下载和上传,要求服务器支持 HTTP/1.1 协议。对于下载,HTTP 服务器的 Head 方法必须返回文件大小,并且它的 Get 方法必须支持 Content-Range 和 Content-Length 标头。因此,除非 ASP、ISAPI 或 CGI 脚本支持 Content-Range 和 Content-Length 标头,否则 BITS 仅传输静态文件内容并在您尝试传输动态内容时生成错误。

只要满足 Head 和 Get 方法要求,BITS 就可以使用 HTTP/1.0 服务器。

为了支持文件的下载范围,服务器必须支持以下要求:

允许 MIME 标头包含标准的 Content-Range 和 Content-Type 标头,以及最多 180 字节的其他标头。在 HTTP 标头和第一个边界字符串之间最多允许两个 CR/LF。

4

3 回答 3

6

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

这里是

IdHTTPHeaderInfo.pas 大约 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;

一个让雷米修理

于 2010-12-11T02:46:04.057 回答
4

当你处理OnCommandGet事件时,你会得到一个;TIdRequestHeaderInfo的后代TIdEntityHeaderInfo。它包含请求包含的所有标头,它甚至解析出一些标头值以读取为属性,包括ContentRangeStartContentRangeEndContentLength.

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

区分 GET 和 HEAD 请求是你的工作;OnCommandGet无论哪种方式都会被触发。检查IdHTTPRequestInfo.CommandType物业。

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

于 2010-12-10T14:57:23.810 回答
4

所以这个问题的答案是:

是的 TIdHTTPServer 是位兼容的。

但前提是你准备好自己做这项工作。

正如@Rob Kennedy 和我自己所建议的那样,可以读取标题并使用请求的范围将数据发送回,一次一个块。

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

任何对代码的评论将不胜感激,建设性的批评总是受欢迎的。

于 2010-12-11T01:32:57.003 回答