From: Tony Finch Date: Fri, 8 Sep 2000 10:16:14 +0000 (+0000) Subject: Reduce the manualarity of managing bucket brigade lists by using the X-Git-Tag: APACHE_2_0_ALPHA_7~200 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6d7be19c9072186da530dcbe04d408a3dab6d6eb;p=apache Reduce the manualarity of managing bucket brigade lists by using the new AP_RING macros. Most of this commit is fairly pedestrian as you would expect, but I had to redo the chunking filter because of the amount of pointer juggling it did. I have done some minimal testing of this patch and it seems to work. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@86178 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/modules/generators/mod_cgi.c b/modules/generators/mod_cgi.c index d929167181..569c2718da 100644 --- a/modules/generators/mod_cgi.c +++ b/modules/generators/mod_cgi.c @@ -656,8 +656,8 @@ static int cgi_handler(request_rec *r) ap_send_http_header(r); if (!r->header_only) { bb = ap_brigade_create(r->pool); - ap_brigade_append_buckets(bb, ap_bucket_create_pipe(script_in)); - ap_brigade_append_buckets(bb, ap_bucket_create_eos()); + ap_brigade_add_bucket(bb, ap_bucket_create_pipe(script_in)); + ap_brigade_add_bucket(bb, ap_bucket_create_eos()); } ap_pass_brigade(r->filters, bb); @@ -667,8 +667,8 @@ static int cgi_handler(request_rec *r) if (script_in && nph) { bb = ap_brigade_create(r->pool); - ap_brigade_append_buckets(bb, ap_bucket_create_pipe(script_in)); - ap_brigade_append_buckets(bb, ap_bucket_create_eos()); + ap_brigade_add_bucket(bb, ap_bucket_create_pipe(script_in)); + ap_brigade_add_bucket(bb, ap_bucket_create_eos()); ap_pass_brigade(r->filters, bb); } diff --git a/modules/http/http_core.c b/modules/http/http_core.c index 43b87336d7..cdedb15821 100644 --- a/modules/http/http_core.c +++ b/modules/http/http_core.c @@ -2914,89 +2914,77 @@ static int default_handler(request_rec *r) return OK; } -/* This is an incredibly stupid chunking filter. This will need to be somewhat - * smart about when it actually sends the data, but this implements some sort - * of chunking for right now. +/* + * Turn a bucket brigade into a properly-formatted HTTP/1.1 chunk + * before passing it down to the next filter. + */ +static apr_status_t pass_chunk(ap_filter_t *f, ap_bucket_brigade *b, + apr_off_t bytes, int eos) +{ + char chunk_hdr[20]; /* enough space for the snprintf below */ + size_t hdr_len; + ap_bucket *e; + + if (bytes == 0) { + return APR_SUCCESS; + } + hdr_len = apr_snprintf(chunk_hdr, sizeof(chunk_hdr), "%qx" CRLF, bytes); + e = ap_bucket_create_transient(chunk_hdr, hdr_len); + AP_RING_INSERT_HEAD(&b->list, e, link); + if (eos) { + /* any trailer should go between the last two CRLFs */ + e = ap_bucket_create_immortal(CRLF "0" CRLF CRLF, 7); + AP_RING_INSERT_BEFORE(AP_RING_LAST(&b->list), e, link); + } else { + e = ap_bucket_create_immortal(CRLF, 2); + AP_RING_INSERT_TAIL(&b->list, e, link); + } + return ap_pass_brigade(f->next, b); +} + +/* + * HTTP/1.1 chunked transfer encoding filter. */ static apr_status_t chunk_filter(ap_filter_t *f, ap_bucket_brigade *b) { - ap_bucket *dptr = b->head, *lb, *next, *tail; - int len = 0, cur_len; - char lenstr[sizeof("ffffffff\r\n")]; - const char *cur_str; - int hit_eos = 0; - apr_status_t rv = APR_SUCCESS; - - 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); - if (rv != APR_SUCCESS) { - return rv; - } - /* 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; - } - } - 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) { - 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; - } + ap_bucket_brigade *more = NULL; + ap_bucket *e; + apr_status_t rv; + + for (more = NULL; b; b = more, more = NULL) { + apr_off_t bytes = 0; + int eos = 0; + AP_RING_FOREACH(e, &b->list, ap_bucket, link) { + if (e->type == AP_BUCKET_EOS) { + /* assume it is the last one in the brigade */ + eos = 1; + break; + } + else if (e->length == -1) { /* indeterminate (e.g., a pipe) */ + const char *data; + apr_ssize_t len; + rv = e->read(e, &data, &len, 1); + if (rv != APR_SUCCESS) { + return rv; + } + bytes += len; + more = ap_brigade_split(b, AP_RING_NEXT(e, link)); + break; + } + else { + bytes += e->length; + } + } + /* + * XXX: if there aren't very many bytes at this point it may + * be a good idea to set them aside and return for more. + */ + rv = pass_chunk(f, b, bytes, eos); + if (rv != APR_SUCCESS || eos) { + return rv; + } } - return ap_pass_brigade(f->next, b); + return APR_SUCCESS; } /* Default filter. This filter should almost always be used. Its only job @@ -3017,11 +3005,11 @@ static int core_filter(ap_filter_t *f, ap_bucket_brigade *b) #endif apr_status_t rv; apr_ssize_t bytes_sent = 0; - ap_bucket *dptr = b->head; + ap_bucket *e; int len = 0, written; const char *str; - -#if 0 + +#if 0 /* XXX: bit rot! */ /* This will all be needed once BUFF is removed from the code */ /* At this point we need to discover if there was any data saved from * the last call to core_filter. @@ -3042,16 +3030,19 @@ static int core_filter(ap_filter_t *f, ap_bucket_brigade *b) } else { #endif - while (dptr->read(dptr, &str, &len, 0) != AP_END_OF_BRIGADE) { - if ((rv = ap_bwrite(f->r->connection->client, str, len, &written)) - != APR_SUCCESS) { + AP_RING_FOREACH(e, &b->list, ap_bucket, link) { + rv = e->read(e, &str, &len, 0); + if (rv != APR_SUCCESS) { return rv; } - dptr = dptr->next; - bytes_sent += written; - if (!dptr) { - break; + if (len == AP_END_OF_BRIGADE) { + break; + } + rv = ap_bwrite(f->r->connection->client, str, len, &written); + if (rv != APR_SUCCESS) { + return rv; } + bytes_sent += written; } ap_brigade_destroy(b); /* This line will go away as soon as the BUFFs are removed */ diff --git a/modules/http/http_protocol.c b/modules/http/http_protocol.c index d74516814c..0969613a75 100644 --- a/modules/http/http_protocol.c +++ b/modules/http/http_protocol.c @@ -1329,7 +1329,7 @@ static void end_output_stream(request_rec *r) ap_bucket_brigade *bb; bb = ap_brigade_create(r->pool); - ap_brigade_append_buckets(bb, ap_bucket_create_eos()); + ap_brigade_add_bucket(bb, ap_bucket_create_eos()); ap_pass_brigade(r->filters, bb); } @@ -2519,7 +2519,7 @@ API_EXPORT(size_t) ap_send_mmap(apr_mmap_t *mm, request_rec *r, size_t offset, * until after the commit to actually write the code. */ bb = ap_brigade_create(r->pool); - ap_brigade_append_buckets(bb, ap_bucket_create_mmap(mm, 0, mm->size)); + ap_brigade_add_bucket(bb, ap_bucket_create_mmap(mm, 0, mm->size)); ap_pass_brigade(r->filters, bb); return mm->size; /* XXX - change API to report apr_status_t? */ @@ -2535,7 +2535,7 @@ API_EXPORT(int) ap_rputc(int c, request_rec *r) return EOF; bb = ap_brigade_create(r->pool); - ap_brigade_append_buckets(bb, ap_bucket_create_transient(&c2, 1)); + ap_brigade_add_bucket(bb, ap_bucket_create_transient(&c2, 1)); ap_pass_brigade(r->filters, bb); return c; @@ -2553,7 +2553,7 @@ API_EXPORT(int) ap_rputs(const char *str, request_rec *r) len = strlen(str); bb = ap_brigade_create(r->pool); - ap_brigade_append_buckets(bb, ap_bucket_create_transient(str, len)); + ap_brigade_add_bucket(bb, ap_bucket_create_transient(str, len)); ap_pass_brigade(r->filters, bb); return len; @@ -2569,7 +2569,7 @@ API_EXPORT(int) ap_rwrite(const void *buf, int nbyte, request_rec *r) return 0; bb = ap_brigade_create(r->pool); - ap_brigade_append_buckets(bb, ap_bucket_create_transient(buf, nbyte)); + ap_brigade_add_bucket(bb, ap_bucket_create_transient(buf, nbyte)); ap_pass_brigade(r->filters, bb); return nbyte; } diff --git a/server/util_filter.c b/server/util_filter.c index 491a52b379..5146bbfc9e 100644 --- a/server/util_filter.c +++ b/server/util_filter.c @@ -189,7 +189,7 @@ API_EXPORT(ap_bucket_brigade *) ap_get_saved_data(ap_filter_t *f, API_EXPORT(void) ap_save_data_to_filter(ap_filter_t *f, ap_bucket_brigade **b) { ap_bucket_brigade *bb = (ap_bucket_brigade *)f->ctx; - ap_bucket *dptr = bb->head; + ap_bucket *e; /* If have never stored any data in the filter, then we had better * create an empty bucket brigade so that we can concat. @@ -198,15 +198,9 @@ API_EXPORT(void) ap_save_data_to_filter(ap_filter_t *f, ap_bucket_brigade **b) bb = ap_brigade_create(f->r->pool); } - while (dptr) { - if (dptr->setaside) { - dptr->setaside(dptr); - } + AP_RING_FOREACH(e, &bb->list, ap_bucket, link) { + e->setaside(e); } - - /* Apend b to bb. This means b is now empty, and we can destory it safely. - */ ap_brigade_catenate(bb, *b); - ap_brigade_destroy(*b); f->ctx = bb; }