]> granicus.if.org Git - apache/blob - server/apreq_parser.c
Add compiled and loaded PCRE version numbers
[apache] / server / apreq_parser.c
1 /*
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
8 **
9 **      http://www.apache.org/licenses/LICENSE-2.0
10 **
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.
16 */
17
18 #include "apreq_error.h"
19 #include "apreq_parser.h"
20 #include "apreq_util.h"
21 #include "apr_strings.h"
22 #include "apr_xml.h"
23 #include "apr_hash.h"
24
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)     \
29         return APR_SUCCESS;                        \
30     else if (bb == NULL)                           \
31         return APR_INCOMPLETE;                     \
32 } while (0);
33
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,
39                                                   const char *temp_dir,
40                                                   apreq_hook_t *hook,
41                                                   void *ctx)
42 {
43     apreq_parser_t *p = apr_palloc(pool, sizeof *p);
44     p->content_type = content_type;
45     p->parser = pfn;
46     p->hook = hook;
47     p->pool = pool;
48     p->bucket_alloc = ba;
49     p->brigade_limit = brigade_limit;
50     p->temp_dir = temp_dir;
51     p->ctx = ctx;
52     return p;
53 }
54
55 APREQ_DECLARE(apreq_hook_t *) apreq_hook_make(apr_pool_t *pool,
56                                               apreq_hook_function_t hook,
57                                               apreq_hook_t *next,
58                                               void *ctx)
59 {
60     apreq_hook_t *h = apr_palloc(pool, sizeof *h);
61     h->hook = hook;
62     h->next = next;
63     h->pool = pool;
64     h->ctx = ctx;
65     return h;
66 }
67
68
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,
71                                                   apreq_hook_t *h)
72 {
73     apreq_hook_t *last = h;
74
75     while (last->next)
76         last = last->next;
77
78     last->next = p->hook;
79     p->hook = h;
80
81     return APR_SUCCESS;
82 }
83
84 static int default_parsers_lock = 0;
85 static apr_hash_t *default_parsers = NULL;
86 static apr_pool_t *default_parser_pool = NULL;
87
88 static apr_status_t apreq_parsers_cleanup(void *data)
89 {
90     default_parsers_lock = 0;
91     default_parsers = NULL;
92     default_parser_pool = NULL;
93
94     return APR_SUCCESS;
95 }
96
97 APREQ_DECLARE(apr_status_t) apreq_pre_initialize(apr_pool_t *pool)
98 {
99     apr_status_t status;
100
101     if (default_parser_pool != NULL)
102         return APR_SUCCESS;
103
104     if (default_parsers_lock)
105         return APREQ_ERROR_GENERAL;
106
107     status = apr_pool_create(&default_parser_pool, pool);
108     if (status != APR_SUCCESS)
109         return status;
110
111     apr_pool_cleanup_register(default_parser_pool, NULL,
112                               apreq_parsers_cleanup,
113                               apr_pool_cleanup_null);
114
115     default_parsers = apr_hash_make(default_parser_pool);
116
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);
121
122     return APR_SUCCESS;
123 }
124
125 APREQ_DECLARE(apr_status_t) apreq_post_initialize(apr_pool_t *pool)
126 {
127     (void)pool;
128
129     if (default_parser_pool == NULL)
130         return APREQ_ERROR_GENERAL;
131
132     default_parsers_lock = 1;
133     return APR_SUCCESS;
134 }
135
136 APREQ_DECLARE(apr_status_t) apreq_initialize(apr_pool_t *pool)
137 {
138     apr_status_t s = apreq_pre_initialize(pool);
139
140     if (s != APR_SUCCESS)
141         return s;
142
143     return apreq_post_initialize(pool);
144 }
145
146
147 APREQ_DECLARE(apr_status_t) apreq_register_parser(const char *enctype,
148                                                   apreq_parser_function_t pfn)
149 {
150     apreq_parser_function_t *f = NULL;
151
152     if (default_parsers == NULL)
153         return APR_EINIT;
154
155     if (enctype == NULL)
156         return APR_EINVAL;
157
158     if (default_parsers_lock)
159         return APREQ_ERROR_GENERAL;
160
161     if (pfn != NULL) {
162         f = apr_palloc(default_parser_pool, sizeof *f);
163         *f = pfn;
164     }
165     apr_hash_set(default_parsers, apr_pstrdup(default_parser_pool, enctype),
166                  APR_HASH_KEY_STRING, f);
167
168     return APR_SUCCESS;
169 }
170
171 APREQ_DECLARE(apreq_parser_function_t)apreq_parser(const char *enctype)
172 {
173     apreq_parser_function_t *f;
174     apr_size_t tlen = 0;
175
176     if (enctype == NULL || default_parsers_lock == 0)
177         return NULL;
178
179     while(enctype[tlen] && enctype[tlen] != ';')
180         ++tlen;
181
182     f = apr_hash_get(default_parsers, enctype, tlen);
183
184     if (f != NULL)
185         return *f;
186     else
187         return NULL;
188 }
189
190 APREQ_DECLARE_HOOK(apreq_hook_disable_uploads)
191 {
192     return (bb == NULL) ? APR_SUCCESS : APREQ_ERROR_GENERAL;
193 }
194
195 APREQ_DECLARE_HOOK(apreq_hook_discard_brigade)
196 {
197     apr_status_t s = APR_SUCCESS;
198     if (hook->next)
199         s = apreq_hook_run(hook->next, param, bb);
200     if (bb != NULL)
201         apr_brigade_cleanup(bb);
202     return s;
203 }
204
205
206 /* generic parser */
207
208 struct gen_ctx {
209     apreq_param_t               *param;
210     enum {
211         GEN_INCOMPLETE,
212         GEN_COMPLETE,
213         GEN_ERROR
214     }                            status;
215 };
216
217 APREQ_DECLARE_PARSER(apreq_parse_generic)
218 {
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;
224
225     if (ctx == NULL) {
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);
232     }
233
234
235     PARSER_STATUS_CHECK(GEN);
236
237     while (e != APR_BRIGADE_SENTINEL(bb)) {
238         if (APR_BUCKET_IS_EOS(e)) {
239             saw_eos = 1;
240             break;
241         }
242         e = APR_BUCKET_PREV(e);
243     }
244
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;
249             return s;
250         }
251     }
252
253     apreq_brigade_setaside(bb, pool);
254     s = apreq_brigade_concat(pool, parser->temp_dir, parser->brigade_limit,
255                              ctx->param->upload, bb);
256
257     if (s != APR_SUCCESS) {
258         ctx->status = GEN_ERROR;
259         return s;
260     }
261
262     if (saw_eos) {
263         ctx->status = GEN_COMPLETE;
264         return APR_SUCCESS;
265     }
266     else
267         return APR_INCOMPLETE;
268 }
269
270
271 struct xml_ctx {
272     apr_xml_doc                 *doc;
273     apr_xml_parser              *xml_parser;
274     enum {
275         XML_INCOMPLETE,
276         XML_COMPLETE,
277         XML_ERROR
278     }                            status;
279 };
280
281
282 APREQ_DECLARE_HOOK(apreq_hook_apr_xml_parser)
283 {
284     apr_pool_t *pool = hook->pool;
285     struct xml_ctx *ctx = hook->ctx;
286     apr_status_t s = APR_SUCCESS;
287     apr_bucket *e;
288
289     if (ctx == NULL) {
290         hook->ctx = ctx = apr_palloc(pool, sizeof *ctx);
291         ctx->doc = NULL;
292         ctx->xml_parser = apr_xml_parser_create(pool);
293         ctx->status = XML_INCOMPLETE;
294     }
295
296     PARSER_STATUS_CHECK(XML);
297
298     for (e = APR_BRIGADE_FIRST(bb); e != APR_BRIGADE_SENTINEL(bb);
299          e = APR_BUCKET_NEXT(e))
300     {
301         const char *data;
302         apr_size_t dlen;
303
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;
308                 if (hook->next)
309                     s = apreq_hook_run(hook->next, param, bb);
310             }
311             else {
312                 ctx->status = XML_ERROR;
313             }
314            return s;
315         }
316         else if (APR_BUCKET_IS_METADATA(e)) {
317             continue;
318         }
319
320         s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
321
322         if (s != APR_SUCCESS) {
323             ctx->status = XML_ERROR;
324             return s;
325         }
326
327         s = apr_xml_parser_feed(ctx->xml_parser, data, dlen);
328
329         if (s != APR_SUCCESS) {
330             ctx->status = XML_ERROR;
331             return s;
332         }
333
334     }
335
336     if (hook->next)
337         return apreq_hook_run(hook->next, param, bb);
338
339     return APR_SUCCESS;
340 }
341
342
343 APREQ_DECLARE_HOOK(apreq_hook_find_param)
344 {
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);
349
350     if (is_final && s == APR_SUCCESS && ctx->param == NULL
351         && strcasecmp(ctx->name, param->v.name) == 0) {
352         ctx->param = param;
353         ctx->prev->next = hook->next;
354     }
355     return s;
356 }