HttpWebRequest and Expect 100 Continue
How do the ServicePointManager.Expect100Continue and ServicePoint.Expect100Continue properties change the behavior of my HttpWebRequest? This is a question that seems to come up from time to time and I thought I would give a little more information.
First, lets talk about the difference between the two versions of this property. ServicePointManager is the master object that controls the creation and lookup of ServicePoints. As a general rule, properties set on ServicePointManager apply to newly created ServicePoints from that point forward. If you set the property on ServicePointManager after a ServicePoint is created, it will not be propogated to the already existing ServicePoints.
Now, having said that, lets look at what this property does. In a nutshell, it tells the HttpWebRequest object whether or not to send the "Expect: 100-continue" header with the request on the wire. What does this mean? When this header is sent on the wire this tells the server that the client is going to delay sending the body of the request for some period of time because it wants the server to give the client the OK (a 100 continue response) to upload the data. In current implementations, the HttpWebRequest object waits 350 milliseconds. Why is this important? There are many things that can go wrong during the HTTP request process. The server could redirect the user to a different location, it could require authentication, the connection could have been dropped in between requests, etc. In the case of redirection or authentication, this allows the client to try to avoid uploading the data (which it knows is useless) if possible. One example of where the client can avoid uploading the data is when the client sets the HttpWebRequest.SendChunked property to true. This means that the client will not tell the server the upload size, but will send the data in chunks. At the beginning of each chunk is information on how big the chunk is and the client sends a zero length chunk to advise the server that there is no more data coming.
What about when the connection is dropped between requests? Because HttpWebRequest keeps a pool of connections to any given server, the connection could be closed by the remote server without the client knowing that the connection has been dropped. Due to the fact that upload requests cannot be assumed to be idempotent, the client cannot safely retry the request if an error occurs beyond a certain point in the request process. If the client has sent even one byte of the upload body on the wire, then HttpWebRequest will fail if an error occurs in the connection. How does HttpWebRequest know if it has sent the body on the wire? It uses the delay between sending the headers (including the "Expect: 100-Continue" header) and sending they body as it's way figuring it out. If Expect100Continue functionality is enabled, this gives a small window where upload requests can be retried safely. If it is disabled, then an error that occurs when sending the request will cause the entire request to fail. This is true even if the data never hits the wire -- all HttpWebRequest knows is that it sent the data down to the underlying socket layer and can't tell if the error occured before or after the data went out on the wire.
I typically suggest that developers leave Expect100Continue set to true unless they are desperate for performance gains or are trying to work around some issue with the server or client.
Comments
Anonymous
June 19, 2006
Whats the best way to handle retrie's using HttpWebRequest? HttpWebRequest does not seem to offer any native mechanisms.
SergeAnonymous
June 20, 2006
There are some limited times when HttpWebRequest will automatically retry a request but there are many times when it will not because it doesn't know a resubmitted request will affect the state of web application receiving the request. Consider a Banking application that communicates over the network. If HttpWebRequest were to retry requests automatically, then it could potentially mess up the state of the bank account. Now, realistically, a banking application should have safeguards against such a problem, but HttpWebRequest can't really make that assumption.
Admittedly, HttpWebRequest could potentially provide some API that would allow a developer to tell it to go ahead and retry a request, but that functionality is not currently supported (I will suggest it to the System.Net team).
As for your need to handle retries with currently released versions of the product, you should submit your request and when an error occurs you will need to inspect the error and decide which types of errors are fatal and which ones are not fatal in the context of your application. You will also need to implement some type of max retry count logic as it is possible that you could get into some type of infinite failure/retry loop otherwise. When deciding what failures are non-fatal, I would look at the WebException.Status property to figure out what type of error occured. A description of the possible values can be found at http://msdn2.microsoft.com/en-us/system.net.webexceptionstatus.aspx.Anonymous
June 22, 2006
Thanks for the post. I'm a C# newbie. I'm trying to send the request body after reading the server response using 100-Continue. I want my application to either follow a redirect if that is returned from the server, or send the body if a 100 Continue is recieved, but it's not obvious to me how to send the body after checking the headers.
resp = (req.GetResponse() as HttpWebResponse);
Seems to hang if a 100 Continue is sent back from the server. (confirmed with packet sniffer)
I'm sure I'm missing something. Thanks in advance.
ryanAnonymous
June 26, 2006
The first thing I would tell you (and anyone else reading this) is that questions like this are typically better directed to the msdn forums (http://forums.microsoft.com/msdn/) because I don't always get around to reading comments on my blogs and they may go unanswered for a while.
To try to answer your question, I would ask for some more code from you. The most common cause of this behavior is that the request stream (returned by GetRequestStream()) is not being closed. As a general rule, you should always close any HttpResponse objects and streams that are associated with your request/response. Doing this signals the underlying objects that things should move along to the next stage in the process.
As for your question on redirects and uploads, keep in mind that some types of redirection can cause POST requests to be turned into GET requests. If you are getting back anything other than a 307 status code when the redirection occurs, then you should consider turning off automatic redirection on HttpWebRequest and handle the redirection yourself.Anonymous
April 21, 2008
The comment has been removedAnonymous
May 26, 2010
You can override the Expect100Continue property on the individual service point after you create the request. request.ServicePoint.Expect100Continue = false;Anonymous
December 11, 2014
İ understood like expect100continue send some body to the server. You set this option true if you upload or download something from server because you need 200 Status Code. Is that true? But my aim is to get http status code of web page like 200, 300, 400 or 500, as i understand i can set this to null. Thanks for answer.