diff options
author | Philip M. Gollucci <pgollucci@apache.org> | 2011-11-13 01:20:32 +0100 |
---|---|---|
committer | Philip M. Gollucci <pgollucci@apache.org> | 2011-11-13 01:20:32 +0100 |
commit | 4472a86146a20a356383475792bae37870c7862a (patch) | |
tree | 629b76803ce960183dc145c9f23c9e0c816309d7 /server/apreq_parser.c | |
parent | Server directive display (-L): Include directives of DSOs. (diff) | |
download | apache2-4472a86146a20a356383475792bae37870c7862a.tar.xz apache2-4472a86146a20a356383475792bae37870c7862a.zip |
As discussed at AC NA 2011
o relocate srclib/libapreq/library/*.c -> server/apreq_${f}.c
o relocate srclib/libapreq/include/*.h -> include/*.h
o remove apreq_version.[hc] related stuff since its nolonger its own lib
o connect modules/apreq to the build under 'most' default comment out in httpd.conf
o update make_exports.awk to handle APREQ marcos
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1201372 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'server/apreq_parser.c')
-rw-r--r-- | server/apreq_parser.c | 356 |
1 files changed, 356 insertions, 0 deletions
diff --git a/server/apreq_parser.c b/server/apreq_parser.c new file mode 100644 index 0000000000..69c0c4f035 --- /dev/null +++ b/server/apreq_parser.c @@ -0,0 +1,356 @@ +/* +** 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_error.h" +#include "apreq_parser.h" +#include "apreq_util.h" +#include "apr_strings.h" +#include "apr_xml.h" +#include "apr_hash.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); + +APREQ_DECLARE(apreq_parser_t *) apreq_parser_make(apr_pool_t *pool, + apr_bucket_alloc_t *ba, + const char *content_type, + apreq_parser_function_t pfn, + apr_size_t brigade_limit, + const char *temp_dir, + apreq_hook_t *hook, + void *ctx) +{ + apreq_parser_t *p = apr_palloc(pool, sizeof *p); + p->content_type = content_type; + p->parser = pfn; + p->hook = hook; + p->pool = pool; + p->bucket_alloc = ba; + p->brigade_limit = brigade_limit; + p->temp_dir = temp_dir; + p->ctx = ctx; + return p; +} + +APREQ_DECLARE(apreq_hook_t *) apreq_hook_make(apr_pool_t *pool, + apreq_hook_function_t hook, + apreq_hook_t *next, + void *ctx) +{ + apreq_hook_t *h = apr_palloc(pool, sizeof *h); + h->hook = hook; + h->next = next; + h->pool = pool; + h->ctx = ctx; + return h; +} + + +/*XXX this may need to check the parser's state before modifying the hook list */ +APREQ_DECLARE(apr_status_t) apreq_parser_add_hook(apreq_parser_t *p, + apreq_hook_t *h) +{ + apreq_hook_t *last = h; + + while (last->next) + last = last->next; + + last->next = p->hook; + p->hook = h; + + return APR_SUCCESS; +} + +static int default_parsers_lock = 0; +static apr_hash_t *default_parsers = NULL; +static apr_pool_t *default_parser_pool = NULL; + +static apr_status_t apreq_parsers_cleanup(void *data) +{ + default_parsers_lock = 0; + default_parsers = NULL; + default_parser_pool = NULL; + + return APR_SUCCESS; +} + +APREQ_DECLARE(apr_status_t) apreq_pre_initialize(apr_pool_t *pool) +{ + apr_status_t status; + + if (default_parser_pool != NULL) + return APR_SUCCESS; + + if (default_parsers_lock) + return APREQ_ERROR_GENERAL; + + status = apr_pool_create(&default_parser_pool, pool); + if (status != APR_SUCCESS) + return status; + + apr_pool_cleanup_register(default_parser_pool, NULL, + apreq_parsers_cleanup, + apr_pool_cleanup_null); + + default_parsers = apr_hash_make(default_parser_pool); + + apreq_register_parser("application/x-www-form-urlencoded", + apreq_parse_urlencoded); + apreq_register_parser("multipart/form-data", apreq_parse_multipart); + apreq_register_parser("multipart/related", apreq_parse_multipart); + + return APR_SUCCESS; +} + +APREQ_DECLARE(apr_status_t) apreq_post_initialize(apr_pool_t *pool) +{ + (void)pool; + + if (default_parser_pool == NULL) + return APREQ_ERROR_GENERAL; + + default_parsers_lock = 1; + return APR_SUCCESS; +} + +APREQ_DECLARE(apr_status_t) apreq_initialize(apr_pool_t *pool) +{ + apr_status_t s = apreq_pre_initialize(pool); + + if (s != APR_SUCCESS) + return s; + + return apreq_post_initialize(pool); +} + + +APREQ_DECLARE(apr_status_t) apreq_register_parser(const char *enctype, + apreq_parser_function_t pfn) +{ + apreq_parser_function_t *f = NULL; + + if (default_parsers == NULL) + return APR_EINIT; + + if (enctype == NULL) + return APR_EINVAL; + + if (default_parsers_lock) + return APREQ_ERROR_GENERAL; + + if (pfn != NULL) { + f = apr_palloc(default_parser_pool, sizeof *f); + *f = pfn; + } + apr_hash_set(default_parsers, apr_pstrdup(default_parser_pool, enctype), + APR_HASH_KEY_STRING, f); + + return APR_SUCCESS; +} + +APREQ_DECLARE(apreq_parser_function_t)apreq_parser(const char *enctype) +{ + apreq_parser_function_t *f; + apr_size_t tlen = 0; + + if (enctype == NULL || default_parsers_lock == 0) + return NULL; + + while(enctype[tlen] && enctype[tlen] != ';') + ++tlen; + + f = apr_hash_get(default_parsers, enctype, tlen); + + if (f != NULL) + return *f; + else + return NULL; +} + +APREQ_DECLARE_HOOK(apreq_hook_disable_uploads) +{ + return (bb == NULL) ? APR_SUCCESS : APREQ_ERROR_GENERAL; +} + +APREQ_DECLARE_HOOK(apreq_hook_discard_brigade) +{ + apr_status_t s = APR_SUCCESS; + if (hook->next) + s = apreq_hook_run(hook->next, param, bb); + if (bb != NULL) + apr_brigade_cleanup(bb); + return s; +} + + +/* generic parser */ + +struct gen_ctx { + apreq_param_t *param; + enum { + GEN_INCOMPLETE, + GEN_COMPLETE, + GEN_ERROR + } status; +}; + +APREQ_DECLARE_PARSER(apreq_parse_generic) +{ + struct gen_ctx *ctx = parser->ctx; + apr_pool_t *pool = parser->pool; + apr_status_t s = APR_SUCCESS; + apr_bucket *e = APR_BRIGADE_LAST(bb); + unsigned saw_eos = 0; + + if (ctx == NULL) { + parser->ctx = ctx = apr_palloc(pool, sizeof *ctx); + ctx->status = GEN_INCOMPLETE; + ctx->param = apreq_param_make(pool, + "_dummy_", strlen("_dummy_"), "", 0); + ctx->param->upload = apr_brigade_create(pool, parser->bucket_alloc); + ctx->param->info = apr_table_make(pool, APREQ_DEFAULT_NELTS); + } + + + PARSER_STATUS_CHECK(GEN); + + while (e != APR_BRIGADE_SENTINEL(bb)) { + if (APR_BUCKET_IS_EOS(e)) { + saw_eos = 1; + break; + } + e = APR_BUCKET_PREV(e); + } + + if (parser->hook != NULL) { + s = apreq_hook_run(parser->hook, ctx->param, bb); + if (s != APR_SUCCESS) { + ctx->status = GEN_ERROR; + return s; + } + } + + apreq_brigade_setaside(bb, pool); + s = apreq_brigade_concat(pool, parser->temp_dir, parser->brigade_limit, + ctx->param->upload, bb); + + if (s != APR_SUCCESS) { + ctx->status = GEN_ERROR; + return s; + } + + if (saw_eos) { + ctx->status = GEN_COMPLETE; + return APR_SUCCESS; + } + else + return APR_INCOMPLETE; +} + + +struct xml_ctx { + apr_xml_doc *doc; + apr_xml_parser *xml_parser; + enum { + XML_INCOMPLETE, + XML_COMPLETE, + XML_ERROR + } status; +}; + + +APREQ_DECLARE_HOOK(apreq_hook_apr_xml_parser) +{ + apr_pool_t *pool = hook->pool; + struct xml_ctx *ctx = hook->ctx; + apr_status_t s = APR_SUCCESS; + apr_bucket *e; + + if (ctx == NULL) { + hook->ctx = ctx = apr_palloc(pool, sizeof *ctx); + ctx->doc = NULL; + ctx->xml_parser = apr_xml_parser_create(pool); + ctx->status = XML_INCOMPLETE; + } + + PARSER_STATUS_CHECK(XML); + + for (e = APR_BRIGADE_FIRST(bb); e != APR_BRIGADE_SENTINEL(bb); + e = APR_BUCKET_NEXT(e)) + { + const char *data; + apr_size_t dlen; + + if (APR_BUCKET_IS_EOS(e)) { + s = apr_xml_parser_done(ctx->xml_parser, &ctx->doc); + if (s == APR_SUCCESS) { + ctx->status = XML_COMPLETE; + if (hook->next) + s = apreq_hook_run(hook->next, param, bb); + } + else { + ctx->status = XML_ERROR; + } + return s; + } + else if (APR_BUCKET_IS_METADATA(e)) { + continue; + } + + s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ); + + if (s != APR_SUCCESS) { + ctx->status = XML_ERROR; + return s; + } + + s = apr_xml_parser_feed(ctx->xml_parser, data, dlen); + + if (s != APR_SUCCESS) { + ctx->status = XML_ERROR; + return s; + } + + } + + if (hook->next) + return apreq_hook_run(hook->next, param, bb); + + return APR_SUCCESS; +} + + +APREQ_DECLARE_HOOK(apreq_hook_find_param) +{ + apreq_hook_find_param_ctx_t *ctx = hook->ctx; + int is_final = (bb == NULL) || APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb)); + apr_status_t s = (hook->next == NULL) + ? APR_SUCCESS : apreq_hook_run(hook->next, param, bb); + + if (is_final && s == APR_SUCCESS + && strcasecmp(ctx->name, param->v.name) == 0) { + ctx->param = param; + ctx->prev->next = hook->next; + } + return s; +} |