"Fossies" - the Fresh Open Source Software Archive

Member "mod_parp-0.16/apache2/mod_parp.c" (15 Jun 2016, 63838 Bytes) of package /linux/www/apache_httpd_modules/mod_parp-0.16-src.tar.gz:


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 };