parser_header.c revision 8556b99a258c0fabe095957939d5b1cb5e84dd11
1516N/A/*
742N/A** Licensed to the Apache Software Foundation (ASF) under one or more
742N/A** contributor license agreements. See the NOTICE file distributed with
742N/A** this work for additional information regarding copyright ownership.
742N/A** The ASF licenses this file to You under the Apache License, Version 2.0
742N/A** (the "License"); you may not use this file except in compliance with
742N/A** the License. You may obtain a copy of the License at
742N/A**
742N/A** http://www.apache.org/licenses/LICENSE-2.0
742N/A**
742N/A** Unless required by applicable law or agreed to in writing, software
742N/A** distributed under the License is distributed on an "AS IS" BASIS,
742N/A** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
742N/A** See the License for the specific language governing permissions and
742N/A** limitations under the License.
742N/A*/
742N/A#include <assert.h>
742N/A#include "apreq_parser.h"
742N/A#include "apreq_error.h"
742N/A#include "apreq_util.h"
742N/A
742N/A#define PARSER_STATUS_CHECK(PREFIX) do { \
3339N/A if (ctx->status == PREFIX##_ERROR) \
742N/A return APREQ_ERROR_GENERAL; \
742N/A else if (ctx->status == PREFIX##_COMPLETE) \
742N/A return APR_SUCCESS; \
1116N/A else if (bb == NULL) \
1638N/A return APR_INCOMPLETE; \
3234N/A} while (0);
3234N/A
3245N/A
3339N/Astruct hdr_ctx {
3234N/A apr_bucket_brigade *bb;
1638N/A apr_size_t nlen;
1431N/A apr_size_t glen;
2651N/A apr_size_t vlen;
1116N/A enum {
1638N/A HDR_NAME,
1638N/A HDR_GAP,
742N/A HDR_VALUE,
1431N/A HDR_NEWLINE,
941N/A HDR_CONTINUE,
1116N/A HDR_COMPLETE,
742N/A HDR_ERROR
1638N/A } status;
1638N/A};
1638N/A
2651N/A/********************* header parsing utils ********************/
742N/A
742N/A
742N/Astatic apr_status_t split_header_line(apreq_param_t **p,
742N/A apr_pool_t *pool,
742N/A apr_bucket_brigade *bb,
742N/A apr_size_t nlen,
742N/A apr_size_t glen,
742N/A apr_size_t vlen)
742N/A{
2028N/A apreq_param_t *param;
1968N/A apreq_value_t *v;
1968N/A apr_bucket *e, *f;
742N/A apr_status_t s;
1431N/A struct iovec vec[APREQ_DEFAULT_NELTS], *iov, *end;
742N/A apr_array_header_t arr;
1431N/A char *dest;
2028N/A const char *data;
2028N/A apr_size_t dlen;
2028N/A
742N/A if (nlen == 0)
742N/A return APR_EBADARG;
742N/A
742N/A param = apreq_param_make(pool, NULL, nlen, NULL, vlen - 1); /*drop (CR)LF */
742N/A *(const apreq_value_t **)&v = &param->v;
1850N/A
742N/A arr.pool = pool;
742N/A arr.elt_size = sizeof(struct iovec);
742N/A arr.nelts = 0;
742N/A arr.nalloc = APREQ_DEFAULT_NELTS;
1968N/A arr.elts = (char *)vec;
2028N/A
1431N/A e = APR_BRIGADE_FIRST(bb);
1431N/A
742N/A /* store name in a temporary iovec array */
742N/A
742N/A while (nlen > 0) {
742N/A apr_size_t len;
742N/A end = apr_array_push(&arr);
1638N/A s = apr_bucket_read(e, (const char **)&end->iov_base,
1638N/A &len, APR_BLOCK_READ);
1638N/A if (s != APR_SUCCESS)
1638N/A return s;
1638N/A
2651N/A assert(nlen >= len);
2651N/A end->iov_len = len;
2651N/A nlen -= len;
2651N/A
2651N/A e = APR_BUCKET_NEXT(e);
2651N/A }
1431N/A
2651N/A /* skip gap */
2651N/A
2651N/A while (glen > 0) {
2651N/A s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
2651N/A if (s != APR_SUCCESS)
2651N/A return s;
2651N/A
2651N/A assert(glen >= dlen);
1431N/A glen -= dlen;
2028N/A e = APR_BUCKET_NEXT(e);
1431N/A }
1431N/A
2651N/A /* copy value */
742N/A assert(vlen > 0);
2958N/A dest = v->data;
2651N/A while (vlen > 0) {
2651N/A
2651N/A s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
2651N/A if (s != APR_SUCCESS)
2651N/A return s;
2651N/A
2651N/A memcpy(dest, data, dlen);
2651N/A dest += dlen;
1638N/A assert(vlen >= dlen);
2651N/A vlen -= dlen;
1431N/A e = APR_BUCKET_NEXT(e);
2651N/A }
2651N/A
2651N/A assert(dest[-1] == '\n');
2651N/A
2651N/A if (dest[-2] == '\r')
2651N/A --dest;
2651N/A
2651N/A dest[-1] = 0;
2651N/A v->dlen = (dest - v->data) - 1;
2651N/A
2651N/A /* write name */
2651N/A v->name = dest;
3339N/A iov = (struct iovec *)arr.elts;
3339N/A
3339N/A while (iov <= end) {
2651N/A memcpy(dest, iov->iov_base, iov->iov_len);
2651N/A dest += iov->iov_len;
2651N/A ++iov;
2651N/A }
2651N/A *dest = 0;
2651N/A nlen = dest - v->name;
2651N/A
3234N/A while ((f = APR_BRIGADE_FIRST(bb)) != e)
2651N/A apr_bucket_delete(f);
2651N/A
2651N/A apreq_param_tainted_on(param);
2651N/A *p = param;
2651N/A return APR_SUCCESS;
2651N/A
2651N/A}
2651N/A
2651N/A
2651N/AAPREQ_DECLARE_PARSER(apreq_parse_headers)
742N/A{
2651N/A apr_pool_t *pool = parser->pool;
2651N/A apr_bucket *e;
2651N/A struct hdr_ctx *ctx;
2651N/A
2651N/A if (parser->ctx == NULL) {
2651N/A ctx = apr_pcalloc(pool, sizeof *ctx);
2651N/A ctx->bb = apr_brigade_create(pool, parser->bucket_alloc);
2651N/A parser->ctx = ctx;
2651N/A ctx->status = HDR_NAME;
2651N/A }
2651N/A else
2651N/A ctx = parser->ctx;
2651N/A
2651N/A PARSER_STATUS_CHECK(HDR);
2651N/A e = APR_BRIGADE_LAST(ctx->bb);
2651N/A APR_BRIGADE_CONCAT(ctx->bb, bb);
2651N/A
2651N/A parse_hdr_brigade:
2651N/A
2651N/A
2651N/A /* parse the brigade for CRLF_CRLF-terminated header block,
2651N/A * each time starting from the front of the brigade.
2651N/A */
2651N/A
2651N/A for (e = APR_BUCKET_NEXT(e);
2651N/A e != APR_BRIGADE_SENTINEL(ctx->bb);
2958N/A e = APR_BUCKET_NEXT(e))
2651N/A {
2651N/A apr_size_t off = 0, dlen;
2651N/A const char *data;
2651N/A apr_status_t s;
2651N/A apreq_param_t *param = NULL; /* silences gcc-4.0 warning */
2651N/A
2651N/A if (APR_BUCKET_IS_EOS(e)) {
2651N/A ctx->status = HDR_COMPLETE;
852N/A APR_BRIGADE_CONCAT(bb, ctx->bb);
2651N/A return APR_SUCCESS;
2958N/A }
2651N/A s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
2859N/A
2859N/A if ( s != APR_SUCCESS ) {
2859N/A ctx->status = HDR_ERROR;
2859N/A return s;
2651N/A }
2651N/A if (dlen == 0)
2651N/A continue;
2651N/A
2651N/A parse_hdr_bucket:
2651N/A
2651N/A /* gap nlen = 13
2651N/A * vvv glen = 3
2651N/A * Sample-Header: grape vlen = 5
2651N/A * ^^^^^^^^^^^^^ ^^^^^
2651N/A * name value
2651N/A */
2651N/A
2651N/A switch (ctx->status) {
2651N/A
2651N/A case HDR_NAME:
2651N/A
2651N/A while (off < dlen) {
2651N/A switch (data[off++]) {
2651N/A
2651N/A case '\n':
2651N/A if (off < dlen)
2651N/A apr_bucket_split(e, off);
2651N/A e = APR_BUCKET_NEXT(e);
2651N/A
2651N/A do {
2651N/A apr_bucket *f = APR_BRIGADE_FIRST(ctx->bb);
2651N/A apr_bucket_delete(f);
2651N/A } while (e != APR_BRIGADE_FIRST(ctx->bb));
2651N/A APR_BRIGADE_CONCAT(bb, ctx->bb);
2651N/A ctx->status = HDR_COMPLETE;
2651N/A return APR_SUCCESS;
2651N/A
852N/A case ':':
2651N/A if (off > 1) {
2651N/A apr_bucket_split(e, off - 1);
2651N/A dlen -= off - 1;
2651N/A data += off - 1;
2651N/A off = 1;
2651N/A e = APR_BUCKET_NEXT(e);
2651N/A }
2651N/A ++ctx->glen;
2651N/A ctx->status = HDR_GAP;
2651N/A goto parse_hdr_bucket;
2651N/A
2651N/A default:
2651N/A ++ctx->nlen;
2651N/A }
2651N/A
2651N/A }
2651N/A
2651N/A break;
2651N/A
2651N/A
2651N/A case HDR_GAP:
2651N/A
2651N/A while (off < dlen) {
2651N/A switch (data[off++]) {
2651N/A case ' ':
2651N/A case '\t':
2651N/A ++ctx->glen;
2651N/A break;
2651N/A
2651N/A case '\n':
2651N/A ctx->status = HDR_NEWLINE;
2651N/A goto parse_hdr_bucket;
2651N/A
2651N/A default:
2651N/A ctx->status = HDR_VALUE;
2651N/A if (off > 1) {
2651N/A apr_bucket_split(e, off - 1);
1431N/A dlen -= off - 1;
2651N/A data += off - 1;
1431N/A off = 1;
2652N/A e = APR_BUCKET_NEXT(e);
2651N/A }
2651N/A ++ctx->vlen;
2651N/A goto parse_hdr_bucket;
2651N/A }
742N/A }
1638N/A break;
1638N/A
1638N/A
1638N/A case HDR_VALUE:
1638N/A
1638N/A while (off < dlen) {
1638N/A ++ctx->vlen;
1638N/A if (data[off++] == '\n') {
1638N/A ctx->status = HDR_NEWLINE;
1638N/A goto parse_hdr_bucket;
1638N/A }
1638N/A }
1638N/A break;
1638N/A
1638N/A
1638N/A case HDR_NEWLINE:
1638N/A
1638N/A if (off == dlen)
1638N/A break;
3171N/A else {
1638N/A switch (data[off]) {
1638N/A
1638N/A case ' ':
1638N/A case '\t':
1638N/A ctx->status = HDR_CONTINUE;
1970N/A ++off;
1638N/A ++ctx->vlen;
2028N/A break;
2028N/A
1638N/A default:
1638N/A /* can parse brigade now */
1638N/A if (off > 0)
1638N/A apr_bucket_split(e, off);
1638N/A s = split_header_line(&param, pool, ctx->bb, ctx->nlen, ctx->glen, ctx->vlen);
1638N/A if (parser->hook != NULL && s == APR_SUCCESS)
1638N/A s = apreq_hook_run(parser->hook, param, NULL);
1638N/A
1638N/A if (s != APR_SUCCESS) {
1638N/A ctx->status = HDR_ERROR;
1638N/A return s;
1638N/A }
1638N/A
1638N/A apreq_value_table_add(&param->v, t);
1638N/A e = APR_BRIGADE_SENTINEL(ctx->bb);
1638N/A ctx->status = HDR_NAME;
1638N/A ctx->nlen = 0;
1638N/A ctx->vlen = 0;
1638N/A ctx->glen = 0;
1638N/A
1638N/A goto parse_hdr_brigade;
1638N/A }
1638N/A
1638N/A /* cases ' ', '\t' fall through to HDR_CONTINUE */
2910N/A }
2910N/A
1638N/A
1638N/A case HDR_CONTINUE:
1638N/A
1638N/A while (off < dlen) {
1638N/A switch (data[off++]) {
1638N/A case ' ':
1638N/A case '\t':
1638N/A ++ctx->vlen;
1638N/A break;
1638N/A
1638N/A case '\n':
1638N/A ctx->status = HDR_NEWLINE;
1638N/A goto parse_hdr_bucket;
2073N/A
1638N/A default:
2028N/A ctx->status = HDR_VALUE;
3171N/A ++ctx->vlen;
1638N/A goto parse_hdr_bucket;
1638N/A }
1638N/A }
1638N/A break;
1638N/A
1638N/A default:
1638N/A ; /* not reached */
2073N/A }
2028N/A }
1638N/A apreq_brigade_setaside(ctx->bb,pool);
1638N/A return APR_INCOMPLETE;
1638N/A}
1638N/A