"Fossies" - the Fresh Open Source Software Archive 
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "mod_parp.c" see the
Fossies "Dox" file reference documentation and the last
Fossies "Diffs" side-by-side code changes report:
0.15-src_vs_0.16-src.
1 /* -*-mode: c; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 * The line above sets XEmacs indention to offset 2,
3 * and does not insert tabs
4 */
5 /* ____ _____ ____ ____
6 * |H _ \(____ |/ ___) _ \
7 * |T|_| / ___ | | | |_| |
8 * |T __/\_____|_| | __/
9 * |P|ParameterParser|_|
10 * http://parp.sourceforge.net
11 *
12 * Copyright (C) 2008-2014 Christian Liesch / Pascal Buchbinder / Lukas Funk
13 *
14 * Licensed to the Apache Software Foundation (ASF) under one or more
15 * contributor license agreements.
16 * The ASF licenses this file to You under the Apache License, Version 2.0
17 * (the "License"); you may not use this file except in compliance with
18 * the License. You may obtain a copy of the License at
19 *
20 * http://www.apache.org/licenses/LICENSE-2.0
21 *
22 * Unless required by applicable law or agreed to in writing, software
23 * distributed under the License is distributed on an "AS IS" BASIS,
24 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25 * See the License for the specific language governing permissions and
26 * limitations under the License.
27 */
28
29 /************************************************************************
30 * Version
31 ***********************************************************************/
32 static const char revision[] = "$Id: mod_parp.c,v 1.46 2016/06/15 15:55:02 lukasfunk Exp $";
33 static const char g_revision[] = "0.16";
34
35 /************************************************************************
36 * Includes
37 ***********************************************************************/
38 /* apache */
39 #include <httpd.h>
40 #include <http_main.h>
41 #include <http_request.h>
42 #include <http_protocol.h>
43 #include <http_config.h>
44 #include <http_log.h>
45
46 /* apr */
47 #include <apr_hooks.h>
48 #include <apr_strings.h>
49 #include <apr_buckets.h>
50 #include <apr_hash.h>
51
52 /* this */
53 #include "mod_parp.h"
54
55 /************************************************************************
56 * defines
57 ***********************************************************************/
58 #define PARP_LOG_PFX(id) "mod_parp("#id"): "
59 #define PARP_DELETE_PARAM "PARP_DELETE_PARAM"
60
61 #define PARP_FLAGS_NONE 0
62 #define PARP_FLAGS_CONT_ON_ERR 1
63 #define PARP_FLAGS_FIRST_PARAM_WRITTEN 2
64
65 #define PARP_ERR_BRIGADE_FULL (APR_OS_START_USERERR + 1)
66
67 /************************************************************************
68 * structures
69 ***********************************************************************/
70 typedef enum {
71 NONE, FORMDATA, MULTIPART
72 } body_content_t;
73
74 typedef enum {
75 QUERY, BODY
76 } parameter_t;
77 /**
78 * parp hook
79 */
80 typedef struct parp_s{
81 apr_pool_t *pool;
82 request_rec *r;
83 apr_bucket_brigade *bb;
84 char *raw_body_data; /** raw data received from the client */
85 apr_size_t raw_body_data_len; /** total length of the raw data (excluding modifications) */
86 int use_raw_body; /** indicates the input filter to read the raw data instead of the bb (body content has changed)*/
87 apr_table_t *params; /** readonly parameter table (query+body) */
88 apr_array_header_t *rw_params; /** writable table of parp_entry_t entries (null if
89 no body or query available or no module has registered) */
90 apr_array_header_t *rw_params_query_structure;
91 apr_array_header_t *rw_params_body_structure;
92
93 body_content_t content_typeclass;
94 apr_table_t *parsers; /** body parser per content type */
95
96 char *error;
97 int flags;
98 int recursion;
99
100 char *data_query;
101 apr_size_t len_query;
102 char *data_body;
103 apr_size_t len_body;
104
105 char *tmp_buffer; /* partial written data */
106 apr_off_t len_tmp_buffer;
107
108 } parp_t;
109
110 typedef struct parp_query_structure_s{
111 int rw_array_index;
112 const char *key;
113 const char *key_addr;
114 const char *value_addr;
115 } parp_query_structure_t;
116
117 typedef struct parp_body_structure_s{
118 int rw_array_index;
119 const char *key; // name attribute in content-disposition
120 const char *key_addr;
121 const char *value_addr; // pointer to the value in the mulitpart body
122
123 const char *multipart_addr; // pointer to the multipart with the start boundary delimiter
124 int mulitpart_nested_header_len; // header length of nested multipart entries
125 int raw_len; // mulitpart part length incl start boundary.
126 int raw_len_modified; // multipart length
127 const char *multipart_boundary; // boundary with starting --
128 apr_array_header_t *multipart_parameters;
129 int multipart_parameters_ndelete; /* the number of parameters to delete in
130 the nested multipart. can be compared to
131 multipart_parameters->nelts so see if the
132 whole multipart must be deleted.*/
133
134 int written_to_brigade;
135 } parp_body_structure_t;
136
137 /**
138 * server configuration
139 */
140 typedef struct parp_srv_config_s{
141 int onerror;
142 apr_table_t *parsers;
143 } parp_srv_config;
144
145 /**
146 * block
147 */
148 typedef struct parp_block_s{
149 apr_size_t len;
150 char *data;
151 char *raw_data;
152 apr_size_t raw_data_len;
153 } parp_block_t;
154
155 /************************************************************************
156 * globals
157 ***********************************************************************/
158 module AP_MODULE_DECLARE_DATA parp_module;
159
160 APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(parp, PARP, apr_status_t, hp_hook,
161 (request_rec *r, apr_table_t *table),
162 (r, table),
163 OK, DECLINED)
164
165 /**
166 * DEPRECATED - only for backwards compatibility - use modify_hook
167 */
168 APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(parp, PARP, apr_status_t, modify_body_hook,
169 (request_rec *r, apr_array_header_t *array),
170 (r, array),
171 OK, DECLINED)
172
173 APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(parp, PARP, apr_status_t, modify_hook,
174 (request_rec *r, apr_array_header_t *array),
175 (r, array),
176 OK, DECLINED)
177 /************************************************************************
178 * functions
179 ***********************************************************************/
180
181 typedef apr_status_t (*parp_parser_f)(parp_t *, parameter_t, apr_table_t *,
182 char *, apr_size_t, apr_array_header_t *);
183
184 static parp_parser_f parp_get_parser(parp_t *self, const char *ct);
185
186 /**
187 * Verifies if we may expext any body request data.
188 */
189 static int parp_has_body(parp_t *self) {
190 request_rec *r = self->r;
191 const char *tenc = apr_table_get(r->headers_in, "Transfer-Encoding");
192 const char *lenp = apr_table_get(r->headers_in, "Content-Length");
193 if (tenc) {
194 if (strcasecmp(tenc, "chunked") == 0) {
195 return 1;
196 }
197 }
198 if (lenp) {
199 char *endstr;
200 apr_off_t remaining;
201 if ((apr_strtoff(&remaining, lenp, &endstr, 10) == APR_SUCCESS)
202 && (remaining > 0)) {
203 return 1;
204 }
205 }
206 return 0;
207 }
208
209 /**
210 * apr_brigade_pflatten() to null terminated string
211 */
212 apr_status_t parp_flatten(apr_bucket_brigade *bb, char **c, apr_size_t *len,
213 apr_pool_t *pool) {
214 apr_off_t actual;
215 apr_size_t total;
216 apr_status_t rv;
217
218 apr_brigade_length(bb, 1, &actual);
219 total = (apr_size_t) actual;
220 *c = apr_palloc(pool, total + 1);
221 rv = apr_brigade_flatten(bb, *c, &total);
222 *len = total;
223 if (rv != APR_SUCCESS) {
224 return rv;
225 }
226 (*c)[total] = '\0';
227 return APR_SUCCESS;
228 }
229
230 /**
231 * Read payload of this request (null terminated)
232 *
233 * @param r IN request record
234 * @param data OUT flatten payload
235 * @param len OUT len of payload
236 *
237 * @return APR_SUCCESS, any apr status code on error
238 */
239 static apr_status_t parp_get_payload(parp_t *self) {
240 char *data;
241 apr_size_t len;
242 apr_status_t status;
243
244 request_rec *r = self->r;
245
246 if ((status = parp_read_payload(r, self->bb, &self->error)) != APR_SUCCESS) {
247 return status;
248 }
249
250 if ((status = parp_flatten(self->bb, &data, &len, self->pool)) != APR_SUCCESS) {
251 self->error = apr_pstrdup(r->pool,
252 "Input filter: apr_brigade_pflatten failed");
253 }
254 else {
255 self->raw_body_data = data;
256 self->raw_body_data_len = len;
257 }
258 return status;
259 }
260
261 /**
262 * read the content type contents
263 *
264 * @param self IN instance
265 * @param headers IN headers
266 * @param result OUT
267 *
268 * @return APR_SUCCESS or APR_EINVAL
269 */
270 static apr_status_t parp_read_header(parp_t *self, const char *header,
271 apr_table_t **result) {
272 char *pair;
273 char *key;
274 char *val;
275 char *last;
276 apr_size_t len;
277
278 apr_table_t *tl = apr_table_make(self->pool, 3);
279
280 *result = tl;
281
282 /* iterate over multipart key/value pairs */
283 pair = apr_strtok(apr_pstrdup(self->pool, header), ";,", &last);
284 if (!pair) {
285 return APR_SUCCESS;
286 }
287 do {
288 /* eat spaces */
289 while (*pair == ' ') {
290 ++pair;
291 }
292 /* get key/value */
293 key = apr_strtok(pair, "=", &val);
294 if (key) {
295 /* strip " away */
296 if (val && val[0] == '"') {
297 ++val;
298 len = strlen(val);
299 if (len > 0) {
300 if (self->rw_params) {
301 /* don't modify the raw data since we still need them */
302 val = apr_pstrndup(self->pool, val, len - 1);
303 }
304 else {
305 val[len - 1] = 0;
306 }
307 }
308 }
309 apr_table_addn(tl, key, val);
310 }
311 }
312 while ((pair = apr_strtok(NULL, ";,", &last)));
313
314 return APR_SUCCESS;
315 }
316
317 /**
318 * read the all boundaries
319 *
320 * @param self IN instance
321 * @param data IN data to parse
322 * @param len IN len of data
323 * @param tag IN boundary tag
324 * @param result OUT table of boundaries
325 *
326 * @return APR_SUCCESS or APR_EINVAL
327 */
328 static apr_status_t parp_read_boundaries(parp_t *self, char *data,
329 apr_size_t len, const char *tag, apr_table_t **result) {
330
331 apr_size_t i;
332 apr_size_t start;
333 apr_size_t match;
334 apr_size_t tag_len;
335 apr_size_t boundary_start;
336 apr_size_t preamble;
337 int incr;
338 apr_table_t *tl;
339 parp_block_t *boundary;
340
341 tl = apr_table_make(self->pool, 5);
342 *result = tl;
343 tag_len = strlen(tag);
344 for (i = 0, match = 0, start = 0, boundary_start = 0, preamble = 1; i < len; i++) {
345 /* test if match complete */
346 if (match == tag_len) {
347 preamble = 0;
348 if (strncmp(&data[i], "\r\n", 2) == 0) {
349 incr = 2;
350 }
351 else if (strncmp(&data[i], "--\r\n", 4) == 0) {
352 incr = 4;
353 }
354 else if (strcmp(&data[i], "--") == 0) {
355 incr = 2;
356 }
357 else if (data[i] == '\n') {
358 incr = 1;
359 }
360 else {
361 match = 0;
362 continue;
363 }
364 /* prepare data finalize string with 0 */
365 //if(self->rw_body_params == NULL) {
366 /* don't modify the raw data since we still need them */
367 //data[i - match] = 0;
368 //}
369
370 /* got it, store it (if>0) */
371 if (data[start] && ((i - match) - start)) {
372 boundary = apr_pcalloc(self->pool, sizeof(*boundary));
373 boundary->len = (i - match) - start;
374 //if(self->rw_body_params) {
375 /* don't modify the raw data since we still need them */
376 //boundary->data = apr_pstrndup(self->pool, &data[start], boundary->len);
377 //} else {
378 boundary->data = &data[start];
379 boundary->raw_data = &data[boundary_start];
380 boundary->raw_data_len = (i - match) - boundary_start;
381 //}
382 apr_table_addn(tl, tag, (char *) boundary);
383 // char* data_cut = apr_pstrmemdup(self->pool, boundary->data, boundary->len);
384 // printf("***\n%s\n***\n", data_cut);
385 // char* multipart = apr_pstrmemdup(self->pool, boundary->raw_data, boundary->raw_data_len);
386 // printf("+++\n%s\n+++\n", multipart);
387
388 boundary_start = (i - match);
389 }
390 i += incr;
391 if (boundary_start <= start) {
392 boundary_start = start;
393 }
394 start = i;
395 }
396 /* pattern matching */
397 if (match < tag_len && data[i] == tag[match]) {
398 ++match;
399 }
400 else {
401 match = 0;
402 if (preamble == 1) {
403 start = boundary_start = i+1;
404 }
405 }
406 }
407
408 return APR_SUCCESS;
409 }
410
411 static char *parp_strtok(apr_pool_t *pool, char *str, const char *sep,
412 char **last) {
413 char *token;
414
415 if (!str) /* subsequent call */
416 str = *last; /* start where we left off */
417
418 /* skip characters in sep (will terminate at '\0') */
419 while (*str && strchr(sep, *str))
420 ++str;
421
422 if (!*str) /* no more tokens */
423 return NULL;
424
425 token = str;
426
427 /* skip valid token characters to terminate token and
428 * prepare for the next call (will terminate at '\0)
429 */
430 *last = token + 1;
431 while (**last && !strchr(sep, **last))
432 ++*last;
433 token = apr_pstrndup(pool, token, *last - token);
434 if (**last) {
435 ++*last;
436 }
437
438 return token;
439 }
440
441 /**
442 * Get headers from data, all lines until first empty line will be
443 * split into header/value stored in the headers table.
444 *
445 * @param self IN instance
446 * @param data IN data
447 * @param len IN len of data
448 * @param headers OUT found headers
449 *
450 * @return APR_SUCCESS or APR_EINVAL
451 */
452 static apr_status_t parp_get_headers(parp_t *self, parp_block_t *b,
453 apr_table_t **headers) {
454 char *last = NULL;
455 char *header = NULL;
456 char *key = NULL;
457 char *val = NULL;
458 char *data = b->data;
459
460 apr_table_t *tl = apr_table_make(self->pool, 3);
461 *headers = tl;
462 header = parp_strtok(self->pool, data, "\r\n", &last);
463 while (header) {
464 key = apr_strtok(header, ":", &val);
465 if (val) {
466 while (*val == ' ')
467 ++val;
468 }
469 apr_table_addn(tl, key, val);
470
471 if (last && (*last == '\n')) {
472 ++last;
473 }
474 /* look if we have a empty line in front (header/body separator)*/
475 if (strncmp(last, "\r\n", 2) == 0) {
476 ++last;
477 break;
478 }
479 header = parp_strtok(self->pool, NULL, "\r\n", &last);
480 }
481 if (last && (*last == '\n')) {
482 ++last;
483 b->len -= last - data;
484 b->data = last;
485 }
486 else {
487 b->len = 0;
488 b->data = NULL;
489 }
490
491 return APR_SUCCESS;
492 }
493
494 /**
495 * Urlencode parser
496 *
497 * @param self IN instance
498 * @param headers IN headers with additional data
499 * @param data IN data with urlencoded content
500 * @param len IN len of data
501 *
502 * @return APR_SUCCESS or APR_EINVAL on parser error
503 *
504 * @note: Get parp_get_error for more detailed report
505 */
506 static apr_status_t parp_parser_urlencode(parp_t *self,
507 parameter_t parameter_type, apr_table_t *headers, const char *data,
508 apr_size_t len, apr_array_header_t *structure_array) {
509 char *key;
510 char *val;
511 char *pair;
512 const char *rest = data;
513
514 if (parameter_type == BODY && self->content_typeclass == NONE) {
515 self->content_typeclass = FORMDATA;
516 }
517 while (rest[0]) {
518 const char *here = rest;
519 pair = ap_getword(self->pool, &rest, '&');
520 /* get key/value */
521 val = pair;
522 key = ap_getword_nc(self->pool, &val, '=');
523 if (key && (key[0] >= ' ')) {
524 /* store it to a table */
525 int val_len = strlen(val);
526 if (val_len >= 2 && strncmp(&val[val_len - 2], "\r\n", 2) == 0) {
527 if (self->rw_params) { // TODO why???
528 val[val_len - 2] = 0;
529 }
530 }
531 else if (val_len >= 1 && val[val_len - 1] == '\n') {
532 val[val_len - 1] = 0;
533 }
534
535 apr_table_addn(self->params, key, val);
536
537 /* store rw ref */
538 if (self->rw_params) {
539 parp_entry_t *entry = apr_array_push(self->rw_params);
540 entry->key = key;
541 entry->value = val;
542 entry->new_value = NULL;
543 entry->delete = 0;
544
545 if (structure_array) {
546 if (parameter_type == QUERY) {
547 parp_query_structure_t *structure = apr_array_push(structure_array);
548 structure->key = key;
549 structure->key_addr = &here[0];
550 structure->value_addr = &here[strlen(key) + 1];
551 structure->rw_array_index = self->rw_params->nelts - 1;
552 }
553 else {
554 parp_body_structure_t *structure = apr_array_push(structure_array);
555 structure->key = key;
556 structure->key_addr = &here[0];
557 structure->value_addr = &here[strlen(key) + 1];
558 structure->rw_array_index = self->rw_params->nelts - 1;
559 structure->multipart_parameters = NULL;
560 structure->multipart_addr = NULL;
561 structure->raw_len = strlen(key) + 1 + strlen(val);
562 structure->raw_len_modified = structure->raw_len;
563 structure->multipart_parameters_ndelete = 0;
564 structure->written_to_brigade = 0;
565 }
566 }
567 }
568 }
569 }
570
571 return APR_SUCCESS;
572 }
573
574 /**
575 * Multipart parser
576 *
577 * @param self IN instance
578 * @param headers IN headers with additional data
579 * @param data IN data
580 * @param len IN len of data
581 *
582 * @return APR_SUCCESS or APR_EINVAL on parser error
583 *
584 * @note: Get parp_get_error for more detailed report
585 */
586 static apr_status_t parp_parser_multipart(parp_t *self,
587 parameter_t parameter_type, apr_table_t *headers, char *data,
588 apr_size_t len, apr_array_header_t* structure_array) {
589 apr_status_t status;
590 apr_size_t val_len;
591 const char *boundary;
592 apr_table_t *ctt;
593 apr_table_t *bs;
594 apr_table_t *ctds;
595 apr_table_entry_t *e;
596 int i;
597 const char *ctd;
598 const char *ct;
599 const char *key;
600 parp_parser_f parser;
601 parp_block_t *b;
602 apr_table_t *hs = apr_table_make(self->pool, 3);
603 if (self->recursion > 3) {
604 self->error = apr_pstrdup(self->pool, "Too deep recursion of multiparts");
605 return APR_EINVAL;
606 }
607 if (self->content_typeclass == NONE) {
608 self->content_typeclass = MULTIPART;
609 }
610
611 ++self->recursion;
612
613 ct = apr_table_get(headers, "Content-Type");
614 if (ct == NULL) {
615 self->error = apr_pstrdup(self->pool, "No content type available");
616 return APR_EINVAL;
617 }
618
619 if ((status = parp_read_header(self, ct, &ctt)) != APR_SUCCESS) {
620 return status;
621 }
622
623 if (!(boundary = apr_table_get(ctt, "boundary"))) {
624 return APR_EINVAL;
625 }
626
627 /* prefix boundary wiht a -- */
628 boundary = apr_pstrcat(self->pool, "--", boundary, NULL);
629
630 parp_body_structure_t* body_structure = NULL;
631 parp_body_structure_t* body_block_structure = NULL;
632 if (structure_array != NULL && self->recursion == 1) {
633 body_structure = apr_array_push(structure_array);
634 body_structure->rw_array_index = -1;
635 body_structure->multipart_addr = data;
636 body_structure->mulitpart_nested_header_len = 0;
637 body_structure->raw_len = len;
638 body_structure->raw_len_modified = len;
639 body_structure->multipart_parameters = apr_array_make(self->pool, 50,
640 sizeof(parp_body_structure_t));
641 body_structure->multipart_parameters_ndelete = 0;
642 body_structure->multipart_boundary = apr_pstrndup(self->pool, boundary,
643 strlen(boundary));
644 body_structure->written_to_brigade = 0;
645 }
646
647 if ((status = parp_read_boundaries(self, data, len, boundary, &bs))
648 != APR_SUCCESS) {
649 self->error = apr_pstrdup(self->pool, "failed to read boundaries");
650 return status;
651 }
652
653 // get boundaries elements
654 e = (apr_table_entry_t *) apr_table_elts(bs)->elts;
655
656 // remove pre- and postamble from the multipart structure if exists...
657 if (body_structure != NULL && apr_table_elts(bs)->nelts > 0) {
658 // first boundary
659 b = (parp_block_t *) e[0].val;
660 body_structure->multipart_addr = b->raw_data;
661 //last boundary
662 b = (parp_block_t *) e[apr_table_elts(bs)->nelts - 1].val;
663 char *multipart_end = b->raw_data;
664 multipart_end += b->raw_data_len;
665 int data_len_remaining = len - (multipart_end - data);
666 int match;
667 int boundary_len = strlen(boundary);
668 for (i = 0, match = 0; i < data_len_remaining; ++i) {
669
670 if (match == boundary_len) {
671 if (strncmp(&multipart_end[i], "--\r\n", 4) == 0) {
672 i += 4;
673 }
674 else if (strcmp(&multipart_end[i], "--") == 0) {
675 i += 2;
676 }
677 else {
678 // should not happen as it need to be the last boundary
679 break;
680 }
681 multipart_end += i;
682 body_structure->raw_len = multipart_end - body_structure->multipart_addr;
683 body_structure->raw_len_modified = body_structure->raw_len;
684 break;
685 }
686 /* pattern matching */
687 if (match < boundary_len && multipart_end[i] == boundary[match]) {
688 ++match;
689 }
690 else {
691 match = 0;
692 }
693 }
694 }
695
696
697 /* iterate over boundaries and store their param/value pairs */
698 for (i = 0; i < apr_table_elts(bs)->nelts; ++i) {
699 /* read boundary headers */
700 b = (parp_block_t *) e[i].val;
701
702 if (body_structure != NULL) {
703 body_block_structure = apr_array_push(
704 body_structure->multipart_parameters);
705 body_block_structure->multipart_addr = b->raw_data;
706 body_block_structure->raw_len = b->raw_data_len;
707 body_block_structure->raw_len_modified = b->raw_data_len;
708 body_block_structure->written_to_brigade = 0;
709 } else if (structure_array != NULL) {
710 body_block_structure = apr_array_push(
711 structure_array);
712 body_block_structure->multipart_addr = b->raw_data;
713 body_block_structure->raw_len = b->raw_data_len;
714 body_block_structure->raw_len_modified = b->raw_data_len;
715 body_block_structure->written_to_brigade = 0;
716 }
717
718 if ((status = parp_get_headers(self, b, &hs)) != APR_SUCCESS) {
719 self->error = apr_pstrdup(self->pool,
720 "failed to read headers within boundary");
721 return status;
722 }
723
724 if ((ct = apr_table_get(hs, "Content-Type")) && apr_strnatcasecmp(ct,
725 "text/plain") != 0) {
726 parser = parp_get_parser(self, ct);
727
728 if (parser == parp_parser_multipart) {
729 if (body_block_structure != NULL) {
730 int nested_mulitpart_header_len = b->data - b->raw_data;
731 body_block_structure->mulitpart_nested_header_len =
732 (nested_mulitpart_header_len > 0 ? nested_mulitpart_header_len : 0);
733 body_block_structure->multipart_parameters = apr_array_make(self->pool,
734 50, sizeof(parp_body_structure_t));
735 body_block_structure->rw_array_index = -1;
736 body_block_structure->multipart_parameters_ndelete = 0;
737 status = parser(self, parameter_type, hs, b->data, b->len,
738 body_block_structure->multipart_parameters);
739 } else {
740 status = parser(self, parameter_type, hs, b->data, b->len, NULL);
741 }
742 }
743 else {
744 status = parser(self, parameter_type, hs, b->data, b->len, NULL);
745 }
746 if (status != APR_SUCCESS && status != APR_ENOTIMPL) {
747 return status;
748 }
749 }
750
751 if (!(ctd = apr_table_get(hs, "Content-Disposition"))) {
752 self->error = apr_pstrdup(self->pool,
753 "failed to read content disposition");
754 return APR_EINVAL;
755 }
756
757 if ((status = parp_read_header(self, ctd, &ctds)) != APR_SUCCESS) {
758 return status;
759 }
760
761 /* skip all parts with top-level content-type "multipart" */
762 char *tlct = apr_pstrndup(self->pool, ct, sizeof "multipart" - 1);
763 if (!ct || apr_strnatcasecmp(tlct, "multipart")) {
764 char *val = b->data;
765 if ((key = apr_table_get(ctds, "name")) == NULL) {
766 return APR_EINVAL;
767 }
768 val_len = b->len;
769 /* there must be a \r\n or at least a \n */
770 if (val_len >= 2 && strncmp(&val[val_len - 2], "\r\n", 2) == 0) {
771 if (self->rw_params) {
772 /* don't modify the raw data since we still need them */
773 val = apr_pstrndup(self->pool, val, val_len - 2);
774 }
775 else {
776 val[val_len - 2] = 0;
777 }
778 }
779 else if (val_len >= 1 && val[val_len - 1] == '\n') {
780 if (self->rw_params) {
781 /* don't modify the raw data since we still need them */
782 val = apr_pstrndup(self->pool, val, val_len - 1);
783 }
784 else {
785 val[val_len - 1] = 0;
786 }
787 }
788 else {
789 return APR_EINVAL;
790 }
791
792 apr_table_addn(self->params, key, val);
793
794 if (self->rw_params) {
795 parp_entry_t *entry = apr_array_push(self->rw_params);
796 entry->key = key;
797 entry->value = val;
798 entry->new_value = NULL;
799 entry->delete = 0;
800
801 if (body_block_structure != NULL) {
802 body_block_structure->key = key;
803 body_block_structure->key_addr = b->raw_data;
804 body_block_structure->value_addr = b->data;
805 body_block_structure->rw_array_index = self->rw_params->nelts - 1;
806 body_block_structure->written_to_brigade = 0;
807 }
808 }
809 }
810 }
811 /* now do all boundaries */
812 --self->recursion;
813 return APR_SUCCESS;
814 }
815
816 /**
817 * Not implemented parser used if there is no corresponding parser found
818 *
819 * @param self IN instance
820 * @param headers IN headers with additional data
821 * @param data IN data with urlencoded content
822 * @param len IN len of data
823 *
824 * @return APR_ENOTIMPL
825 */
826 static apr_status_t parp_parser_not_impl(parp_t *self,
827 parameter_t parameter_type, apr_table_t *headers, char *data,
828 apr_size_t len, apr_array_header_t* structure_array) {
829 return APR_ENOTIMPL;
830 }
831
832 /**
833 * To get body data from a content type not parsed
834 *
835 * @param self IN instance
836 * @param headers IN headers with additional data
837 * @param data IN data with urlencoded content
838 * @param len IN len of data
839 *
840 * @return APR_SUCCESS
841 */
842 static apr_status_t parp_parser_get_body(parp_t *self,
843 parameter_t parameter_type, apr_table_t *headers, char *data,
844 apr_size_t len, apr_array_header_t* structure_array) {
845 self->data_body = data;
846 self->len_body = len;
847 return APR_SUCCESS;
848 }
849
850 /**
851 * Get content type parser
852 *
853 * @param self IN instance
854 * @param ct IN content type (or NULL)
855 *
856 * @return content type parser
857 */
858 static parp_parser_f parp_get_parser(parp_t *self, const char *ct) {
859 const char *type;
860 char *last;
861
862 parp_parser_f parser = NULL;
863 parp_srv_config *sconf = ap_get_module_config(self->r->server->module_config,
864 &parp_module);
865
866 if (ct) {
867 type = apr_strtok(apr_pstrdup(self->pool, ct), ";,", &last);
868 if (type) {
869 if (sconf->parsers) {
870 parser = (parp_parser_f) apr_table_get(sconf->parsers, type);
871 }
872 if (!parser) {
873 parser = (parp_parser_f) apr_table_get(self->parsers, type);
874 }
875 if(!parser) {
876 if (sconf->parsers)
877 parser = (parp_parser_f) apr_table_get(sconf->parsers, "*/*");
878 }
879 if(!parser) {
880 parser = (parp_parser_f) apr_table_get(self->parsers, "*/*");
881 }
882 }
883 }
884 if (parser) {
885 return parser;
886 }
887 self->error = apr_psprintf(self->pool,
888 "No parser available for this content type (%s)",
889 ct == NULL ? "-" : ct);
890 return parp_parser_not_impl;
891 }
892
893 /**************************************************************************
894 * Public
895 **************************************************************************/
896
897 /**
898 * Read payload of this request
899 *
900 * @param r IN request record
901 * @param out IN bucket brigade to fill
902 * @param error OUT error text if status != APR_SUCCESS
903 *
904 * @return APR_SUCCESS, any apr status code on error
905 */
906 AP_DECLARE(apr_status_t ) parp_read_payload(request_rec *r,
907 apr_bucket_brigade *out, char **error) {
908 apr_status_t status;
909 apr_bucket_brigade *bb;
910 apr_bucket *b;
911 const char *buf;
912 apr_size_t len;
913 apr_off_t off;
914 const char *enc;
915 const char *len_str;
916
917 int seen_eos = 0;
918
919 if ((status = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)) != OK) {
920 *error = apr_pstrdup(r->pool, "ap_setup_client_block failed");
921 return status;
922 }
923
924 bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
925
926 do {
927 status = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES,
928 APR_BLOCK_READ, HUGE_STRING_LEN);
929
930 if (status == APR_SUCCESS) {
931 while (!APR_BRIGADE_EMPTY(bb)) {
932 b = APR_BRIGADE_FIRST(bb);
933 APR_BUCKET_REMOVE(b);
934
935 if (APR_BUCKET_IS_EOS(b)) {
936 seen_eos = 1;
937 APR_BRIGADE_INSERT_TAIL(out, b);
938 }
939 else if (APR_BUCKET_IS_FLUSH(b)) {
940 APR_BRIGADE_INSERT_TAIL(out, b);
941 }
942 else {
943 status = apr_bucket_read(b, &buf, &len, APR_BLOCK_READ);
944 if (status != APR_SUCCESS) {
945 *error = apr_pstrdup(r->pool, "Input filter: Failed reading input");
946 return status;
947 }
948 apr_brigade_write(out, NULL, NULL, buf, len);
949 apr_bucket_destroy(b);
950 }
951 }
952 apr_brigade_cleanup(bb);
953 }
954 else {
955 /* we expext a bb (even it might be empty)!
956 client may have closed the connection?
957 or any other filter in the chain has canceled the request? */
958 char buf[MAX_STRING_LEN];
959 buf[0] = '\0';
960 if (status > 0) {
961 apr_strerror(status, buf, sizeof(buf));
962 }
963 *error = apr_psprintf(r->pool,
964 "Input filter: Failed reading data from client."
965 " Blocked by another filter in chain? [%s]", buf);
966 seen_eos = 1;
967 }
968 }
969 while (!seen_eos);
970
971 apr_brigade_length(out, 1, &off);
972
973 /* correct content-length header if deflate filter runs before */
974 enc = apr_table_get(r->headers_in, "Transfer-Encoding");
975 if (!enc || strcasecmp(enc, "chunked") != 0) {
976 len_str = apr_off_t_toa(r->pool, off);
977 apr_table_set(r->headers_in, "Content-Length", len_str);
978 r->remaining = off;
979 }
980
981 return status;
982 }
983
984 /**
985 * Creates a new parameter parser.
986 *
987 * @param r IN request record
988 *
989 * @return new parameter parser instance
990 */
991 AP_DECLARE(parp_t *) parp_new(request_rec *r, int flags) {
992 parp_t *self = apr_pcalloc(r->pool, sizeof(parp_t));
993
994 self->pool = r->pool;
995 self->r = r;
996 self->bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
997 self->params = apr_table_make(r->pool, 5);
998 self->rw_params = NULL;
999 self->rw_params_query_structure = NULL;
1000 self->rw_params_body_structure = NULL;
1001 self->parsers = apr_table_make(r->pool, 3);
1002 apr_table_setn(self->parsers, apr_pstrdup(r->pool,
1003 "application/x-www-form-urlencoded"), (char *) parp_parser_urlencode);
1004 apr_table_setn(self->parsers, apr_pstrdup(r->pool, "multipart/form-data"),
1005 (char *) parp_parser_multipart);
1006 apr_table_setn(self->parsers, apr_pstrdup(r->pool, "multipart/mixed"),
1007 (char *) parp_parser_multipart);
1008 self->flags = flags;
1009
1010 self->raw_body_data = NULL;
1011 self->raw_body_data_len = 0;
1012 self->use_raw_body = 0;
1013
1014 self->content_typeclass = NONE;
1015
1016 self->data_body = NULL;
1017 self->len_body = 0;
1018
1019 self->recursion = 0;
1020
1021 self->tmp_buffer = NULL;
1022 self->len_tmp_buffer = 0;
1023
1024 return self;
1025 }
1026
1027 /**
1028 * Get all parameter/value pairs in this request
1029 *
1030 * @param self IN instance
1031 * @param params OUT table of key/value pairs
1032 *
1033 * @return APR_SUCCESS or APR_EINVAL on parser errors
1034 *
1035 * @note: see parap_error(self) for detailed error message
1036 */
1037 AP_DECLARE(apr_status_t) parp_read_params(parp_t *self) {
1038 apr_status_t status;
1039 parp_parser_f parser;
1040 request_rec *r = self->r;
1041 int modify = 0;
1042 apr_array_header_t *hs = apr_optional_hook_get("modify_body_hook"); // only for backwards compatibility
1043 apr_array_header_t *hs2 = apr_optional_hook_get("modify_hook");
1044 if (((hs != NULL) && (hs->nelts > 0)) || ((hs2 != NULL) && (hs2->nelts > 0))) {
1045 /* module has registered */
1046 self->rw_params = apr_array_make(r->pool, 50, sizeof(parp_entry_t));
1047 modify = 1;
1048 }
1049 if (r->args) { // read query parameters
1050 if (modify == 1) {
1051 self->rw_params_query_structure = apr_array_make(r->pool, 50,
1052 sizeof(parp_query_structure_t));
1053 }
1054 if ((status = parp_parser_urlencode(self, QUERY, r->headers_in, r->args,
1055 strlen(r->args), self->rw_params_query_structure))
1056 != APR_SUCCESS) {
1057 return status;
1058 }
1059
1060 }
1061 if (parp_has_body(self)) {
1062 if (modify == 1) {
1063 self->rw_params_body_structure = apr_array_make(r->pool, 50,
1064 sizeof(parp_body_structure_t));
1065 }
1066 if ((status = parp_get_payload(self)) != APR_SUCCESS) {
1067 return status;
1068 }
1069 parser
1070 = parp_get_parser(self, apr_table_get(r->headers_in, "Content-Type"));
1071 if ((status = parser(self, BODY, r->headers_in, self->raw_body_data,
1072 self->raw_body_data_len, self->rw_params_body_structure))
1073 != APR_SUCCESS) {
1074 /* only set data to self pointer if untouched by parser,
1075 * because parser could modify body data */
1076 if (status == APR_ENOTIMPL) {
1077 }
1078 return status;
1079 }
1080 }
1081 return APR_SUCCESS;
1082 }
1083
1084
1085 AP_DECLARE (apr_status_t) parp_write_nested_multipart(parp_t *self,
1086 apr_bucket_brigade * bb, apr_off_t* freebytes, parp_body_structure_t *multipart) {
1087
1088 int i;
1089 apr_status_t rv;
1090 parp_entry_t *rw_entries = (parp_entry_t *) self->rw_params->elts;
1091
1092
1093 if (multipart->multipart_parameters && multipart->multipart_parameters->nelts == multipart->multipart_parameters_ndelete) { // all multipart elements are deleted
1094 self->raw_body_data = &self->raw_body_data[multipart->raw_len];
1095 self->raw_body_data_len -= multipart->raw_len;
1096 multipart->written_to_brigade = 1;
1097 } else {
1098
1099 // writing nested mulitpart header
1100 if (*freebytes >= multipart->mulitpart_nested_header_len) {
1101 if ((rv = apr_brigade_write(bb, NULL, NULL, self->raw_body_data, multipart->mulitpart_nested_header_len)) != APR_SUCCESS) { return rv;}
1102 self->raw_body_data_len -= multipart->mulitpart_nested_header_len;
1103 self->raw_body_data = &self->raw_body_data[multipart->mulitpart_nested_header_len];
1104 *freebytes -= multipart->mulitpart_nested_header_len;
1105 } else {
1106 return PARP_ERR_BRIGADE_FULL;
1107 }
1108
1109 // writing elements
1110 parp_body_structure_t *multipart_param_entries =
1111 (parp_body_structure_t *) multipart->multipart_parameters->elts;
1112 for (i = 0; i < multipart->multipart_parameters->nelts; ++i) {
1113 parp_body_structure_t *mp = &multipart_param_entries[i];
1114 if (mp->rw_array_index >= 0 && mp->rw_array_index < self->rw_params->nelts && mp->written_to_brigade == 0) {
1115 parp_entry_t *e = &rw_entries[mp->rw_array_index];
1116 if (e->delete != 0) { // delete
1117 self->raw_body_data = &self->raw_body_data[mp->raw_len];
1118 self->raw_body_data_len -= mp->raw_len;
1119 mp->written_to_brigade = 1;
1120 } else if (e->new_value != NULL) { // new value
1121 if (*freebytes >= mp->raw_len_modified) {
1122 int key_len = mp->value_addr-mp->key_addr;
1123 if ((rv = apr_brigade_write(bb, NULL, NULL, self->raw_body_data, key_len)) != APR_SUCCESS) { return rv;}
1124 self->raw_body_data_len -= key_len;
1125 self->raw_body_data = &self->raw_body_data[key_len];
1126
1127 // remove old value fom raw_body_data
1128 self->raw_body_data = &self->raw_body_data[strlen(e->value)];
1129 self->raw_body_data_len -= strlen(e->value);
1130 // write new value
1131 if ((rv = apr_brigade_write(bb, NULL, NULL, e->new_value, strlen(e->new_value))) != APR_SUCCESS) { return rv;}
1132 // write rest of multipartdata
1133 int rest_len = &mp->multipart_addr[mp->raw_len] - self->raw_body_data;
1134 if ((rv = apr_brigade_write(bb, NULL, NULL, self->raw_body_data, rest_len)) != APR_SUCCESS) { return rv;}
1135 self->raw_body_data_len -= rest_len;
1136 self->raw_body_data = &self->raw_body_data[rest_len];
1137 *freebytes -= mp->raw_len_modified;
1138 mp->written_to_brigade = 1;
1139 } else {
1140 return PARP_ERR_BRIGADE_FULL;
1141 }
1142 } else { // no changes
1143 if (*freebytes >= mp->raw_len) {
1144 if ((rv = apr_brigade_write(bb, NULL, NULL, self->raw_body_data, mp->raw_len)) != APR_SUCCESS) { return rv;}
1145 self->raw_body_data = &self->raw_body_data[mp->raw_len];
1146 self->raw_body_data_len -= mp->raw_len;
1147 *freebytes -= mp->raw_len;
1148 mp->written_to_brigade = 1;
1149 } else {
1150 return PARP_ERR_BRIGADE_FULL;
1151 }
1152 }
1153
1154 } else if (mp->multipart_parameters->nelts > 0 && mp->rw_array_index < 0) { // nested multipart
1155 if ((rv = parp_write_nested_multipart(self, bb, freebytes, mp)) != APR_SUCCESS) {
1156 return rv;
1157 }
1158 }
1159 }
1160 // writing end boundary
1161 int rest_len = &multipart->multipart_addr[multipart->raw_len] - self->raw_body_data;
1162 if (rest_len > 0) {
1163 if (*freebytes >= rest_len) {
1164 if ((rv = apr_brigade_write(bb, NULL, NULL, self->raw_body_data, rest_len)) != APR_SUCCESS) { return rv;}
1165 self->raw_body_data = &self->raw_body_data[rest_len];
1166 self->raw_body_data_len -= rest_len;
1167 multipart->written_to_brigade = 1;
1168 *freebytes -= rest_len;
1169 } else {
1170 return PARP_ERR_BRIGADE_FULL;
1171 }
1172 }
1173
1174
1175 }
1176 return APR_SUCCESS;
1177 }
1178
1179 /**
1180 * Forward all data back to request.
1181 *
1182 * @param f IN filter
1183 * @param bb IN bucket brigade
1184 * @param mode IN
1185 * @param block IN block mode
1186 * @param nbytes IN requested bytes
1187 *
1188 * @return any apr status
1189 */
1190 AP_DECLARE (apr_status_t) parp_forward_filter(ap_filter_t * f,
1191 apr_bucket_brigade * bb, ap_input_mode_t mode, apr_read_type_e block,
1192 apr_off_t nbytes) {
1193
1194 int i;
1195 apr_status_t rv;
1196 apr_bucket *e;
1197 apr_size_t len;
1198 const char *buf;
1199 apr_off_t read = 0;
1200 parp_t *self = f->ctx;
1201
1202 if (self == NULL || (f->r && f->r->status != 200)) {
1203 /* nothing to do ... */
1204 return ap_get_brigade(f->next, bb, mode, block, nbytes);
1205 }
1206
1207 if (self->use_raw_body) {
1208 parp_entry_t *rw_entries = (parp_entry_t *) self->rw_params->elts;
1209 /* forward data from the raw buffer and apply modifications */
1210 apr_off_t bytes = nbytes <= self->raw_body_data_len ? nbytes : self->raw_body_data_len;
1211 apr_off_t freebytes = nbytes;
1212
1213 if (self->content_typeclass == FORMDATA) {
1214
1215 parp_body_structure_t *body_structure_entries =
1216 (parp_body_structure_t *) self->rw_params_body_structure->elts;
1217
1218 if(self->len_tmp_buffer > 0) {
1219 // we still have some data left from the last filter call
1220 apr_off_t toSend = self->len_tmp_buffer;
1221 if(toSend > freebytes) {
1222 toSend = freebytes;
1223 }
1224 self->len_tmp_buffer -= toSend;
1225 if ((rv = apr_brigade_write(bb, NULL, NULL, self->tmp_buffer, toSend)) != APR_SUCCESS) {
1226 return rv;
1227 }
1228 self->tmp_buffer += toSend;
1229 freebytes -= toSend;
1230 if(self->len_tmp_buffer > 0) {
1231 // still not done...
1232 return APR_SUCCESS;
1233 }
1234 };
1235
1236 for (i = 0; i < self->rw_params_body_structure->nelts; ++i) {
1237 parp_body_structure_t *bs = &body_structure_entries[i];
1238
1239 if (bs->rw_array_index >= 0 && bs->rw_array_index < self->rw_params->nelts
1240 && bs->written_to_brigade == 0) {
1241 parp_entry_t *e = &rw_entries[bs->rw_array_index];
1242 char *tmp_param = NULL;
1243 if (e->new_value != NULL) {
1244 tmp_param = apr_pstrcat(self->pool, e->key, "=", e->new_value, NULL);
1245 } else if (e->delete == 0) { // value has not changed and is not delete
1246 tmp_param = apr_pstrcat(self->pool, e->key, "=", e->value, NULL);
1247 }
1248 if (tmp_param != NULL) {
1249 if (self->flags & PARP_FLAGS_FIRST_PARAM_WRITTEN) {
1250 tmp_param = apr_pstrcat(self->pool, "&", tmp_param, NULL);
1251 } else {
1252 self->flags |= PARP_FLAGS_FIRST_PARAM_WRITTEN;
1253 }
1254 apr_off_t slen = strlen(tmp_param);
1255 if (freebytes >= slen) { // enough space in brigade
1256 if ((rv = apr_brigade_write(bb, NULL, NULL, tmp_param, slen)) != APR_SUCCESS) {
1257 return rv;
1258 }
1259 bs->written_to_brigade = 1;
1260 freebytes -= slen;
1261 self->raw_body_data = &self->raw_body_data[bs->raw_len];
1262 self->raw_body_data_len -= bs->raw_len;
1263 if (self->raw_body_data[0] == '&') {
1264 self->raw_body_data++;
1265 self->raw_body_data_len--;
1266 }
1267 } else {
1268 // not enough space in brigade, write as much as we can
1269 // ans store the remaining data...
1270 if ((rv = apr_brigade_write(bb, NULL, NULL, tmp_param, freebytes)) != APR_SUCCESS) {
1271 return rv;
1272 }
1273 slen -= freebytes;
1274 self->len_tmp_buffer = slen;
1275 self->tmp_buffer = &tmp_param[freebytes];
1276 bs->written_to_brigade = 1;
1277 self->raw_body_data = &self->raw_body_data[bs->raw_len];
1278 self->raw_body_data_len -= bs->raw_len;
1279 if (self->raw_body_data[0] == '&') {
1280 self->raw_body_data++;
1281 self->raw_body_data_len--;
1282 }
1283 freebytes = 0;
1284 // ...and process further in the next round
1285 return APR_SUCCESS;
1286 //break;
1287 }
1288
1289 } else {
1290 bs->written_to_brigade = 1;
1291 self->raw_body_data = &self->raw_body_data[bs->raw_len];
1292 self->raw_body_data_len -= bs->raw_len;
1293 if (self->raw_body_data[0] == '&') {
1294 self->raw_body_data++;
1295 self->raw_body_data_len--;
1296 }
1297 }
1298 }
1299 }
1300 if (i == self->rw_params_body_structure->nelts) { // all parameters written, clean raw_body_data up
1301 if (self->raw_body_data_len > 0) {
1302 if (freebytes >= self->raw_body_data_len) {
1303 rv = apr_brigade_write(bb, NULL, NULL, self->raw_body_data, self->raw_body_data_len);
1304 freebytes -= self->raw_body_data_len;
1305 self->raw_body_data = &self->raw_body_data[self->raw_body_data_len];
1306 self->raw_body_data_len = 0;
1307 } else {
1308 rv = apr_brigade_write(bb, NULL, NULL, self->raw_body_data, freebytes);
1309 freebytes = 0;
1310 self->raw_body_data = &self->raw_body_data[freebytes];
1311 self->raw_body_data_len -= freebytes;
1312 }
1313 }
1314 }
1315 } else if (self->content_typeclass == MULTIPART) {
1316
1317 parp_body_structure_t *body_structure_entries =
1318 (parp_body_structure_t *) self->rw_params_body_structure->elts;
1319
1320 if(self->len_tmp_buffer > 0) {
1321 // we still have some data left from the last filter call
1322 apr_off_t toSend = self->len_tmp_buffer;
1323 if(toSend > freebytes) {
1324 toSend = freebytes;
1325 }
1326 self->len_tmp_buffer -= toSend;
1327 if ((rv = apr_brigade_write(bb, NULL, NULL, self->tmp_buffer, toSend)) != APR_SUCCESS) { return rv;}
1328 self->tmp_buffer += toSend;
1329 freebytes -= toSend;
1330 if(self->len_tmp_buffer > 0) {
1331 // still not done...
1332 return APR_SUCCESS;
1333 }
1334 };
1335
1336 for (i = 0; i < self->rw_params_body_structure->nelts; ++i) {
1337 parp_body_structure_t *bs = &body_structure_entries[i];
1338
1339 // write preamble if exist
1340 bytes = bs->multipart_addr - self->raw_body_data;
1341 if (bytes > 0) {
1342 if (freebytes >= bytes) {
1343 rv = apr_brigade_write(bb, NULL, NULL, self->raw_body_data, bytes);
1344 self->raw_body_data = &self->raw_body_data[bytes];
1345 self->raw_body_data_len -= bytes;
1346 freebytes -= bytes;
1347 } else {
1348 rv = apr_brigade_write(bb, NULL, NULL, self->raw_body_data, freebytes);
1349 self->raw_body_data = &self->raw_body_data[freebytes];
1350 self->raw_body_data_len -= freebytes;
1351 freebytes = 0;
1352 break;
1353 }
1354 }
1355 if (bs->written_to_brigade == 0) {
1356 if (bs->multipart_parameters && bs->multipart_parameters->nelts == bs->multipart_parameters_ndelete) { // all multipart elements are deleted
1357 self->raw_body_data = &self->raw_body_data[bs->raw_len];
1358 self->raw_body_data_len -= bs->raw_len;
1359 bs->written_to_brigade = 1;
1360 } else {
1361 parp_body_structure_t *multipart_param_entries =
1362 (parp_body_structure_t *) bs->multipart_parameters->elts;
1363 for (i = 0; i < bs->multipart_parameters->nelts; ++i) {
1364 parp_body_structure_t *mp = &multipart_param_entries[i];
1365 if (mp->written_to_brigade == 0) {
1366 if (mp->rw_array_index >= 0 && mp->rw_array_index < self->rw_params->nelts) {
1367 parp_entry_t *e = &rw_entries[mp->rw_array_index];
1368 if (e->delete != 0) { // delete
1369 self->raw_body_data = &self->raw_body_data[mp->raw_len];
1370 self->raw_body_data_len -= mp->raw_len;
1371 mp->written_to_brigade = 1;
1372 } else if (e->new_value != NULL) { // new value
1373
1374 if (freebytes >= mp->raw_len_modified) {
1375 int key_len = mp->value_addr - mp->key_addr;
1376
1377 if ((rv = apr_brigade_write(bb, NULL, NULL, self->raw_body_data, key_len)) != APR_SUCCESS) { return rv;}
1378 self->raw_body_data_len -= key_len;
1379 self->raw_body_data = &self->raw_body_data[key_len];
1380
1381 // remove old value fom raw_body_data
1382 self->raw_body_data = &self->raw_body_data[strlen(e->value)];
1383 self->raw_body_data_len -= strlen(e->value);
1384 // write new value
1385 if ((rv = apr_brigade_write(bb, NULL, NULL, e->new_value, strlen(e->new_value))) != APR_SUCCESS) { return rv;}
1386 // write rest of multipartdata
1387 int rest_len = &mp->multipart_addr[mp->raw_len] - self->raw_body_data;
1388 if ((rv = apr_brigade_write(bb, NULL, NULL, self->raw_body_data, rest_len)) != APR_SUCCESS) { return rv;}
1389 self->raw_body_data_len -= rest_len;
1390 self->raw_body_data = &self->raw_body_data[rest_len];
1391 mp->written_to_brigade = 1;
1392 } else {
1393 return APR_SUCCESS;
1394 }
1395 } else { // no changes
1396 if (freebytes >= mp->raw_len) {
1397 if ((rv = apr_brigade_write(bb, NULL, NULL, self->raw_body_data, mp->raw_len)) != APR_SUCCESS) { return rv;}
1398 self->raw_body_data = &self->raw_body_data[mp->raw_len];
1399 self->raw_body_data_len -= mp->raw_len;
1400 mp->written_to_brigade = 1;
1401 } else {
1402 self->tmp_buffer = self->raw_body_data;
1403 self->len_tmp_buffer = mp->raw_len;
1404 self->raw_body_data += mp->raw_len;
1405 self->raw_body_data_len -= mp->raw_len;
1406 mp->written_to_brigade = 1;
1407 if ((rv = apr_brigade_write(bb, NULL, NULL, self->tmp_buffer, freebytes)) != APR_SUCCESS) { return rv;}
1408 self->len_tmp_buffer -= freebytes;
1409 self->tmp_buffer += freebytes;
1410 return APR_SUCCESS;
1411 }
1412 }
1413
1414 } else if (mp->multipart_parameters && mp->multipart_parameters->nelts > 0 && mp->rw_array_index < 0) { // nested multipart
1415 rv = parp_write_nested_multipart(self, bb, &freebytes, mp);
1416 if (rv == PARP_ERR_BRIGADE_FULL) {
1417 return APR_SUCCESS;
1418 } else if (rv != APR_SUCCESS) {
1419 return rv;
1420 }
1421 mp->written_to_brigade = 1;
1422 }
1423 }
1424 }
1425 bs->written_to_brigade = 1;
1426 }
1427 }
1428 // write postamble if exist
1429 if (self->raw_body_data_len > 0) {
1430 if (freebytes >= self->raw_body_data_len) {
1431 rv = apr_brigade_write(bb, NULL, NULL, self->raw_body_data, self->raw_body_data_len);
1432 freebytes -= self->raw_body_data_len;
1433 self->raw_body_data = &self->raw_body_data[self->raw_body_data_len];
1434 self->raw_body_data_len = 0;
1435 } else {
1436 rv = apr_brigade_write(bb, NULL, NULL, self->raw_body_data, freebytes);
1437 freebytes = 0;
1438 self->raw_body_data = &self->raw_body_data[freebytes];
1439 self->raw_body_data_len -= freebytes;
1440 }
1441 }
1442 }
1443 }
1444
1445 if (self->raw_body_data_len == 0) {
1446 ap_remove_input_filter(f);
1447 }
1448 }
1449 else {
1450 /* transparent forwarding */
1451 /* do never send a bigger brigade than request with "nbytes"! */
1452 while (read < nbytes && !APR_BRIGADE_EMPTY(self->bb)) {
1453 e = APR_BRIGADE_FIRST(self->bb);
1454 rv = apr_bucket_read(e, &buf, &len, block);
1455 if (rv != APR_SUCCESS) {
1456 return rv;
1457 }
1458 if (len + read > nbytes) {
1459 apr_bucket_split(e, nbytes - read);
1460 APR_BUCKET_REMOVE(e);
1461 APR_BRIGADE_INSERT_TAIL(bb, e);
1462 return APR_SUCCESS;
1463 }
1464 APR_BUCKET_REMOVE(e);
1465 APR_BRIGADE_INSERT_TAIL(bb, e);
1466 read += len;
1467 }
1468 if (APR_BRIGADE_EMPTY(self->bb)) {
1469 /* our work is done so remove this filter */
1470 ap_remove_input_filter(f);
1471 }
1472 }
1473 return APR_SUCCESS;
1474 }
1475
1476 /**
1477 * Get all parameter/value pairs in this request
1478 *
1479 * @param self IN instance
1480 * @param params OUT table of key/value pairs
1481 *
1482 * @return APR_SUCCESS
1483 */
1484 AP_DECLARE(apr_status_t) parp_get_params(parp_t *self, apr_table_t **params) {
1485 *params = self->params;
1486 return APR_SUCCESS;
1487 }
1488
1489 /**
1490 * Get error message on error
1491 *
1492 * @param self IN instance
1493 *
1494 * @return error message, empty message or NULL if instance not valid
1495 */
1496 AP_DECLARE(char *) parp_get_error(parp_t *self) {
1497 if (self && self->error) {
1498 return apr_pstrdup(self->pool, self->error);
1499 }
1500 else {
1501 return NULL;
1502 }
1503 }
1504
1505 /**
1506 * Optional function which may be used by Apache modules
1507 * to access the parameter table.
1508 *
1509 * @param r IN request record
1510 *
1511 * @return table with the request parameter or NULL if not available
1512 */
1513 AP_DECLARE(apr_table_t *)parp_hp_table(request_rec *r) {
1514 parp_t *parp = ap_get_module_config(r->request_config, &parp_module);
1515 apr_table_t *tl = NULL;
1516 if (parp) {
1517 parp_get_params(parp, &tl);
1518 }
1519 return tl;
1520 }
1521
1522 /**
1523 * Optional function which may be used by Apache modules
1524 * to access the body data. Only get data if not allready
1525 * parsed (and modified) and parser was active.
1526 *
1527 * @param r IN request record
1528 * @param len OUT body data len
1529 *
1530 * @return body data or NULL
1531 */
1532 AP_DECLARE(const char *)parp_body_data(request_rec *r, apr_size_t *len) {
1533 parp_t *parp = ap_get_module_config(r->request_config, &parp_module);
1534 *len = 0;
1535 if (parp && parp->data_body) {
1536 *len = parp->len_body;
1537 return parp->data_body;
1538 }
1539 return NULL;
1540 }
1541
1542 /**
1543 * Verifies if some values have been changed and adjust content length header. Also
1544 * sets the "use_raw_body" flag to signalize the input filter to forward the modifed data.
1545 */
1546 static void parp_update_content_length_multipart(parp_t *self, parp_body_structure_t *parent,
1547 apr_off_t *contentlen) {
1548
1549 int i;
1550 parp_entry_t *rw_entries = (parp_entry_t *) self->rw_params->elts;
1551
1552 parp_body_structure_t *body_structure_entries =
1553 (parp_body_structure_t *) parent->multipart_parameters->elts;
1554 for (i = 0; i < parent->multipart_parameters->nelts; ++i) {
1555 parp_body_structure_t *bs = &body_structure_entries[i];
1556 if (bs->rw_array_index == -1 && bs->multipart_parameters != NULL) { //multipart
1557 parp_update_content_length_multipart(self,bs, contentlen);
1558 if (bs->multipart_parameters_ndelete == bs->multipart_parameters->nelts) {
1559 *contentlen = *contentlen - bs->raw_len_modified;
1560 parent->raw_len_modified -= bs->raw_len;
1561 parent->multipart_parameters_ndelete++;
1562 }
1563 } else {
1564 if (bs->rw_array_index >= 0 && bs->rw_array_index < self->rw_params->nelts) { // valid index
1565 parp_entry_t *e = &rw_entries[bs->rw_array_index];
1566 if (e->new_value != NULL) {
1567 *contentlen = *contentlen + strlen(e->new_value) - strlen(e->value); // TODO: this is not safe from security coding prospective
1568 self->use_raw_body = 1;
1569 } else if (e->delete != 0) {
1570 *contentlen = *contentlen - bs->raw_len;
1571 parent->raw_len_modified -= bs->raw_len;
1572 parent->multipart_parameters_ndelete++;
1573 self->use_raw_body = 1;
1574 }
1575 }
1576 }
1577 }
1578 }
1579
1580 /**
1581 * Verifies if some values have been changed and adjust content length header. Also
1582 * sets the "use_raw_body" flag to signalize the input filter to forward the modifed data.
1583 */
1584 static void parp_update_content_length(request_rec *r, parp_t *self,
1585 apr_off_t *contentlen) {
1586
1587 int i;
1588 if (self->rw_params_body_structure && self->rw_params) {
1589 parp_entry_t *rw_entries = (parp_entry_t *) self->rw_params->elts;
1590 parp_body_structure_t *body_structure_entries =
1591 (parp_body_structure_t *) self->rw_params_body_structure->elts;
1592 for (i = 0; i < self->rw_params_body_structure->nelts; ++i) {
1593 parp_body_structure_t *bs = &body_structure_entries[i];
1594
1595 if (bs->rw_array_index >= 0 && bs->multipart_parameters == NULL) { // no multipart
1596 parp_entry_t *pe = &rw_entries[bs->rw_array_index];
1597 if (pe->new_value) {
1598 int diff = strlen(pe->new_value) - strlen(pe->value); // TODO: this is not safe from security coding prospective
1599 *contentlen = *contentlen + diff;
1600 bs->raw_len_modified = bs->raw_len_modified + diff;
1601 self->use_raw_body = 1;
1602 }
1603 else if (pe->delete == 1) {
1604 int temp_len = strlen(pe->key) + 1 + strlen(pe->value);
1605 if (*contentlen == temp_len) {
1606 *contentlen = 0;
1607 bs->raw_len_modified = 0;
1608 }
1609 else {
1610 *contentlen = *contentlen - temp_len - 1; // remove also '&'
1611 bs->raw_len_modified -= temp_len;
1612 }
1613 self->use_raw_body = 1;
1614 }
1615 }
1616 else { // multipart
1617 parp_update_content_length_multipart(self, bs, contentlen);
1618 if (bs->multipart_parameters_ndelete == bs->multipart_parameters->nelts) {
1619 *contentlen = *contentlen - bs->raw_len_modified;
1620 }
1621 }
1622 }
1623 if (apr_table_get(r->headers_in, "Content-Length")) {
1624 apr_table_set (r->headers_in, "Content-Length", apr_psprintf(r->pool, "%"APR_OFF_T_FMT, *contentlen));
1625 }
1626 }
1627 }
1628
1629
1630 static void parp_update_query_parameter(request_rec *r, parp_t *self) {
1631
1632 int i;
1633 // update query parameters
1634 if (!apr_is_empty_array(self->rw_params_query_structure)) {
1635 char *new_arg = NULL;
1636 int query_has_changed = 0;
1637
1638 parp_entry_t *rw_entries = (parp_entry_t *) self->rw_params->elts;
1639 parp_query_structure_t *query_structure_entries =
1640 (parp_query_structure_t *) self->rw_params_query_structure->elts;
1641 for (i = 0; i < self->rw_params_query_structure->nelts; ++i) {
1642 parp_query_structure_t *qs = &query_structure_entries[i];
1643 if (qs->rw_array_index >= 0 && qs->rw_array_index < self->rw_params->nelts) {
1644 parp_entry_t *e = &rw_entries[qs->rw_array_index];
1645 char *tmp_param = NULL;
1646 if (e->new_value != NULL) {
1647 tmp_param = apr_pstrcat(self->pool, e->key, "=", e->new_value, NULL);
1648 query_has_changed = 1;
1649 } else if (e->delete != 0) {
1650 query_has_changed = 1;
1651 } else {
1652 tmp_param = apr_pstrcat(self->pool, e->key, "=", e->value, NULL);
1653 }
1654 if (tmp_param != NULL) {
1655 if (new_arg != NULL) {
1656 new_arg = apr_pstrcat(self->pool, new_arg, "&", tmp_param, NULL);
1657 } else {
1658 new_arg = apr_pstrdup(self->pool, tmp_param);
1659 }
1660 }
1661 }
1662 }
1663 if (query_has_changed == 1) {
1664 char *unparsed_uri = apr_pstrdup(self->pool, r->unparsed_uri);
1665
1666 char *anchorstart = strchr(unparsed_uri, '#');
1667 char *querystart = strchr(unparsed_uri, '?');
1668 if (querystart != NULL) {
1669 querystart[0] = '\0';
1670 }
1671
1672 char *new_uri;
1673 if (new_arg != NULL) {
1674 new_uri = apr_pstrcat(self->pool, unparsed_uri, "?", new_arg, NULL);
1675 }
1676 else {
1677 new_uri = apr_pstrcat(self->pool, unparsed_uri, NULL);
1678 }
1679 if (anchorstart != NULL) {
1680 new_uri = apr_pstrcat(self->pool, new_uri, anchorstart, NULL);
1681 }
1682
1683 // update r->the_request
1684 char *hp = strstr(r->the_request, r->unparsed_uri);
1685 if(hp) {
1686 hp[0] = '\0';
1687 r->the_request = apr_pstrdup(r->pool, r->the_request);
1688 hp += strlen(r->unparsed_uri);
1689 r->the_request = apr_pstrcat(r->pool, r->the_request, new_uri, hp, NULL);
1690 }
1691 // restore all uri parameter
1692 ap_parse_uri(r, new_uri);
1693 }
1694 }
1695 }
1696 /************************************************************************
1697 * handlers
1698 ***********************************************************************/
1699
1700 /**
1701 * Hook to delete parameter which has been defined by the notes PARP_DELETE_PARAM.
1702 */
1703 static apr_status_t parp_delete_parameter(request_rec *r, apr_array_header_t *array) {
1704 int i;
1705 parp_entry_t *entries = (parp_entry_t *)array->elts;
1706
1707 /* create a table from the r->notes with all defined parameter names to be remoced */
1708 apr_table_t *param_table = apr_table_make(r->pool, 10);
1709 apr_table_entry_t *e = (apr_table_entry_t *) apr_table_elts(r->notes)->elts;
1710 for(i = 0; i < apr_table_elts(r->notes)->nelts; ++i) {
1711 if(e[i].key && e[i].val && strcmp(e[i].key, PARP_DELETE_PARAM) == 0) {
1712 apr_table_set(param_table, e[i].val, "");
1713 }
1714 }
1715
1716 /* iterate through the received parameters and remove those within our param_table */
1717 for(i = 0; i < array->nelts; ++i) {
1718 parp_entry_t *b = &entries[i];
1719 if(apr_table_get(param_table, b->key)) {
1720 b->delete = 1;
1721 }
1722 }
1723 return DECLINED;
1724 }
1725
1726 static int parp_post_config(apr_pool_t *pconf, apr_pool_t *plog,
1727 apr_pool_t *ptemp, server_rec *bs) {
1728 // register hook to delete parameters as defined by r->notes
1729 APR_OPTIONAL_HOOK(parp, modify_hook, parp_delete_parameter, NULL, NULL, APR_HOOK_MIDDLE);
1730 return DECLINED;
1731 }
1732
1733 /**
1734 * Header parser starts body parsing when reading "parp" in
1735 * the process environment or request notes and calls all
1736 * functions registered to the hs_hook.
1737 *
1738 * @param r IN request record
1739 * @return DECLINED if inactive, return code of the registered
1740 * functions or the value defined by PARP_ExitOnError
1741 * on any parser error.
1742 */
1743 static int parp_header_parser(request_rec * r) {
1744 apr_status_t status = DECLINED;
1745 if (ap_is_initial_req(r)) {
1746 const char *e = apr_table_get(r->notes, "parp");
1747 if (e == NULL) {
1748 e = apr_table_get(r->subprocess_env, "parp");
1749 }
1750 if (e == NULL) {
1751 /* no event */
1752 return DECLINED;
1753 } else {
1754 apr_table_t *tl;
1755 parp_t *parp = parp_new(r, PARP_FLAGS_NONE);
1756 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
1757 PARP_LOG_PFX(000)"enabled (%s)", e);
1758
1759 status = parp_read_params(parp);
1760 ap_set_module_config(r->request_config, &parp_module, parp);
1761 ap_add_input_filter("parp-forward-filter", parp, r, r->connection);
1762 if (status == APR_SUCCESS) {
1763 apr_off_t contentlen;
1764 parp_get_params(parp, &tl);
1765 apr_brigade_length(parp->bb, 1, &contentlen);
1766
1767 status = parp_run_hp_hook(r, tl);
1768 if (parp->rw_params) {
1769 parp_run_modify_body_hook(r, parp->rw_params); // only for backwards compatibility
1770 parp_run_modify_hook(r, parp->rw_params);
1771 parp_update_content_length(r, parp, &contentlen);
1772 parp_update_query_parameter(r, parp);
1773 }
1774 apr_table_set (r->subprocess_env,
1775 "PARPContentLength",
1776 apr_psprintf(r->pool, "%"APR_OFF_T_FMT, contentlen));
1777 } else {
1778 parp_srv_config *sconf = ap_get_module_config(r->server->module_config,
1779 &parp_module);
1780 char *error = parp_get_error(parp);
1781
1782 ap_log_rerror(APLOG_MARK, sconf->onerror == 200 ? APLOG_WARNING : APLOG_ERR, 0, r,
1783 PARP_LOG_PFX(010)"parser error, rc=%d (%s)",
1784 sconf->onerror == -1 ? 500 : sconf->onerror,
1785 error == NULL ? "-" : error);
1786 if(sconf->onerror == 200) {
1787 return DECLINED;
1788 }
1789 if(sconf->onerror == -1) {
1790 status = HTTP_INTERNAL_SERVER_ERROR;
1791 } else {
1792 status = sconf->onerror;
1793 }
1794 }
1795 }
1796 }
1797 return status;
1798 }
1799
1800 static void *parp_srv_config_create(apr_pool_t *p, server_rec *s) {
1801 parp_srv_config *sconf = apr_pcalloc(p, sizeof(parp_srv_config));
1802 sconf->onerror = -1; /* -1 is handles same as 500 but is the default (used for merger) */
1803 return sconf;
1804 }
1805
1806 static void *parp_srv_config_merge(apr_pool_t *p, void *basev, void *addv) {
1807 parp_srv_config *b = (parp_srv_config *) basev;
1808 parp_srv_config *o = (parp_srv_config *) addv;
1809 if (o->onerror == -1) {
1810 o->onerror = b->onerror;
1811 }
1812 if (o->parsers == NULL) {
1813 o->parsers = b->parsers;
1814 }
1815 return o;
1816 }
1817
1818 /************************************************************************
1819 * directiv handlers
1820 ***********************************************************************/
1821 const char *parp_error_code_cmd(cmd_parms *cmd, void *dcfg, const char *arg) {
1822 parp_srv_config *sconf = ap_get_module_config(cmd->server->module_config,
1823 &parp_module);
1824 sconf->onerror = atoi(arg);
1825 if (sconf->onerror == 200) {
1826 return NULL;
1827 }
1828 if ((sconf->onerror < 400) || (sconf->onerror > 599)) {
1829 return apr_psprintf(cmd->pool, "%s: error code must be a numeric value between 400 and 599"
1830 " (or set 200 to ignore errors)",
1831 cmd->directive->directive);
1832 }
1833 return NULL;
1834 }
1835
1836 const char *parp_body_data_cmd(cmd_parms *cmd, void *dcfg, const char *arg) {
1837 parp_srv_config *sconf = ap_get_module_config(cmd->server->module_config,
1838 &parp_module);
1839 if (!sconf->parsers) {
1840 sconf->parsers = apr_table_make(cmd->pool, 5);
1841 }
1842 apr_table_setn(sconf->parsers, apr_pstrdup(cmd->pool, arg),
1843 (char *) parp_parser_get_body);
1844 return NULL;
1845 }
1846
1847 static const command_rec parp_config_cmds[] = {
1848 AP_INIT_TAKE1("PARP_ExitOnError", parp_error_code_cmd, NULL,
1849 RSRC_CONF,
1850 "PARP_ExitOnError <code>, defines the HTTP error code"
1851 " to return on parsing errors. Default is 500."
1852 " Specify 200 in order to ignore errors."),
1853 AP_INIT_ITERATE("PARP_BodyData", parp_body_data_cmd, NULL,
1854 RSRC_CONF,
1855 "PARP_BodyData <content-type>, defines content"
1856 " types where only the body data are read. Default is"
1857 " no content type. Use '*/*' no activate the body read"
1858 " parser for any content type."),
1859 { NULL }
1860 };
1861
1862 /************************************************************************
1863 * apache register
1864 ***********************************************************************/
1865 static void parp_register_hooks(apr_pool_t * p) {
1866 static const char *pre[] = { "mod_setenvif.c", "mod_deflate.c", NULL };
1867 /* header parser is invoked after mod_setenvif */
1868 ap_hook_header_parser(parp_header_parser, pre, NULL, APR_HOOK_MIDDLE);
1869 ap_hook_post_config(parp_post_config, pre, NULL, APR_HOOK_MIDDLE);
1870 ap_register_input_filter("parp-forward-filter", parp_forward_filter, NULL, AP_FTYPE_RESOURCE);
1871 APR_REGISTER_OPTIONAL_FN(parp_hp_table);
1872 APR_REGISTER_OPTIONAL_FN(parp_body_data);
1873 }
1874
1875 /************************************************************************
1876 * apache module definition
1877 ***********************************************************************/
1878 module AP_MODULE_DECLARE_DATA parp_module ={
1879 STANDARD20_MODULE_STUFF,
1880 NULL, /**< dir config creater */
1881 NULL, /**< dir merger */
1882 parp_srv_config_create, /**< server config */
1883 parp_srv_config_merge, /**< server merger */
1884 parp_config_cmds, /**< command table */
1885 parp_register_hooks, /**< hook registery */
1886 };