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_error.h"
19 #include "apreq_parser.h"
20 #include "apreq_util.h"
21 #include "apr_strings.h"
25 #define PARSER_STATUS_CHECK(PREFIX) do { \
26 if (ctx->status == PREFIX##_ERROR) \
27 return APREQ_ERROR_GENERAL; \
28 else if (ctx->status == PREFIX##_COMPLETE) \
30 else if (bb == NULL) \
31 return APR_INCOMPLETE; \
34 APREQ_DECLARE(apreq_parser_t *) apreq_parser_make(apr_pool_t *pool,
35 apr_bucket_alloc_t *ba,
36 const char *content_type,
37 apreq_parser_function_t pfn,
38 apr_size_t brigade_limit,
43 apreq_parser_t *p = apr_palloc(pool, sizeof *p);
44 p->content_type = content_type;
49 p->brigade_limit = brigade_limit;
50 p->temp_dir = temp_dir;
55 APREQ_DECLARE(apreq_hook_t *) apreq_hook_make(apr_pool_t *pool,
56 apreq_hook_function_t hook,
60 apreq_hook_t *h = apr_palloc(pool, sizeof *h);
69 /*XXX this may need to check the parser's state before modifying the hook list */
70 APREQ_DECLARE(apr_status_t) apreq_parser_add_hook(apreq_parser_t *p,
73 apreq_hook_t *last = h;
84 static int default_parsers_lock = 0;
85 static apr_hash_t *default_parsers = NULL;
86 static apr_pool_t *default_parser_pool = NULL;
88 static apr_status_t apreq_parsers_cleanup(void *data)
90 default_parsers_lock = 0;
91 default_parsers = NULL;
92 default_parser_pool = NULL;
97 APREQ_DECLARE(apr_status_t) apreq_pre_initialize(apr_pool_t *pool)
101 if (default_parser_pool != NULL)
104 if (default_parsers_lock)
105 return APREQ_ERROR_GENERAL;
107 status = apr_pool_create(&default_parser_pool, pool);
108 if (status != APR_SUCCESS)
111 apr_pool_cleanup_register(default_parser_pool, NULL,
112 apreq_parsers_cleanup,
113 apr_pool_cleanup_null);
115 default_parsers = apr_hash_make(default_parser_pool);
117 apreq_register_parser("application/x-www-form-urlencoded",
118 apreq_parse_urlencoded);
119 apreq_register_parser("multipart/form-data", apreq_parse_multipart);
120 apreq_register_parser("multipart/related", apreq_parse_multipart);
125 APREQ_DECLARE(apr_status_t) apreq_post_initialize(apr_pool_t *pool)
129 if (default_parser_pool == NULL)
130 return APREQ_ERROR_GENERAL;
132 default_parsers_lock = 1;
136 APREQ_DECLARE(apr_status_t) apreq_initialize(apr_pool_t *pool)
138 apr_status_t s = apreq_pre_initialize(pool);
140 if (s != APR_SUCCESS)
143 return apreq_post_initialize(pool);
147 APREQ_DECLARE(apr_status_t) apreq_register_parser(const char *enctype,
148 apreq_parser_function_t pfn)
150 apreq_parser_function_t *f = NULL;
152 if (default_parsers == NULL)
158 if (default_parsers_lock)
159 return APREQ_ERROR_GENERAL;
162 f = apr_palloc(default_parser_pool, sizeof *f);
165 apr_hash_set(default_parsers, apr_pstrdup(default_parser_pool, enctype),
166 APR_HASH_KEY_STRING, f);
171 APREQ_DECLARE(apreq_parser_function_t)apreq_parser(const char *enctype)
173 apreq_parser_function_t *f;
176 if (enctype == NULL || default_parsers_lock == 0)
179 while(enctype[tlen] && enctype[tlen] != ';')
182 f = apr_hash_get(default_parsers, enctype, tlen);
190 APREQ_DECLARE_HOOK(apreq_hook_disable_uploads)
192 return (bb == NULL) ? APR_SUCCESS : APREQ_ERROR_GENERAL;
195 APREQ_DECLARE_HOOK(apreq_hook_discard_brigade)
197 apr_status_t s = APR_SUCCESS;
199 s = apreq_hook_run(hook->next, param, bb);
201 apr_brigade_cleanup(bb);
209 apreq_param_t *param;
217 APREQ_DECLARE_PARSER(apreq_parse_generic)
219 struct gen_ctx *ctx = parser->ctx;
220 apr_pool_t *pool = parser->pool;
221 apr_status_t s = APR_SUCCESS;
222 apr_bucket *e = APR_BRIGADE_LAST(bb);
223 unsigned saw_eos = 0;
226 parser->ctx = ctx = apr_palloc(pool, sizeof *ctx);
227 ctx->status = GEN_INCOMPLETE;
228 ctx->param = apreq_param_make(pool,
229 "_dummy_", strlen("_dummy_"), "", 0);
230 ctx->param->upload = apr_brigade_create(pool, parser->bucket_alloc);
231 ctx->param->info = apr_table_make(pool, APREQ_DEFAULT_NELTS);
235 PARSER_STATUS_CHECK(GEN);
237 while (e != APR_BRIGADE_SENTINEL(bb)) {
238 if (APR_BUCKET_IS_EOS(e)) {
242 e = APR_BUCKET_PREV(e);
245 if (parser->hook != NULL) {
246 s = apreq_hook_run(parser->hook, ctx->param, bb);
247 if (s != APR_SUCCESS) {
248 ctx->status = GEN_ERROR;
253 apreq_brigade_setaside(bb, pool);
254 s = apreq_brigade_concat(pool, parser->temp_dir, parser->brigade_limit,
255 ctx->param->upload, bb);
257 if (s != APR_SUCCESS) {
258 ctx->status = GEN_ERROR;
263 ctx->status = GEN_COMPLETE;
267 return APR_INCOMPLETE;
273 apr_xml_parser *xml_parser;
282 APREQ_DECLARE_HOOK(apreq_hook_apr_xml_parser)
284 apr_pool_t *pool = hook->pool;
285 struct xml_ctx *ctx = hook->ctx;
286 apr_status_t s = APR_SUCCESS;
290 hook->ctx = ctx = apr_palloc(pool, sizeof *ctx);
292 ctx->xml_parser = apr_xml_parser_create(pool);
293 ctx->status = XML_INCOMPLETE;
296 PARSER_STATUS_CHECK(XML);
298 for (e = APR_BRIGADE_FIRST(bb); e != APR_BRIGADE_SENTINEL(bb);
299 e = APR_BUCKET_NEXT(e))
304 if (APR_BUCKET_IS_EOS(e)) {
305 s = apr_xml_parser_done(ctx->xml_parser, &ctx->doc);
306 if (s == APR_SUCCESS) {
307 ctx->status = XML_COMPLETE;
309 s = apreq_hook_run(hook->next, param, bb);
312 ctx->status = XML_ERROR;
316 else if (APR_BUCKET_IS_METADATA(e)) {
320 s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
322 if (s != APR_SUCCESS) {
323 ctx->status = XML_ERROR;
327 s = apr_xml_parser_feed(ctx->xml_parser, data, dlen);
329 if (s != APR_SUCCESS) {
330 ctx->status = XML_ERROR;
337 return apreq_hook_run(hook->next, param, bb);
343 APREQ_DECLARE_HOOK(apreq_hook_find_param)
345 apreq_hook_find_param_ctx_t *ctx = hook->ctx;
346 int is_final = (bb == NULL) || APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb));
347 apr_status_t s = (hook->next == NULL)
348 ? APR_SUCCESS : apreq_hook_run(hook->next, param, bb);
350 if (is_final && s == APR_SUCCESS && ctx->param == NULL
351 && strcasecmp(ctx->name, param->v.name) == 0) {
353 ctx->prev->next = hook->next;