2

In my desktop application I process HTTP response from the server and I want to provide a progress of processed bytes relatively to the total response length.
I know the content length from the HTTP header but the problem is that a compression (gzip) was applied for the response body. I can calculate the number of processed bytes but they are after decompression and that number is different from the content-length. The HTTP response's Stream is not seekable and to determine the progress I cannot use its Position property as I will have a NotSupportedException, similar to what MSDN declares for NetworkStream.Position property.

Below is the code that reads from the gzipped response

        HttpClient httpClient = new HttpClient();

        HttpResponseMessage response = httpClient.GetAsync(gzipGetUri, HttpCompletionOption.ResponseHeadersRead).Result;

        long? contentLength = response.Content.Headers.ContentLength;
        long totalCount = 0;
        int percentDone = 0;

        Stream responseStream = response.Content.ReadAsStreamAsync().Result;
        Stream gzipStream = new GZipStream(responseStream, CompressionMode.Decompress);

        byte[] buffer = new byte[1024];
        while (true)
        {
            int nBytes = gzipStream.Read(buffer, 0, buffer.Length);
            if (nBytes <= 0)
                break;

            // process decompressed bytes here... 

            totalCount += nBytes;

            // This code throws NotSupportedException: This stream does not support seek operations
            percentDone = (int)(((double)responseStream.Position / contentLength) * 100);
        }

        Console.WriteLine($"content-length: {contentLength}; bytes read from gzipStream: {totalCount}");

The output to Console (when the line with calculation of percentDone is commented out) is

content-length: 1,316,578; bytes read from gzipStream: 9,410,402

My question is how I can determine the number of bytes that were consumed from a non-seekable response stream before they are transformed by decompression. Also I cannot use the count after decompression for percentDone calculation because I do not know the final number of decompressed bytes.

I guess that I can derive a class from Stream that counts passing through bytes, use it as a wrapper around responseStream and pass it as an inner stream to gzipStream but that solution seems too heavy.

Igor B
  • 98
  • 7

0 Answers0