- From: Roy T. Fielding <fielding@kiwi.ICS.UCI.EDU>
- Date: Wed, 19 Feb 1997 09:40:32 -0800
- To: ben@algroup.co.uk
- Cc: HTTP Working Group <http-wg@cuckoo.hpl.hp.com>
Ben Laurie writes: >Since no-one else from the Apache Group has mentioned it, I thought I'd better. >I know that there's various things we are supposed to be looking at, but most >of the Apache Group are spending most of their spare time trying to get 1.2 >out, and encountering some significant difficulties with HTTP/1.1. So, don't >take silence from AG to indicate lack of interest! No doubt we'll be back soon! Ummm, we never left. Aside from the problems I already described a few months ago, the only new HTTP/1.1 problem we have is with pipelining and persistent connections and greedy/lazy browsers. I haven't mentioned it yet because we haven't nailed down all the causes, but here is a summary. I'm sure the other Apache people will chime-in if I've forgotten something. A more detailed discussion is at http://www.apache.org/docs/misc/fin_wait_2.html Basically, what we are seeing is a lot of connections being left in FIN_WAIT_2 state after the server has closed the connection (for whatever reason, but usually due to a pre-request timeout). The one known source of the FIN_WAIT_2 state (wherein the server's TCB is waiting for the client to send a FIN or RST) is due to current clients with keep-alive enabled -- they open multiple connections to the server and then leave them open, never checking to see that the connection has been closed, and thus never closing their side of the connection. That is a generic problem with client/server applications, so the only real solution is to either require all clients to be good (not likely) or include a FIN_WAIT_2 timeout within the TCP implementation of the OS. The other source of FIN_WAIT_2 states is still unknown, but is somehow connected to the way we are lingering on a half-closed connection in order to ensure the client has time to ACK the last response sent to the server, and the server has enough time to receive the ACK before it fully-closes the connection. This lingering behavior exists to avoid the TCP buffer reset problem discussed in several notes within the HTTP/1.1 specification. However, I believe that the cause of this problem is either in our implementation or that of the OS implementation of the shutdown() system call, and therefore not a problem with HTTP/1.1 per se. One thing I should note is that we have not yet attempted to complete an HTTP/1.1 proxy. Our current proxy, which is a bit of a bastard child for people who were desperately seeking an alternative to the old CERN proxy, is suffering from a lack of volunteers to improve it. If anybody reading this is using the Apache proxy and would like to help make it HTTP/1.1-compliant, please let me know. Oh yeah, one other thing... The BNF for the Allow header is 1#Method, which is a problem if a resource is set to disallow all methods, as might be the case for a resource made temporarily unavailable. The simple solution is to change it to #Method, wherein no value means no methods are allowed. Ah, and a third thing (funny how things get remembered) ... The order and precedence in which the various If-* conditional header fields are checked is important, and I don't recall it being detailed in the specification. Anyway, the order should be as follows: =============================== /* If an If-Match request-header field was given and * if our ETag does not match any of the entity tags in that field * and the field value is not "*" (meaning match anything), then * respond with a status of 412 (Precondition Failed). */ if (if_match) { if ((if_match[0] != '*') && !find_token(r->pool, if_match, etag)) return HTTP_PRECONDITION_FAILED; } /* Else if a valid If-Unmodified-Since request-header field was given * and the requested resource has been modified since the time * specified in this field, then the server MUST * respond with a status of 412 (Precondition Failed). */ else if (if_unmodified) { time_t ius = parseHTTPdate(if_unmodified); if ((ius != BAD_DATE) && (mtime > ius)) return HTTP_PRECONDITION_FAILED; } /* If an If-None-Match request-header field was given and * if our ETag matches any of the entity tags in that field or * if the field value is "*" (meaning match anything), then * if the request method was GET or HEAD, the server SHOULD * respond with a 304 (Not Modified) response. * For all other request methods, the server MUST * respond with a status of 412 (Precondition Failed). */ if (if_nonematch) { if ((if_nonematch[0] == '*') || find_token(r->pool,if_nonematch,etag)) return (r->method_number == M_GET) ? HTTP_NOT_MODIFIED : HTTP_PRECONDITION_FAILED; } /* Else if a valid If-Modified-Since request-header field was given * and it is a GET or HEAD request * and the requested resource has not been modified since the time * specified in this field, then the server MUST * respond with a status of 304 (Not Modified). * A date later than the server's current request time is invalid. */ else if (if_modified_since && (r->method_number == M_GET)) { time_t ims = parseHTTPdate(if_modified_since); if ((ims >= mtime) && (ims <= r->request_time)) return HTTP_NOT_MODIFIED; } =============================== The order is important because ETags have greater accuracy than pure modification dates (if implemented correctly), and thus should be given precedence in handling the conditionals. ...Roy T. Fielding Department of Information & Computer Science (fielding@ics.uci.edu) University of California, Irvine, CA 92697-3425 fax:+1(714)824-4056 http://www.ics.uci.edu/~fielding/
Received on Wednesday, 19 February 1997 10:38:54 UTC