12/12/2016

Did you know that about HTTP?

Home


Titile: Chapel of the Emerald Buddha in Bangkok, Source: own resources, Authors: Agnieszka and Michał Komorowscy

Recently, when answering a question on stackoverflow.com, I've learned an interesting thing about HTTP protocol. Actually currently it seems to be obvious to me ;) What I'm talking about? Well, initially I thought that if you send GET HTTP request in order to download a specific URL, then in a response you will get an entire page/file. In other words I thought that it's not possible to read the specific part of a page/file. However, it turned out that it's quite easy.

For instance, let's assume that we want to read X bytes starting from the byte number N. In that case we should use Range header. Here is an example C# program showing how to do that with HttpClient class.

In this example, I'm reading one of my recent posts. More precisely I'm reading either the first byte or the first 50 bytes or 30 bytes starting from the byte number 100 or the entire post. The code seems to be self explanatory. The only "extraordinary" thing is the fact that I used RangeHeaderValue class to tell HttpClient which bytes should be read.
class Program
{
   static void Main(string[] args)
   {
      var url = "http://www.michalkomorowski.com/2016/11/how-to-validate-dynamic-ui-with-jquery.html";

      var conf = new []
      {
         new { Start = 0, Bytes = 1 },
         new { Start = 0, Bytes = 50 },
         new { Start = 100, Bytes = 30 },
         new { Start = -1, Bytes = -1 },
      };

      foreach (var c in conf)
      {
         Console.WriteLine($"Reading {c.Bytes} bytes starting from {c.Start}");
         GetRange(c.Start, c.Bytes, url).Wait();
         Console.WriteLine();
      }

        Console.ReadLine();
    }

    private static async Task GetRange(int start, int bytes, string url)
    {
         using (var client = new HttpClient())
         {
             var request = new HttpRequestMessage(HttpMethod.Get, url);

             if(start >= 0 && bytes >= 0)
                 request.Headers.Range = new RangeHeaderValue(start, start + bytes - 1);
      
             using (var response = await client.SendAsync(request))
             {
                 var s = await response.Content.ReadAsStringAsync();
                 Console.Write(s);
             }
          }
     }
}
If you start Fiddler and run this code you should see the result as below. You can notice that 4 request were sent to the server. The Body column shows the number of read bytes for each request.


A screenshot comes from Fiddler

When this functionality can be used in practice? For example, if you want to resume the download of a file. I haven't tried this but I think that Range header can be also used to parallelize downloading of large files.

2 comments:

Anonymous said...

Nice! :)

Ian Yates said...

This is what GetRight used to use back in the day to fetch big files in parallel. Good times!

Post a Comment