From: Jeff Trawick Date: Mon, 28 Aug 2000 20:36:42 +0000 (+0000) Subject: Update chunk_filter to handle buckets with unknown length (e.g., pipes). X-Git-Tag: APACHE_2_0_ALPHA_7~212 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=933a5d5736b154595f1566c721e27d46f5d319e4;p=apache Update chunk_filter to handle buckets with unknown length (e.g., pipes). As soon as we hit such a bucket, we'll read from it then pass everything we have so far on to the next filter. At that point we'll start over. Also, increase the size of the chunk header buffer to handle larger lengths. Note: There is still an extra final chunk header (0) when mod_cgi is used because EOS is coming down twice. This is likely to have some bugs here and there. Even worse, it is butt ugly and in need of simplification. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@86155 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/modules/http/http_core.c b/modules/http/http_core.c index f15e6368e6..1cb96cd63c 100644 --- a/modules/http/http_core.c +++ b/modules/http/http_core.c @@ -2921,49 +2921,84 @@ static int default_handler(request_rec *r) */ static int chunk_filter(ap_filter_t *f, ap_bucket_brigade *b) { - ap_bucket *dptr = b->head; - int len = 0; - char lenstr[6]; + ap_bucket *dptr = b->head, *lb, *next, *tail; + int len = 0, cur_len; + char lenstr[strlen("ffffffff\r\n") + 1]; + const char *cur_str; int hit_eos = 0; + apr_status_t rv = 0; /* currently bytes written, will be APR_* */ while (dptr) { if (dptr->type == AP_BUCKET_EOS) { hit_eos = 1; + break; } + else if (dptr->length == -1) { /* indeterminate (e.g., a pipe) */ + dptr->read(dptr, &cur_str, &cur_len, 0); + if (cur_len) { + len += cur_len; + /* write out what we have so far */ + apr_snprintf(lenstr, sizeof(lenstr), "%x\r\n", len); + lb = ap_bucket_create_transient(lenstr, strlen(lenstr)); + lb->next = b->head; + lb->next->prev = lb; + b->head = lb; + next = dptr->next; + tail = b->tail; + b->tail = ap_bucket_create_transient("\r\n", 2); + dptr->next = b->tail; + b->tail->prev = dptr; + rv += ap_pass_brigade(f->next, b); + /* start a new brigade */ + len = 0; + b = ap_brigade_create(f->r->pool); + dptr = next; + b->head = dptr; + b->tail = tail; + } + else { + dptr = dptr->next; + } + } else { len += dptr->length; + dptr = dptr->next; } - dptr = dptr->next; - } - - apr_snprintf(lenstr, 6, "%x\r\n", len); - dptr = ap_bucket_create_transient(lenstr, strlen(lenstr)); - b->head->prev = dptr; - dptr->next = b->head; - b->head = dptr; - dptr = ap_bucket_create_transient("\r\n", 2); - if (hit_eos) { - b->tail->prev->next = dptr; - dptr->prev = b->tail->prev; - b->tail->prev = dptr; - dptr->next = b->tail; } - else { - ap_brigade_append_buckets(b, dptr); + if (len) { + apr_snprintf(lenstr, sizeof(lenstr), "%x\r\n", len); + lb = ap_bucket_create_transient(lenstr, strlen(lenstr)); + lb->next = b->head; + lb->next->prev = lb; + b->head = lb; + lb = ap_bucket_create_transient("\r\n", 2); + if (hit_eos) { + b->tail->prev->next = lb; + lb->prev = b->tail->prev; + b->tail->prev = lb; + lb->next = b->tail; + } + else { + ap_brigade_append_buckets(b, lb); + } } - - if (hit_eos && len != 0) { - dptr = ap_bucket_create_transient("0\r\n\r\n", 5); - b->tail->prev->next = dptr; - dptr->prev = b->tail->prev; - b->tail->prev = dptr; - dptr->next = b->tail; + if (hit_eos) { + lb = ap_bucket_create_transient("0\r\n\r\n", 5); + if (b->tail->prev) { + b->tail->prev->next = lb; + } + lb->prev = b->tail->prev; + b->tail->prev = lb; + lb->next = b->tail; + if (b->head == b->tail) { + b->head = lb; + } } - - return ap_pass_brigade(f->next, b); + rv += ap_pass_brigade(f->next, b); + return rv; } -/* Default filter. This filter should almost always be used. It's only job +/* Default filter. This filter should almost always be used. Its only job * is to send the headers if they haven't already been sent, and then send * the actual data. To send the data, we create an iovec out of the bucket * brigade and then call the sendv function. On platforms that don't