Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I change the content of an incoming HTTP request using a HTTP Module?

I'm trying to extend my REST service (built using WCF/webHttpBinding) so that clients can upload gzipped data. I'm not sure what the best way to accomplish this but I thought it would be fairly easy by adding a HTTP module which will decompress the data if Content-Encoding for the incoming request is set to gzip.

So I created an class deriving from IHttpModule with the following implementation:

  private void OnBeginRequest(object sender, EventArgs e)
  {
     var app = (HttpApplication) sender;
     var context = app.Context;

     var contentEncoding = context.Request.Headers["Content-Encoding"];

     if (contentEncoding == "gzip")
     {
        // some debug code:
        var decompressedStream = new GZipStream(context.Request.InputStream, CompressionMode.Decompress);
        var memoryStream = new MemoryStream();
        decompressedStream.CopyTo(memoryStream);
        memoryStream.Seek(0, SeekOrigin.Begin);

        var streamReader = new StreamReader(memoryStream);
        string msg = streamReader.ReadToEnd();

        context.Request.InputStream.Seek(0, SeekOrigin.Begin);

        app.Request.Filter = //new TestFilterStream(app.Request.Filter);
                    new System.IO.Compression.GZipStream(
                    app.Request.Filter, CompressionMode.Decompress);
     }

  }

The issue I'm seeing is that the GZipStream decompression is never actually performed. I've confirmed that the incoming data is in fact gzip'd (the msg-variable contains the proper data). I've also tried creating my own stream class (TestFilterStream) above and assign that to app.Request.Filter and I've confirmed that no members on the stream class is actually called by ASP.NET. So it seems like while it's possible to specify a filter, that filter isn't actually used.

Isn't HttpApplication.Request.Filter actually used?

like image 924
Nitramk Avatar asked Nov 27 '13 18:11

Nitramk


1 Answers

I tried setting the Request Filter in two ways:

  1. Using a HttpModule
  2. Setting it in the start of Application_BeginRequest() (Global.asax)

Both with the same results (VS2012 web project + IISExpress):

  • If there is no input data (GET request or similar), the Filter.Read is not invoked
  • In case of a POST with actual data, the filter is executed and the web service gets the filtered data
  • Even if I read from the Request.InputStream before the Filter is set, I still get the filter triggered from my service code.

I have no easy way of testing with Gzippet input, so I have not tried if the actual filter works. However, I know it is getting triggered, since I get an error from GZipStream while it attempts to look for the input.

Perhaps you are having other HttpModules or Filters that disrupt your input or control flow?

This post proposes a method similar to yours, but also states the following, which may be causing some side effects (my tests were not using WCF):

"It appears that this approach trigger a problem in WCF, as WCF relies on the original Content-Length and not the value obtained after decompressing."

like image 151
Henrik Avatar answered Oct 17 '22 11:10

Henrik