summaryrefslogtreecommitdiff
path: root/srclib/libapreq/library/parser_urlencoded.c
diff options
context:
space:
mode:
Diffstat (limited to 'srclib/libapreq/library/parser_urlencoded.c')
-rw-r--r--srclib/libapreq/library/parser_urlencoded.c275
1 files changed, 275 insertions, 0 deletions
diff --git a/srclib/libapreq/library/parser_urlencoded.c b/srclib/libapreq/library/parser_urlencoded.c
new file mode 100644
index 0000000000..e90d0dd382
--- /dev/null
+++ b/srclib/libapreq/library/parser_urlencoded.c
@@ -0,0 +1,275 @@
+/*
+** Licensed to the Apache Software Foundation (ASF) under one or more
+** contributor license agreements. See the NOTICE file distributed with
+** this work for additional information regarding copyright ownership.
+** The ASF licenses this file to You under the Apache License, Version 2.0
+** (the "License"); you may not use this file except in compliance with
+** the License. You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "apreq_parser.h"
+#include "apreq_util.h"
+#include "apreq_error.h"
+
+
+#define PARSER_STATUS_CHECK(PREFIX) do { \
+ if (ctx->status == PREFIX##_ERROR) \
+ return APREQ_ERROR_GENERAL; \
+ else if (ctx->status == PREFIX##_COMPLETE) \
+ return APR_SUCCESS; \
+ else if (bb == NULL) \
+ return APR_INCOMPLETE; \
+} while (0);
+
+
+
+struct url_ctx {
+ apr_bucket_brigade *bb;
+ apr_size_t nlen;
+ apr_size_t vlen;
+ enum {
+ URL_NAME,
+ URL_VALUE,
+ URL_COMPLETE,
+ URL_ERROR
+ } status;
+};
+
+
+/******************** application/x-www-form-urlencoded ********************/
+
+static apr_status_t split_urlword(apreq_param_t **p, apr_pool_t *pool,
+ apr_bucket_brigade *bb,
+ apr_size_t nlen,
+ apr_size_t vlen)
+{
+ apreq_param_t *param;
+ apreq_value_t *v;
+ apr_bucket *e, *f;
+ apr_status_t s;
+ struct iovec vec[APREQ_DEFAULT_NELTS];
+ apr_array_header_t arr;
+ apr_size_t mark;
+ apreq_charset_t charset;
+
+ if (nlen == 0)
+ return APR_EBADARG;
+
+ param = apreq_param_make(pool, NULL, nlen, NULL, vlen);
+ *(const apreq_value_t **)&v = &param->v;
+
+ arr.pool = pool;
+ arr.elt_size = sizeof(struct iovec);
+ arr.nelts = 0;
+ arr.nalloc = APREQ_DEFAULT_NELTS;
+ arr.elts = (char *)vec;
+
+ ++nlen, ++vlen;
+ e = APR_BRIGADE_FIRST(bb);
+
+ while (!APR_BUCKET_IS_EOS(e)) {
+ struct iovec *iov = apr_array_push(&arr);
+ apr_size_t len;
+ s = apr_bucket_read(e, (const char **)&iov->iov_base,
+ &len, APR_BLOCK_READ);
+ if (s != APR_SUCCESS)
+ return s;
+
+ iov->iov_len = len;
+ nlen -= len;
+
+ e = APR_BUCKET_NEXT(e);
+
+ if (nlen == 0) {
+ iov->iov_len--;
+ break;
+ }
+ }
+
+ mark = arr.nelts;
+
+ while (!APR_BUCKET_IS_EOS(e)) {
+ struct iovec *iov = apr_array_push(&arr);
+ apr_size_t len;
+ s = apr_bucket_read(e, (const char **)&iov->iov_base,
+ &len, APR_BLOCK_READ);
+ if (s != APR_SUCCESS)
+ return s;
+
+ iov->iov_len = len;
+ vlen -= len;
+
+ e = APR_BUCKET_NEXT(e);
+
+ if (vlen == 0) {
+ iov->iov_len--;
+ break;
+ }
+
+ }
+
+ s = apreq_decodev(v->data, &vlen,
+ (struct iovec *)arr.elts + mark, arr.nelts - mark);
+ if (s != APR_SUCCESS)
+ return s;
+
+ charset = apreq_charset_divine(v->data, vlen);
+
+ v->name = v->data + vlen + 1;
+ v->dlen = vlen;
+
+ s = apreq_decodev(v->name, &nlen, (struct iovec *)arr.elts, mark);
+ if (s != APR_SUCCESS)
+ return s;
+
+ switch (apreq_charset_divine(v->name, nlen)) {
+ case APREQ_CHARSET_UTF8:
+ if (charset == APREQ_CHARSET_ASCII)
+ charset = APREQ_CHARSET_UTF8;
+ case APREQ_CHARSET_ASCII:
+ break;
+
+ case APREQ_CHARSET_LATIN1:
+ if (charset != APREQ_CHARSET_CP1252)
+ charset = APREQ_CHARSET_LATIN1;
+ break;
+ case APREQ_CHARSET_CP1252:
+ charset = APREQ_CHARSET_CP1252;
+ }
+
+ v->nlen = nlen;
+
+ while ((f = APR_BRIGADE_FIRST(bb)) != e)
+ apr_bucket_delete(f);
+
+ apreq_param_tainted_on(param);
+ apreq_param_charset_set(param, charset);
+ *p = param;
+ return APR_SUCCESS;
+}
+
+APREQ_DECLARE_PARSER(apreq_parse_urlencoded)
+{
+ apr_pool_t *pool = parser->pool;
+ apr_bucket *e;
+ struct url_ctx *ctx;
+
+ if (parser->ctx == NULL) {
+ ctx = apr_pcalloc(pool, sizeof *ctx);
+ ctx->bb = apr_brigade_create(pool, parser->bucket_alloc);
+ parser->ctx = ctx;
+ ctx->status = URL_NAME;
+ }
+ else
+ ctx = parser->ctx;
+
+ PARSER_STATUS_CHECK(URL);
+ e = APR_BRIGADE_LAST(ctx->bb);
+ APR_BRIGADE_CONCAT(ctx->bb, bb);
+
+ parse_url_brigade:
+
+ for (e = APR_BUCKET_NEXT(e);
+ e != APR_BRIGADE_SENTINEL(ctx->bb);
+ e = APR_BUCKET_NEXT(e))
+ {
+ apreq_param_t *param;
+ apr_size_t off = 0, dlen;
+ const char *data;
+ apr_status_t s;
+
+ if (APR_BUCKET_IS_EOS(e)) {
+ if (ctx->status == URL_NAME) {
+ s = APR_SUCCESS;
+ }
+ else {
+ s = split_urlword(&param, pool, ctx->bb, ctx->nlen, ctx->vlen);
+ if (parser->hook != NULL && s == APR_SUCCESS)
+ s = apreq_hook_run(parser->hook, param, NULL);
+
+ if (s == APR_SUCCESS) {
+ apreq_value_table_add(&param->v, t);
+ ctx->status = URL_COMPLETE;
+ }
+ else {
+ ctx->status = URL_ERROR;
+ }
+ }
+
+ APR_BRIGADE_CONCAT(bb, ctx->bb);
+ return s;
+ }
+
+ s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
+ if ( s != APR_SUCCESS ) {
+ ctx->status = URL_ERROR;
+ return s;
+ }
+
+ parse_url_bucket:
+
+ switch (ctx->status) {
+
+ case URL_NAME:
+ while (off < dlen) {
+ switch (data[off++]) {
+ case '=':
+ apr_bucket_split(e, off);
+ dlen -= off;
+ data += off;
+ off = 0;
+ e = APR_BUCKET_NEXT(e);
+ ctx->status = URL_VALUE;
+ goto parse_url_bucket;
+ default:
+ ++ctx->nlen;
+ }
+ }
+ break;
+
+ case URL_VALUE:
+ while (off < dlen) {
+
+ switch (data[off++]) {
+ case '&':
+ case ';':
+ apr_bucket_split(e, off);
+ s = split_urlword(&param, pool, ctx->bb,
+ ctx->nlen, ctx->vlen);
+ if (parser->hook != NULL && s == APR_SUCCESS)
+ s = apreq_hook_run(parser->hook, param, NULL);
+
+ if (s != APR_SUCCESS) {
+ ctx->status = URL_ERROR;
+ return s;
+ }
+
+ apreq_value_table_add(&param->v, t);
+ ctx->status = URL_NAME;
+ ctx->nlen = 0;
+ ctx->vlen = 0;
+ e = APR_BRIGADE_SENTINEL(ctx->bb);
+ goto parse_url_brigade;
+
+ default:
+ ++ctx->vlen;
+ }
+ }
+ break;
+ default:
+ ; /* not reached */
+ }
+ }
+ apreq_brigade_setaside(ctx->bb, pool);
+ return APR_INCOMPLETE;
+}
+
+