azzlack / Microsoft.AspNet.WebApi.MessageHandlers.Compression

Drop-in module for ASP.Net WebAPI that enables GZip and Deflate support
Apache License 2.0
194 stars 54 forks source link

Unable to decompress request using compressor 'System.Net.Http.Extensions.Compression.Core.Compressors.GZipCompressor', Exception of type 'System.OutOfMemoryException' was thrown. #61

Closed MartinRobins closed 2 years ago

MartinRobins commented 5 years ago

I have a WebAPI application (.NET 4.7.2) that works locally on Windows 10 but does not work when deployed to Windows Server 2012R2/IIS8.5. The only clue I can get from it is...

{"Message":"An error has occurred.", "ExceptionMessage":"Unable to decompress request using compressor 'System.Net.Http.Extensions.Compression.Core.Compressors.GZipCompressor'", "ExceptionType":"System.Exception","StackTrace":"
at Microsoft.AspNet.WebApi.Extensions.Compression.Server.BaseServerCompressionHandler.d19.MoveNext()\r\n --- End of stack trace from previous location where exception was thrown ---\r\n
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n
at Microsoft.AspNet.WebApi.Extensions.Compression.Server.BaseServerCompressionHandler.d
16.MoveNext()\r\n --- End of stack trace from previous location where exception was thrown ---\r\n
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n
at Microsoft.AspNet.WebApi.Extensions.Compression.Server.BaseServerCompressionHandler.d15.MoveNext()\r\n --- End of stack trace from previous location where exception was thrown ---\r\n
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n
at System.Web.Http.HttpServer.d
24.MoveNext()", "InnerException":{"Message":"An error has occurred.","ExceptionMessage":"Exception of type 'System.OutOfMemoryException' was thrown.","ExceptionType":"System.OutOfMemoryException","StackTrace":"
at System.Web.HttpRawUploadedContent.AddBytes(Byte[] data, Int32 offset, Int32 length)\r\n
at System.Web.HttpBufferlessInputStream.EndRead(IAsyncResult asyncResult)\r\n
at System.Web.Http.WebHost.SeekableBufferedRequestStream.EndRead(IAsyncResult asyncResult)\r\n
at System.Net.Http.StreamToStreamCopy.StartRead()\r\n --- End of stack trace from previous location where exception was thrown ---\r\n
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n
at System.Net.Http.Extensions.Compression.Core.HttpContentOperations.d0.MoveNext()\r\n --- End of stack trace from previous location where exception was thrown ---\r\n
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n
at Microsoft.AspNet.WebApi.Extensions.Compression.Server.BaseServerCompressionHandler.d
19.MoveNext()"}}

Any thoughts as currently I have no idea where to start?

MartinRobins commented 5 years ago

A little more information; when sending some compressed requests, reading from the original Request.Content throws the exception (I have downloaded your source so that I can debug and tried intercepting it at various levels up the chain all the way up to BaseServerCompressionHandler.SendAsync; having opened the content using ReadAsStreamAsync any attempt to read results in OutOfMemoryException).

The error is however intermittent. If I send the request without compression (by setting the contentSizeThreshold of the ClientCompressionHandler to Int32.MaxValue), I am able to read the Request.Content within BaseServerCompressionHandler.SendAsync as would be expected.

The code being used to read within BaseServerCompressionHandler.SendAsync is simply...

            byte[] buffer = new byte[4096];
            int bytesRead;
            Stream stream = await request.Content.ReadAsStreamAsync();
            while (0 < (bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)))
                Debug.WriteLine(bytesRead);

The size of the compressed request when it fails is in excess of 200Mb if that makes any difference.

M.