1 /* Copyright 1999-2004 The Apache Software Foundation
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
17 * chunk_filter.c --- HTTP/1.1 chunked transfer encoding filter.
20 #include "apr_strings.h"
21 #include "apr_thread_proc.h" /* for RLIMIT stuff */
23 #define APR_WANT_STRFUNC
28 #include "http_config.h"
29 #include "http_connection.h"
30 #include "http_core.h"
31 #include "http_protocol.h" /* For index_of_response(). Grump. */
32 #include "http_request.h"
34 #include "util_filter.h"
35 #include "util_ebcdic.h"
37 #include "scoreboard.h"
41 apr_status_t ap_http_chunk_filter(ap_filter_t *f, apr_bucket_brigade *b)
43 #define ASCII_CRLF "\015\012"
44 #define ASCII_ZERO "\060"
45 conn_rec *c = f->r->connection;
46 apr_bucket_brigade *more;
50 for (more = NULL; b; b = more, more = NULL) {
52 apr_bucket *eos = NULL;
53 apr_bucket *flush = NULL;
54 /* XXX: chunk_hdr must remain at this scope since it is used in a
57 char chunk_hdr[20]; /* enough space for the snprintf below */
60 for (e = APR_BRIGADE_FIRST(b);
61 e != APR_BRIGADE_SENTINEL(b);
62 e = APR_BUCKET_NEXT(e))
64 if (APR_BUCKET_IS_EOS(e)) {
65 /* there shouldn't be anything after the eos */
69 if (APR_BUCKET_IS_FLUSH(e)) {
72 else if (e->length == (apr_size_t)-1) {
73 /* unknown amount of data (e.g. a pipe) */
77 rv = apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
78 if (rv != APR_SUCCESS) {
83 * There may be a new next bucket representing the
84 * rest of the data stream on which a read() may
85 * block so we pass down what we have so far.
88 more = apr_brigade_split(b, APR_BUCKET_NEXT(e));
92 /* If there was nothing in this bucket then we can
93 * safely move on to the next one without pausing
94 * to pass down what we have counted up so far.
105 * XXX: if there aren't very many bytes at this point it may
106 * be a good idea to set them aside and return for more,
107 * unless we haven't finished counting this brigade yet.
109 /* if there are content bytes, then wrap them in a chunk */
113 * Insert the chunk header, specifying the number of bytes in
116 hdr_len = apr_snprintf(chunk_hdr, sizeof(chunk_hdr),
117 "%" APR_UINT64_T_HEX_FMT CRLF, (apr_uint64_t)bytes);
118 ap_xlate_proto_to_ascii(chunk_hdr, hdr_len);
119 e = apr_bucket_transient_create(chunk_hdr, hdr_len,
121 APR_BRIGADE_INSERT_HEAD(b, e);
124 * Insert the end-of-chunk CRLF before an EOS or
125 * FLUSH bucket, or appended to the brigade
127 e = apr_bucket_immortal_create(ASCII_CRLF, 2, c->bucket_alloc);
129 APR_BUCKET_INSERT_BEFORE(eos, e);
131 else if (flush != NULL) {
132 APR_BUCKET_INSERT_BEFORE(flush, e);
135 APR_BRIGADE_INSERT_TAIL(b, e);
139 /* RFC 2616, Section 3.6.1
141 * If there is an EOS bucket, then prefix it with:
142 * 1) the last-chunk marker ("0" CRLF)
144 * 3) the end-of-chunked body CRLF
146 * If there is no EOS bucket, then do nothing.
148 * XXX: it would be nice to combine this with the end-of-chunk
149 * marker above, but this is a bit more straight-forward for
153 /* XXX: (2) trailers ... does not yet exist */
154 e = apr_bucket_immortal_create(ASCII_ZERO ASCII_CRLF
156 ASCII_CRLF, 5, c->bucket_alloc);
157 APR_BUCKET_INSERT_BEFORE(eos, e);
160 /* pass the brigade to the next filter. */
161 rv = ap_pass_brigade(f->next, b);
162 if (rv != APR_SUCCESS || eos != NULL) {