Return-Path: Delivered-To: apmail-httpd-cvs-archive@httpd.apache.org Received: (qmail 16769 invoked by uid 500); 6 Jul 2002 01:53:38 -0000 Mailing-List: contact cvs-help@httpd.apache.org; run by ezmlm Precedence: bulk Reply-To: dev@httpd.apache.org list-help: list-unsubscribe: list-post: Delivered-To: mailing list cvs@httpd.apache.org Received: (qmail 16758 invoked by uid 500); 6 Jul 2002 01:53:38 -0000 Delivered-To: apmail-httpd-2.0-cvs@apache.org Date: 6 Jul 2002 01:53:37 -0000 Message-ID: <20020706015337.42043.qmail@icarus.apache.org> From: brianp@apache.org To: httpd-2.0-cvs@apache.org Subject: cvs commit: httpd-2.0/server protocol.c X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N brianp 2002/07/05 18:53:37 Modified: server protocol.c Log: Eliminated the use of AP_MODE_SPECULATIVE brigade reads to check for request header continuation lines. Instead, ap_get_mime_headers_core() now sets aside each line of input until it sees the next line. If the next line starts with a tab, it is appended to the previous one; otherwise, the previous line is added to the request headers table. This reduces the number of temporary buckets that must be created and destroyed to read in a request. Revision Changes Path 1.111 +77 -29 httpd-2.0/server/protocol.c Index: protocol.c =================================================================== RCS file: /home/cvs/httpd-2.0/server/protocol.c,v retrieving revision 1.110 retrieving revision 1.111 diff -u -r1.110 -r1.111 --- protocol.c 4 Jul 2002 17:05:25 -0000 1.110 +++ protocol.c 6 Jul 2002 01:53:37 -0000 1.111 @@ -743,7 +743,10 @@ AP_DECLARE(void) ap_get_mime_headers_core(request_rec *r, apr_bucket_brigade *bb) { - char* field; + char *last_field = NULL; + apr_size_t last_len; + apr_size_t alloc_len = 0; + char *field; char *value; apr_size_t len; int fields_read = 0; @@ -758,10 +761,11 @@ */ while(1) { apr_status_t rv; + int folded = 0; field = NULL; rv = ap_rgetline(&field, DEFAULT_LIMIT_REQUEST_FIELDSIZE + 2, - &len, r, 1, bb); + &len, r, 0, bb); /* ap_rgetline returns APR_ENOSPC if it fills up the buffer before * finding the end-of-line. This is only going to happen if it @@ -787,39 +791,83 @@ return; } - /* Found a blank line, stop. */ - if (len == 0) { - break; - } + if (last_field != NULL) { + if ((len > 0) && (*field == '\t')) { + /* This line is a continuation of the preceding line(s), + * so append it to the line that we've set aside. + * Note: this uses a power-of-two allocator to avoid + * doing O(n) allocs and using O(n^2) space for + * continuations that span many many lines. + */ + if (last_len + len > alloc_len) { + char *fold_buf; + alloc_len += alloc_len; + if (last_len + len > alloc_len) { + alloc_len = last_len + len; + } + fold_buf = (char *)apr_palloc(r->pool, alloc_len); + memcpy(fold_buf, last_field, last_len); + last_field = fold_buf; + } + memcpy(last_field + last_len, field, len +1); /* +1 for nul */ + last_len += len; + folded = 1; + } + else { + + if (r->server->limit_req_fields + && (++fields_read > r->server->limit_req_fields)) { + r->status = HTTP_BAD_REQUEST; + apr_table_setn(r->notes, "error-notes", + "The number of request header fields " + "exceeds this server's limit."); + return; + } + + if (!(value = strchr(last_field, ':'))) { /* Find ':' or */ + r->status = HTTP_BAD_REQUEST; /* abort bad request */ + apr_table_setn(r->notes, "error-notes", + apr_pstrcat(r->pool, + "Request header field is " + "missing ':' separator.
\n" + "
\n",
  +                                               ap_escape_html(r->pool,
  +                                                              last_field),
  +                                               "
\n", NULL)); + return; + } + + *value = '\0'; + ++value; + while (*value == ' ' || *value == '\t') { + ++value; /* Skip to start of value */ + } + + apr_table_addn(tmp_headers, last_field, value); + + /* reset the alloc_len so that we'll allocate a new + * buffer if we have to do any more folding: we can't + * use the previous buffer because its contents are + * now part of tmp_headers + */ + alloc_len = 0; - if (r->server->limit_req_fields - && (++fields_read > r->server->limit_req_fields)) { - r->status = HTTP_BAD_REQUEST; - apr_table_setn(r->notes, "error-notes", - "The number of request header fields exceeds " - "this server's limit."); - return; + } /* end if current line is not a continuation starting with tab */ } - if (!(value = strchr(field, ':'))) { /* Find the colon separator */ - r->status = HTTP_BAD_REQUEST; /* or abort the bad request */ - apr_table_setn(r->notes, "error-notes", - apr_pstrcat(r->pool, - "Request header field is missing " - "colon separator.
\n" - "
\n",
  -                                       ap_escape_html(r->pool, field),
  -                                       "
\n", NULL)); - return; + /* Found a blank line, stop. */ + if (len == 0) { + break; } - *value = '\0'; - ++value; - while (*value == ' ' || *value == '\t') { - ++value; /* Skip to start of value */ + /* Keep track of this line so that we can parse it on + * the next loop iteration. (In the folded case, last_field + * has been updated already.) + */ + if (!folded) { + last_field = field; + last_len = len; } - - apr_table_addn(tmp_headers, field, value); } apr_table_overlap(r->headers_in, tmp_headers, APR_OVERLAP_TABLES_MERGE);