10

TIdHTTPServerコンポーネントを使用して、ソフトウェアの更新サーバーを作成しようとしています。現在、利用可能なアップデートとそのファイルバージョンなどをリストしたXMLファイルを提供しています。クライアントプログラムがアップデートされたバージョンを見つけると、BITSを使用してダウンロードを開始する必要があります。

ここで問題が発生します。プログラムはXMLファイルを要求しており、利用可能な更新があることを確認しています。次に、ダウンロードするBITSジョブを作成しますが、BITSはダウンロードが失敗したことを報告し続けます。同じURLとIE/Firefox/Chromeを使用してファイルをダウンロードできます。

だから私の質問:

TIdHTTPServerはBITSと互換性がありますか?

ビットが機能するためのこれらのダウンロード要件があることを発見したので、これを尋ねます。
BITSダウンロードのHTTP要件

BITSはHTTPおよびHTTPSのダウンロードとアップロードをサポートし、サーバーがHTTP/1.1プロトコルをサポートしている必要があります。ダウンロードの場合、HTTPサーバーのHeadメソッドはファイルサイズを返す必要があり、そのGetメソッドはContent-RangeヘッダーとContent-Lengthヘッダーをサポートする必要があります。その結果、ASP、ISAPI、またはCGIスクリプトがContent-RangeヘッダーとContent-Lengthヘッダーをサポートしていない限り、BITSは静的ファイルコンテンツのみを転送し、動的コンテンツを転送しようとするとエラーを生成します。

BITSは、HeadメソッドとGetメソッドの要件を満たしている限り、HTTP/1.0サーバーを使用できます。

ファイルのダウンロード範囲をサポートするには、サーバーが次の要件をサポートしている必要があります。

MIMEヘッダーに、標準のContent-RangeヘッダーとContent-Typeヘッダーに加えて、最大180バイトの他のヘッダーを含めることができます。HTTPヘッダーと最初の境界文字列の間に最大2つのCR/LFを許可します。

4

3 に答える 3

6

範囲リクエストを使用するときに2.1GBを超えるファイルの転送を妨げるindyのバグを見つけました。

ここにあります

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;

レミーが修正するための1つ

于 2010-12-11T02:46:04.057 に答える
4

OnCommandGetイベントを処理すると、 ;TIdRequestHeaderInfoから派生するが与えられます。TIdEntityHeaderInfoこれには、リクエストに含まれるすべてのヘッダーが含まれ、いくつかのヘッダー値を解析して、、、、などのプロパティとして読み取ることもできContentRangeStartます。ContentRangeEndContentLength

これらのプロパティを使用して、プロパティに割り当てるストリームにデータを入力できTIdHTTPResponseInfo.ContentStreamます。ストリーム全体が送信されます。

GETリクエストとHEADリクエストを区別するのはあなたの仕事です。OnCommandGetどちらの方法でもトリガーされます。IdHTTPRequestInfo.CommandTypeプロパティを確認してください。

したがって、IndyはBITSをサポートしていない可能性がありますが、BITSをサポートするプログラムを作成するために必要なすべてのツールを提供します。

于 2010-12-10T14:57:23.810 に答える
4

したがって、この質問に対する答えは次のとおりです。

はいTIdHTTPServerはビット互換です。

ただし、自分で作業を行う準備ができている場合に限ります。

@Rob KennedyとMyselfが提案したように、ヘッダーを読み取り、要求された範囲を使用して、一度に1つのチャンクでデータを送り返すことができます。

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 に答える