2 ** Licensed to the Apache Software Foundation (ASF) under one or more
3 ** contributor license agreements. See the NOTICE file distributed with
4 ** this work for additional information regarding copyright ownership.
5 ** The ASF licenses this file to You under the Apache License, Version 2.0
6 ** (the "License"); you may not use this file except in compliance with
7 ** the License. You may obtain a copy of the License at
9 ** http://www.apache.org/licenses/LICENSE-2.0
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
18 #include "apreq_parser.h"
19 #include "apreq_error.h"
20 #include "apreq_util.h"
22 #define PARSER_STATUS_CHECK(PREFIX) do { \
23 if (ctx->status == PREFIX##_ERROR) \
24 return APREQ_ERROR_GENERAL; \
25 else if (ctx->status == PREFIX##_COMPLETE) \
27 else if (bb == NULL) \
28 return APR_INCOMPLETE; \
33 apr_bucket_brigade *bb;
48 /********************* header parsing utils ********************/
51 static apr_status_t split_header_line(apreq_param_t **p,
53 apr_bucket_brigade *bb,
62 struct iovec vec[APREQ_DEFAULT_NELTS], *iov, *end;
63 apr_array_header_t arr;
71 param = apreq_param_make(pool, NULL, nlen, NULL, vlen - 1); /*drop (CR)LF */
72 *(const apreq_value_t **)&v = ¶m->v;
75 arr.elt_size = sizeof(struct iovec);
77 arr.nalloc = APREQ_DEFAULT_NELTS;
78 arr.elts = (char *)vec;
80 e = APR_BRIGADE_FIRST(bb);
82 /* store name in a temporary iovec array */
86 end = apr_array_push(&arr);
87 s = apr_bucket_read(e, (const char **)&end->iov_base,
88 &len, APR_BLOCK_READ);
96 e = APR_BUCKET_NEXT(e);
102 s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
103 if (s != APR_SUCCESS)
106 assert(glen >= dlen);
108 e = APR_BUCKET_NEXT(e);
116 s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
117 if (s != APR_SUCCESS)
120 memcpy(dest, data, dlen);
122 assert(vlen >= dlen);
124 e = APR_BUCKET_NEXT(e);
127 assert(dest[-1] == '\n');
129 if (dest[-2] == '\r')
133 v->dlen = (dest - v->data) - 1;
137 iov = (struct iovec *)arr.elts;
140 memcpy(dest, iov->iov_base, iov->iov_len);
141 dest += iov->iov_len;
146 while ((f = APR_BRIGADE_FIRST(bb)) != e)
147 apr_bucket_delete(f);
149 apreq_param_tainted_on(param);
156 APREQ_DECLARE_PARSER(apreq_parse_headers)
158 apr_pool_t *pool = parser->pool;
162 if (parser->ctx == NULL) {
163 ctx = apr_pcalloc(pool, sizeof *ctx);
164 ctx->bb = apr_brigade_create(pool, parser->bucket_alloc);
166 ctx->status = HDR_NAME;
171 PARSER_STATUS_CHECK(HDR);
172 e = APR_BRIGADE_LAST(ctx->bb);
173 APR_BRIGADE_CONCAT(ctx->bb, bb);
178 /* parse the brigade for CRLF_CRLF-terminated header block,
179 * each time starting from the front of the brigade.
182 for (e = APR_BUCKET_NEXT(e);
183 e != APR_BRIGADE_SENTINEL(ctx->bb);
184 e = APR_BUCKET_NEXT(e))
186 apr_size_t off = 0, dlen;
189 apreq_param_t *param = NULL; /* silences gcc-4.0 warning */
191 if (APR_BUCKET_IS_EOS(e)) {
192 ctx->status = HDR_COMPLETE;
193 APR_BRIGADE_CONCAT(bb, ctx->bb);
196 s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
198 if ( s != APR_SUCCESS ) {
199 ctx->status = HDR_ERROR;
209 * Sample-Header: grape vlen = 5
210 * ^^^^^^^^^^^^^ ^^^^^
214 switch (ctx->status) {
219 switch (data[off++]) {
223 apr_bucket_split(e, off);
224 e = APR_BUCKET_NEXT(e);
227 apr_bucket *f = APR_BRIGADE_FIRST(ctx->bb);
228 apr_bucket_delete(f);
229 } while (e != APR_BRIGADE_FIRST(ctx->bb));
230 APR_BRIGADE_CONCAT(bb, ctx->bb);
231 ctx->status = HDR_COMPLETE;
236 apr_bucket_split(e, off - 1);
240 e = APR_BUCKET_NEXT(e);
243 ctx->status = HDR_GAP;
244 goto parse_hdr_bucket;
258 switch (data[off++]) {
265 ctx->status = HDR_NEWLINE;
266 goto parse_hdr_bucket;
269 ctx->status = HDR_VALUE;
271 apr_bucket_split(e, off - 1);
275 e = APR_BUCKET_NEXT(e);
278 goto parse_hdr_bucket;
288 if (data[off++] == '\n') {
289 ctx->status = HDR_NEWLINE;
290 goto parse_hdr_bucket;
305 ctx->status = HDR_CONTINUE;
311 /* can parse brigade now */
313 apr_bucket_split(e, off);
314 s = split_header_line(¶m, pool, ctx->bb, ctx->nlen, ctx->glen, ctx->vlen);
315 if (parser->hook != NULL && s == APR_SUCCESS)
316 s = apreq_hook_run(parser->hook, param, NULL);
318 if (s != APR_SUCCESS) {
319 ctx->status = HDR_ERROR;
323 apreq_value_table_add(¶m->v, t);
324 e = APR_BRIGADE_SENTINEL(ctx->bb);
325 ctx->status = HDR_NAME;
330 goto parse_hdr_brigade;
333 /* cases ' ', '\t' fall through to HDR_CONTINUE */
340 switch (data[off++]) {
347 ctx->status = HDR_NEWLINE;
348 goto parse_hdr_bucket;
351 ctx->status = HDR_VALUE;
353 goto parse_hdr_bucket;
362 apreq_brigade_setaside(ctx->bb,pool);
363 return APR_INCOMPLETE;