fielding 97/07/19 13:17:45
Modified: src Tag: APACHE_1_2_X CHANGES http_core.c http_protocol.c http_protocol.h http_request.c Log: In HTTP/1.1, whether or not a request message contains a body is independent of the request method and based solely on the presence of a Content-Length or Transfer-Encoding. Therefore, our default handlers need to be prepared to read a body even if they don't know what to do with it; otherwise, the body would be mistaken for the next request on a persistent connection. discard_request_body() has been added to take care of that. PR: 378 Reviewed by: Dean Gaudet Revision Changes Path No revision No revision 1.286.2.28 +8 -0 apache/src/CHANGES Index: CHANGES =================================================================== RCS file: /export/home/cvs/apache/src/CHANGES,v retrieving revision 1.286.2.27 retrieving revision 1.286.2.28 diff -C3 -r1.286.2.27 -r1.286.2.28 *** CHANGES 1997/07/19 19:13:56 1.286.2.27 --- CHANGES 1997/07/19 20:17:38 1.286.2.28 *************** *** 1,5 **** --- 1,13 ---- Changes with Apache 1.2.2 + *) API: In HTTP/1.1, whether or not a request message contains a body + is independent of the request method and based solely on the presence + of a Content-Length or Transfer-Encoding. Therefore, our default + handlers need to be prepared to read a body even if they don't know + what to do with it; otherwise, the body would be mistaken for the + next request on a persistent connection. discard_request_body() + has been added to take care of that. [Roy Fielding] PR#378 + *) API: Symbol APACHE_RELEASE provides a numeric form of the Apache release version number, such that it always increases along the same lines as our source code branching. [Roy Fielding] 1.81.2.5 +7 -2 apache/src/http_core.c Index: http_core.c =================================================================== RCS file: /export/home/cvs/apache/src/http_core.c,v retrieving revision 1.81.2.4 retrieving revision 1.81.2.5 diff -C3 -r1.81.2.4 -r1.81.2.5 *** http_core.c 1997/07/05 17:56:49 1.81.2.4 --- http_core.c 1997/07/19 20:17:39 1.81.2.5 *************** *** 1324,1332 **** (core_dir_config *)get_module_config(r->per_dir_config, &core_module); int rangestatus, errstatus; FILE *f; ! r->allowed |= (1 << M_GET); - r->allowed |= (1 << M_TRACE); r->allowed |= (1 << M_OPTIONS); if (r->method_number == M_INVALID) { --- 1324,1337 ---- (core_dir_config *)get_module_config(r->per_dir_config, &core_module); int rangestatus, errstatus; FILE *f; ! ! /* This handler has no use for a request body (yet), but we still ! * need to read and discard it if the client sent one. ! */ ! if ((errstatus = discard_request_body(r)) != OK) ! return errstatus; ! r->allowed |= (1 << M_GET); r->allowed |= (1 << M_OPTIONS); if (r->method_number == M_INVALID) { 1.126.2.3 +53 -19 apache/src/http_protocol.c Index: http_protocol.c =================================================================== RCS file: /export/home/cvs/apache/src/http_protocol.c,v retrieving revision 1.126.2.2 retrieving revision 1.126.2.3 diff -C3 -r1.126.2.2 -r1.126.2.3 *** http_protocol.c 1997/07/01 06:50:29 1.126.2.2 --- http_protocol.c 1997/07/19 20:17:40 1.126.2.3 *************** *** 1087,1120 **** bputs("\015\012", client); /* Send the terminating empty line */ } static char *make_allow(request_rec *r) { ! int allowed = r->allowed; ! ! if( allowed == 0 ) { ! /* RFC2068 #14.7, Allow must contain at least one method. So rather ! * than deal with the possibility of trying not to emit an Allow: ! * header, i.e. #10.4.6 says 405 Method Not Allowed MUST include ! * an Allow header, we'll just say TRACE is valid. ! */ ! return( "TRACE" ); ! } ! ! return 2 + pstrcat(r->pool, (allowed & (1 << M_GET)) ? ", GET, HEAD" : "", ! (allowed & (1 << M_POST)) ? ", POST" : "", ! (allowed & (1 << M_PUT)) ? ", PUT" : "", ! (allowed & (1 << M_DELETE)) ? ", DELETE" : "", ! (allowed & (1 << M_OPTIONS)) ? ", OPTIONS" : "", ! (allowed & (1 << M_TRACE)) ? ", TRACE" : "", ! NULL); ! } int send_http_trace (request_rec *r) { /* Get the original request */ while (r->prev) r = r->prev; hard_timeout("send TRACE", r); r->content_type = "message/http"; --- 1087,1117 ---- bputs("\015\012", client); /* Send the terminating empty line */ } + /* Build the Allow field-value from the request handler method mask. + * Note that we always allow TRACE, since it is handled below. + */ static char *make_allow(request_rec *r) { ! return 2 + pstrcat(r->pool, ! (r->allowed & (1 << M_GET)) ? ", GET, HEAD" : "", ! (r->allowed & (1 << M_POST)) ? ", POST" : "", ! (r->allowed & (1 << M_PUT)) ? ", PUT" : "", ! (r->allowed & (1 << M_DELETE)) ? ", DELETE" : "", ! (r->allowed & (1 << M_OPTIONS)) ? ", OPTIONS" : "", ! ", TRACE", ! NULL); } int send_http_trace (request_rec *r) { + int rv; + /* Get the original request */ while (r->prev) r = r->prev; + if ((rv = setup_client_block(r, REQUEST_NO_BODY))) + return rv; + hard_timeout("send TRACE", r); r->content_type = "message/http"; *************** *** 1514,1519 **** --- 1511,1553 ---- return (chunk_start + len_read); } + /* In HTTP/1.1, any method can have a body. However, most GET handlers + * wouldn't know what to do with a request body if they received one. + * This helper routine tests for and reads any message body in the request, + * simply discarding whatever it receives. We need to do this because + * failing to read the request body would cause it to be interpreted + * as the next request on a persistent connection. + * + * Since we return an error status if the request is malformed, this + * routine should be called at the beginning of a no-body handler, e.g., + * + * if ((retval = discard_request_body(r)) != OK) + * return retval; + */ + int discard_request_body(request_rec *r) + { + int rv; + + if ((rv = setup_client_block(r, REQUEST_CHUNKED_PASS))) + return rv; + + if (should_client_block(r)) { + char dumpbuf[HUGE_STRING_LEN]; + + hard_timeout("reading request body", r); + while ((rv = get_client_block(r, dumpbuf, HUGE_STRING_LEN)) > 0) + continue; + kill_timeout(r); + + if (rv < 0) + return HTTP_BAD_REQUEST; + } + return OK; + } + + /* + * Send the body of a response to the client. + */ long send_fd(FILE *f, request_rec *r) { return send_fd_length(f, r, -1); } long send_fd_length(FILE *f, request_rec *r, long length) 1.19.2.1 +1 -0 apache/src/http_protocol.h Index: http_protocol.h =================================================================== RCS file: /export/home/cvs/apache/src/http_protocol.h,v retrieving revision 1.19 retrieving revision 1.19.2.1 diff -C3 -r1.19 -r1.19.2.1 *** http_protocol.h 1997/04/07 10:58:38 1.19 --- http_protocol.h 1997/07/19 20:17:40 1.19.2.1 *************** *** 134,139 **** --- 134,140 ---- int setup_client_block (request_rec *r, int read_policy); int should_client_block (request_rec *r); long get_client_block (request_rec *r, char *buffer, int bufsiz); + int discard_request_body (request_rec *r); /* Sending a byterange */ 1.50.2.4 +4 -2 apache/src/http_request.c Index: http_request.c =================================================================== RCS file: /export/home/cvs/apache/src/http_request.c,v retrieving revision 1.50.2.3 retrieving revision 1.50.2.4 diff -C3 -r1.50.2.3 -r1.50.2.4 *** http_request.c 1997/07/01 06:50:30 1.50.2.3 --- http_request.c 1997/07/19 20:17:41 1.50.2.4 *************** *** 910,917 **** * we handle it specially. */ if (r->method_number == M_TRACE) { ! send_http_trace(r); ! finalize_request_protocol(r); return; } --- 910,919 ---- * we handle it specially. */ if (r->method_number == M_TRACE) { ! if ((access_status = send_http_trace(r))) ! die(access_status, r); ! else ! finalize_request_protocol(r); return; }