我们正在尝试使用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。
答案 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
;它包含请求包含的所有标头,甚至会解析一些标头值以作为属性读取,包括ContentRangeStart
,ContentRangeEnd
和ContentLength
。
您可以使用这些属性填充分配给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的范围请求的基础知识。最重要的是它有效。
任何关于代码的评论都会受到赞赏,建设性批评总是受到欢迎。