none
Portable HttpClient hides Content-Length and Content-Encoding headers with gzip encoding RRS feed

  • Question

  • Start with this code...

          HttpClientHandler handler = new HttpClientHandler
          {
            AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,
          };
    
          using (HttpClient client = new HttpClient(handler, true))
          {
            string url = "http://www.microsoft.com/en-us/default.aspx";
            using (HttpRequestMessage request = new HttpRequestMessage() { Method = new HttpMethod("GET"), RequestUri = new Uri(url) })
            {
              using (HttpResponseMessage response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead))
              {
                string contentEncoding = response.Content.Headers.ContentEncoding.FirstOrDefault();
              }
            }
          }

    Here's what one sees on the wire:

    HTTP/1.1 200 OK
    Cache-Control: private
    Content-Length: 37749
    Content-Type: text/html
    Content-Encoding: gzip
    Vary: Accept-Encoding
    Server: Microsoft-IIS/8.0
    P3P: CP="ALL IND DSP COR ADM CONo CUR CUSo IVAo IVDo PSA PSD TAI TELo OUR SAMo CNT COM INT NAV ONL PHY PRE PUR UNI"
    X-AspNet-Version: 4.0.30319
    X-Powered-By: ASP.NET
    Access-Control-Allow-Origin: Content-Type
    Access-Control-Allow-Headers: GET, POST, PUT, DELETE, OPTIONS
    Access-Control-Allow-Methods: true
    X-Powered-By: ARR/2.5
    X-Powered-By: ASP.NET
    Date: Fri, 27 Dec 2013 23:51:29 GMT

    However, there does not appear to be any programmatic way to get the Content-Length or Content-Encoding headers from the HttpResponseMessage. In the snippet above, contentEncoding is always null and response.Content.Headers is just Content-Type: text/html.  The is no indication of length whatsoever that I can find.  Even getting the stream for the response throws NotSupportedException for the Length property.

    Ideally, there would be some way for the programmer to know that there's actually content here, but I don't see any such thing anywhere on the HttpResponseMessage.  Maybe I'm missing something?  (I hope I am!)

    Saturday, December 28, 2013 12:05 AM

Answers

  • I spoke to the devs about this issue and they had a conversation about it.  Here are the good parts:

    When setting AutomaticDecompression, HttpClientHandler will modify Content-Encoding as it unzips the content.  It does the same on Desktop.  This is to be consistent with the representation of the content body since it is no longer compressed.

    An easy way to demonstrate this is to set the Accept-Encoding without setting AutomaticDecompression.  This will cause the server to send a gzip’ed response (due to AcceptEncoding), but HttpClientHandler won’t automatically decompress.

    The actual content length is not known until the entire stream is decompressed.  This happens asynchronously as bytes are read from the stream.  The best that we can know after reading headers are that there are some bytes, so ContentLength is set to -1 just like a chunked response.

    How can they determine if there is a response body?  I think the answer is that they should just assume there is a body unless the headers conclusively tell them otherwise (e.g. Content-Length: 0), or the verb is HEAD.


    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    NOTE: If I ask for code, please provide something that I can drop directly into a project and run (including XAML), or an actual application project. I'm trying to help a lot of people, so I don't have time to figure out weird snippets with undefined objects and unknown namespaces.

    Thursday, January 2, 2014 12:52 PM
    Moderator

All replies

  • You're right, that information is on the wire but not represented in the HTTPResponseMessage. I'm going to ask about this and let you know what I find out.

    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    NOTE: If I ask for code, please provide something that I can drop directly into a project and run (including XAML), or an actual application project. I'm trying to help a lot of people, so I don't have time to figure out weird snippets with undefined objects and unknown namespaces.

    Tuesday, December 31, 2013 8:44 PM
    Moderator
  • I spoke to the devs about this issue and they had a conversation about it.  Here are the good parts:

    When setting AutomaticDecompression, HttpClientHandler will modify Content-Encoding as it unzips the content.  It does the same on Desktop.  This is to be consistent with the representation of the content body since it is no longer compressed.

    An easy way to demonstrate this is to set the Accept-Encoding without setting AutomaticDecompression.  This will cause the server to send a gzip’ed response (due to AcceptEncoding), but HttpClientHandler won’t automatically decompress.

    The actual content length is not known until the entire stream is decompressed.  This happens asynchronously as bytes are read from the stream.  The best that we can know after reading headers are that there are some bytes, so ContentLength is set to -1 just like a chunked response.

    How can they determine if there is a response body?  I think the answer is that they should just assume there is a body unless the headers conclusively tell them otherwise (e.g. Content-Length: 0), or the verb is HEAD.


    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    NOTE: If I ask for code, please provide something that I can drop directly into a project and run (including XAML), or an actual application project. I'm trying to help a lot of people, so I don't have time to figure out weird snippets with undefined objects and unknown namespaces.

    Thursday, January 2, 2014 12:52 PM
    Moderator
  • Makes sense. I can't think of a better suggestion for this scenario. Thanks for the reply.
    Thursday, January 23, 2014 12:50 AM
  • I spoke to the devs about this issue and they had a conversation about it.  Here are the good parts:

    When setting AutomaticDecompression, HttpClientHandler will modify Content-Encoding as it unzips the content.  It does the same on Desktop.  This is to be consistent with the representation of the content body since it is no longer compressed.

    An easy way to demonstrate this is to set the Accept-Encoding without setting AutomaticDecompression.  This will cause the server to send a gzip’ed response (due to AcceptEncoding), but HttpClientHandler won’t automatically decompress.

    The actual content length is not known until the entire stream is decompressed.  This happens asynchronously as bytes are read from the stream.  The best that we can know after reading headers are that there are some bytes, so ContentLength is set to -1 just like a chunked response.

    How can they determine if there is a response body?  I think the answer is that they should just assume there is a body unless the headers conclusively tell them otherwise (e.g. Content-Length: 0), or the verb is HEAD.


    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    NOTE: If I ask for code, please provide something that I can drop directly into a project and run (including XAML), or an actual application project. I'm trying to help a lot of people, so I don't have time to figure out weird snippets with undefined objects and unknown namespaces.

    I am facing this issue and not found any document mention about it. Thanks. So now I can not use Content-Length or Content-Encoding to check result.

    Here is my code on Windows Phone 8.1:

    HttpBaseProtocolFilter filter = new HttpBaseProtocolFilter();
    filter.AutomaticDecompression = true;
    
    HttpClient httpClient = new HttpClient(filter);
    ......
    httpResponseMsg = await httpClient.SendRequestAsync(postRequest);
    strResponseBody = await httpResponseMsg.Content.ReadAsStringAsync();



    Vu Tran


    • Edited by Vu_Tran Thursday, April 2, 2015 8:50 AM add code example
    Thursday, April 2, 2015 8:45 AM