1 /* Copyright 1999-2005 The Apache Software Foundation or its licensors, as
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * chunk_filter.c --- HTTP/1.1 chunked transfer encoding filter.
21 #include "apr_strings.h"
22 #include "apr_thread_proc.h" /* for RLIMIT stuff */
24 #define APR_WANT_STRFUNC
29 #include "http_config.h"
30 #include "http_connection.h"
31 #include "http_core.h"
32 #include "http_protocol.h" /* For index_of_response(). Grump. */
33 #include "http_request.h"
35 #include "util_filter.h"
36 #include "util_ebcdic.h"
38 #include "scoreboard.h"
42 apr_status_t ap_http_chunk_filter(ap_filter_t *f, apr_bucket_brigade *b)
44 #define ASCII_CRLF "\015\012"
45 #define ASCII_ZERO "\060"
46 conn_rec *c = f->r->connection;
47 apr_bucket_brigade *more;
51 for (more = NULL; b; b = more, more = NULL) {
53 apr_bucket *eos = NULL;
54 apr_bucket *flush = NULL;
55 /* XXX: chunk_hdr must remain at this scope since it is used in a
58 char chunk_hdr[20]; /* enough space for the snprintf below */
61 for (e = APR_BRIGADE_FIRST(b);
62 e != APR_BRIGADE_SENTINEL(b);
63 e = APR_BUCKET_NEXT(e))
65 if (APR_BUCKET_IS_EOS(e)) {
66 /* there shouldn't be anything after the eos */
70 if (APR_BUCKET_IS_FLUSH(e)) {
73 else if (e->length == (apr_size_t)-1) {
74 /* unknown amount of data (e.g. a pipe) */
78 rv = apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
79 if (rv != APR_SUCCESS) {
84 * There may be a new next bucket representing the
85 * rest of the data stream on which a read() may
86 * block so we pass down what we have so far.
89 more = apr_brigade_split(b, APR_BUCKET_NEXT(e));
93 /* If there was nothing in this bucket then we can
94 * safely move on to the next one without pausing
95 * to pass down what we have counted up so far.
106 * XXX: if there aren't very many bytes at this point it may
107 * be a good idea to set them aside and return for more,
108 * unless we haven't finished counting this brigade yet.
110 /* if there are content bytes, then wrap them in a chunk */
114 * Insert the chunk header, specifying the number of bytes in
117 hdr_len = apr_snprintf(chunk_hdr, sizeof(chunk_hdr),
118 "%" APR_UINT64_T_HEX_FMT CRLF, (apr_uint64_t)bytes);
119 ap_xlate_proto_to_ascii(chunk_hdr, hdr_len);
120 e = apr_bucket_transient_create(chunk_hdr, hdr_len,
122 APR_BRIGADE_INSERT_HEAD(b, e);
125 * Insert the end-of-chunk CRLF before an EOS or
126 * FLUSH bucket, or appended to the brigade
128 e = apr_bucket_immortal_create(ASCII_CRLF, 2, c->bucket_alloc);
130 APR_BUCKET_INSERT_BEFORE(eos, e);
132 else if (flush != NULL) {
133 APR_BUCKET_INSERT_BEFORE(flush, e);
136 APR_BRIGADE_INSERT_TAIL(b, e);
140 /* RFC 2616, Section 3.6.1
142 * If there is an EOS bucket, then prefix it with:
143 * 1) the last-chunk marker ("0" CRLF)
145 * 3) the end-of-chunked body CRLF
147 * If there is no EOS bucket, then do nothing.
149 * XXX: it would be nice to combine this with the end-of-chunk
150 * marker above, but this is a bit more straight-forward for
154 /* XXX: (2) trailers ... does not yet exist */
155 e = apr_bucket_immortal_create(ASCII_ZERO ASCII_CRLF
157 ASCII_CRLF, 5, c->bucket_alloc);
158 APR_BUCKET_INSERT_BEFORE(eos, e);
161 /* pass the brigade to the next filter. */
162 rv = ap_pass_brigade(f->next, b);
163 if (rv != APR_SUCCESS || eos != NULL) {