2010-02-19 102 views
1

如果我想部分下载文件并定义在请求报头的单个范围,我得到 在响应体中的请求的文件的字节流。具有多个HTTP请求范围

但是,如果我如下指定多个范围,总是得到为每个定义的范围内的额外 响应头(至极描述所请求的范围),该破坏 所下载的文件的响应主体内。如Wireshark的所示

static void Main(string[] args) 
{ 

    Console.Write("Please enter target File: "); 
    string Target = Console.ReadLine(); 
    string Source = @"http://mozilla-mirror.3347.voxcdn.com/pub/mozilla.org/firefox/releases/3.6/win32/de/Firefox%20Setup%203.6.exe"; 

    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Source); 
    request.Credentials = CredentialCache.DefaultCredentials; 

    // define multiple Ranges 
    request.AddRange(  0, 1000000); 
    request.AddRange(1000000, 2000000); 

    HttpWebResponse response = (HttpWebResponse)request.GetResponse(); 

    using (Stream source = response.GetResponseStream()) 
    { 
     using (FileStream target = File.Open(Target, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite)) 
     { 
      byte[] buffer = new byte[4096]; 
      int BytesRead = 0; 
      int TotalBytesRead = 0; 

      while((BytesRead = source.Read(buffer, 0, buffer.Length)) > 0) 
      { 
       target.Write(buffer, 0, BytesRead); 
       TotalBytesRead += BytesRead; 

       Console.WriteLine("{0}", TotalBytesRead); 
      } 
     } 
    } 

    Console.WriteLine("Downloading Finished!"); 
    Console.ReadLine(); 
} 

请求:

http://img197.imageshack.us/img197/8199/requesty.png 

响应体应该只包含该文件的字节流,但另外含有在每一限定范围的开始不需要的响应头:

Response hex dump

是否有可能避免在体内的附加响应报头,而无需请求每个范围分别?

是否有一个内置的方式来过滤额外的响应头,其大小可以根据HTTP的服务器上有什么不同?

+0

就问:你为什么要这么做?我猜你上面的代码只是一个例子,因为直接请求连续的范围没有意义? – 2010-02-25 22:09:01

回答

1

感谢您的帮助,如链接描述它上面是假设 方式的HTTP响应与多个范围的请求。

所以....

是否有可能避免在体内的附加响应报头而不 请求每个范围分别?

=>号

是否有一个内置的方式过滤的附加响应标头,其大小可以 根据HTTP的服务器上的变化?

=>我不知道,但...

也许你们中的一些可能有在代码至极 以下块的关键效果滤镜从文件数据的标题:

public void DoDownload(Range[] Ranges) 
    { 

     HttpWebRequest request = (HttpWebRequest)WebRequest.Create(m_Source); 
     request.Credentials = CredentialCache.DefaultCredentials; 

     foreach (Range r in Ranges) 
     { 
      request.AddRange(r.From, r.To); 
     } 

     HttpWebResponse response = (HttpWebResponse)request.GetResponse(); 

     string boundary = ""; 
     Match m = Regex.Match(response.ContentType, @"^.*boundary=(?<boundary>.*)$"); 

     if (m.Success) 
     { 
      boundary = m.Groups["boundary"].Value; 
     } 
     else 
     { 
      throw new InvalidDataException("invalid packet data: no boundary specification found."); 
     } 


     using (Stream source = response.GetResponseStream()) 
     { 
      using (FileStream target = File.Open(m_TargetFile, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite)) 
      { 
       // buffer for payload 
       byte[] buffer = new byte[4096]; 
       // buffer for current range header 
       byte[] header = new byte[200]; 
       // next header after x bytes 
       int NextHeader = 0; 
       // current position in header[] 
       int HeaderPosition = 0; 
       // current position in buffer[] 
       int BufferPosition = 0; 
       // left data to proceed 
       int BytesToProceed = 0; 
       // total data written without range-headers 
       long TotalBytesWritten = 0; 
       // count of last data written to target file 
       int BytesWritten = 0; 
       // size of processed header data 
       int HeaderSize = 0; 
       // count of last data read from ResponseStream 
       int BytesRead = 0; 


       while ((BytesRead = source.Read(buffer, 0, buffer.Length)) > 0) 
       { 
        BufferPosition = 0; 
        BytesToProceed = BytesRead; 
        HeaderSize = 0; 

        while (BytesToProceed > 0) 
        { 
         if (NextHeader == 0) 
         { 
          for (;HeaderPosition < header.Length; HeaderPosition++, BufferPosition++, HeaderSize++) 
          { 
           if (BytesToProceed > HeaderPosition && BufferPosition < BytesRead) 
           { 
            header[HeaderPosition] = buffer[BufferPosition]; 

            if (HeaderPosition >= 4 && 
             header[HeaderPosition - 3] == 0x0d && 
             header[HeaderPosition - 2] == 0x0a && 
             header[HeaderPosition - 1] == 0x0d && 
             header[HeaderPosition] == 0x0a) 
            { 
             string RangeHeader = Encoding.ASCII.GetString(header, 0, HeaderPosition + 1); 
             Match mm = Regex.Match(RangeHeader, 
              @"^\r\n(--)?" + boundary + @".*?(?<from>\d+)\s*-\s*(?<to>\d+)/.*\r\n\r\n", RegexOptions.Singleline); 

             if (mm.Success) 
             { 
              int RangeStart = Convert.ToInt32(mm.Groups["from"].Value); 
              int RangeEnd = Convert.ToInt32(mm.Groups["to"].Value); 

              NextHeader = (RangeEnd - RangeStart) + 1; 

              target.Seek(RangeStart, SeekOrigin.Begin); 
              BufferPosition++; 

              BytesToProceed -= HeaderSize + 1; 

              HeaderPosition = 0; 
              HeaderSize = 0; 

              break; 
             } 
             else { throw new InvalidDataException("invalid header: missing range specification.");} 
            } 
           } 
           else { goto READ_NEW; } 
          } 

          if (NextHeader == 0) 
           throw new InvalidDataException("invalid packet data: no range-header found."); 
         } 

         BytesWritten = (NextHeader > BytesToProceed) ? BytesToProceed : NextHeader; 

         target.Write(buffer, BufferPosition, BytesWritten); 

         BytesToProceed -= BytesWritten; 
         NextHeader -= BytesWritten; 
         BufferPosition += BytesWritten; 

         TotalBytesWritten += BytesWritten; 
        } 

       READ_NEW:; 
       } 
      } 
     } 
    } 

,并可以给我一些提示如果有另一个/更好的方式来做到这一点。

问候 cap_Chap

+0

看起来很可怕。虽然它似乎并不像有对C#支持多响应(可能是因为他们很少使用)任何HTTP客户端库。或者,也许我看起来不是很努力。无论如何,如果你被困在替代品中,为什么不仅仅用一个范围来做多个HTTP请求呢? – 2010-02-25 22:12:00

+0

方式以后,但应该仍然是一个很好的参考。 WebAPI客户端库支持多部分请求http://www.c-sharpcorner。COM /条/上传并节省-multipartform数据合的WebAPI-2 / – 2017-04-12 21:00:35