I have an ApiController
which responds to a POST request by redirecting it via HTTP's status code 307. It does so using only information from the header, so the body of the request is not needed by this action. This action is equivalent to:
public HttpResponseMessage Post() {
var url;
// Some logic to construct the URL
var response = new HttpResponseMessage(HttpStatusCode.TemporaryRedirect);
response.Headers.Location = new System.Uri(url);
return response;
}
This is straightforward enough, but there is one improvement I would like to make. The request body could potentially contain a large amount of data, so I would like to leverage the HTTP status code 100 to make this request more efficient. With the controller as it is now, a conversation might look like this:
> POST /api/test HTTP/1.1
> Expect: 100-continue
> ...
< HTTP/1.1 100 Continue
> (request body is sent)
< HTTP/1.1 307 Temporary Redirect
< Location: (the URL)
< ...
Since the request body is not needed by the redirection action, I would like to be able to shorten the conversation to:
> POST /api/controller HTTP/1.1
> Expect: 100-continue
> ...
< HTTP/1.1 307 Temporary Redirect
< Location: (the URL)
< ...
I have spent the better part of a day researching how to accomplish this, and I have not been able to come up with a solution. In my research, I have learned:
ApiController
's action executes, the 100 Continue
has already been sent.ApiController
is constructed, the 100 Continue
has already been sent.HttpApplication
's PreRequestHandlerExecute
event is triggered, the 100 Continue
response has not been sent.DelegatingHandler
executes, the 100 Continue
has already been sent.Based on this, the best solution I have come up with so far is to create an HttpModule
which uses the RouteData
on the RequestContext
to override the response when the ApiController
in question is the recipient of the request. This is far from an ideal solution, however, for several reasons (code separation, not taking advantage of Web API's parameter binding, and bypassing additional logic in an AuthorizeAttribute
on the ApiController
).
It seems as if there must be a better solution to this, but I have found very little information on how to properly handle the Expect: 100-continue
header in a Web API application. What would be the simplest way to implement this ApiController
to properly handle the Expect: 100-continue
header?
...Are you sure that you need this optimization?
If you're using IIS 6, you're looking at kicking down into IIS 5 Compatibility Mode and writing a ReadRawData/SendRawData ISAPI Filter. An ISAPI Extension is out of the question for reasons given further down in my response. (If you're using IIS 5 or below, may God have mercy on your soul)
If you're using IIS 7+, you might be able to get away with writing an IIS Native Module.
You are correct in your thinking that by the time the controller becomes involved, the response has already been sent because Web API lives inside ASP.NET; this response is being handled by the IIS Core.
Some light reading material
HTTP.SYS IIS and the 100 Continue
David Wang
A "100 continue", like a "400 Bad Request" or a Kernel Response Cache Hit, is special in that HTTP.SYS transparently handles it in kernel mode without notifying user mode of anything.In addition, ISAPI Extensions cannot interact with any response output - they can only generate response output, not see results of response output. Thus, an ISAPI Extension will never be able to interact with requests that generate "100 continue" nor "100 continue" responses themselves to suppress them.
On IIS6, the only way to inject user mode processing into these transparent request handlings of HTTP.SYS is to run in IIS5 Compatibility Mode and use an ReadRawData/SendRawData ISAPI Filter. ReadRawData forces HTTP.SYS to hand the raw data off the network into user mode for filtering PRIOR to parsing that user mode output into HTTP requests to place into queues.
Of course, this method completely defeats the purpose of running IIS6 with Application Pools and process isolation (a single failure in this filtering user mode process halts the entire server)... but such is the server-side compromise when the client is buggy...
FYI: This approach will not work on Vista Server/IIS7. HTTP.SYS will no longer hand raw data off the network into user mode for filtering prior to parsing, so it will be impossible for user mode code to know that a request which triggers the automatic "100 continue" happened.
Haacked Http Web Request Expect 100 Continue
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With