Copying Http Request InputStream

Adrian Grigore picture Adrian Grigore · Aug 10, 2010 · Viewed 23.3k times · Source

I'm implementing a proxy action method that forwards the incoming web request and forwards it to another web page, adding a few headers. The action method works file for GET requests, but I'm still struggling with forwarding the incoming POST request.

The problem is that I don't know how to properly write the request body to the outgoing HTTP request stream.

Here's a shortened version of what I've got so far:

//the incoming request stream
var requestStream=HttpContext.Current.Request.InputStream;
//the outgoing web request
var webRequest = (HttpWebRequest)WebRequest.Create(url);
...

//copy incoming request body to outgoing request
if (requestStream != null && requestStream.Length>0)
            {
                long length = requestStream.Length;
                webRequest.ContentLength = length;
                requestStream.CopyTo(webRequest.GetRequestStream())                    
            }

//THE NEXT LINE THROWS A ProtocolViolationException
 using (HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse())
                {
                    ...
                }

As soon as I call GetResponse on the outgoing http request, I get the following exception:

ProtocolViolationException: You must write ContentLength bytes to the request stream before calling [Begin]GetResponse.

I don't understand why this is happening, since requestStream.CopyTo should have taken care of writing the right amount of bytes.

Any suggestions would be greatly appreciated.

Thanks,

Adrian

Answer

Brian picture Brian · Jan 12, 2011

Yes, .Net is very finicky about this. The way to solve the problem is to both flush and close the stream. In other words:

Stream webStream = null;

try
{
    //copy incoming request body to outgoing request
    if (requestStream != null && requestStream.Length>0)
    {
        long length = requestStream.Length;
        webRequest.ContentLength = length;
        webStream = webRequest.GetRequestStream();
        requestStream.CopyTo(webStream);
    }
}
finally
{
    if (null != webStream)
    {
        webStream.Flush();
        webStream.Close();    // might need additional exception handling here
    }
}

// No more ProtocolViolationException!
using (HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse())
{
    ...
}