| /* |
| ** Licensed to the Apache Software Foundation (ASF) under one or more |
| ** contributor license agreements. See the NOTICE file distributed with |
| ** this work for additional information regarding copyright ownership. |
| ** The ASF licenses this file to You under the Apache License, Version 2.0 |
| ** (the "License"); you may not use this file except in compliance with |
| ** the License. You may obtain a copy of the License at |
| ** |
| ** http://www.apache.org/licenses/LICENSE-2.0 |
| ** |
| ** Unless required by applicable law or agreed to in writing, software |
| ** distributed under the License is distributed on an "AS IS" BASIS, |
| ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| ** See the License for the specific language governing permissions and |
| ** limitations under the License. |
| */ |
| |
| #include "apreq_param.h" |
| #include "apreq_error.h" |
| #include "apreq_util.h" |
| #include "apr_strings.h" |
| #include "apr_lib.h" |
| |
| #define MAX_LEN (1024 * 1024) |
| #define MAX_BRIGADE_LEN (1024 * 256) |
| #define MAX_READ_AHEAD (1024 * 64) |
| |
| |
| APREQ_DECLARE(apreq_param_t *) apreq_param_make(apr_pool_t *p, |
| const char *name, |
| const apr_size_t nlen, |
| const char *val, |
| const apr_size_t vlen) |
| { |
| apreq_param_t *param; |
| apreq_value_t *v; |
| |
| param = apr_palloc(p, nlen + vlen + 1 + sizeof *param); |
| |
| if (param == NULL) |
| return NULL; |
| |
| param->info = NULL; |
| param->upload = NULL; |
| param->flags = 0; |
| |
| *(const apreq_value_t **)&v = ¶m->v; |
| |
| if (vlen && val != NULL) |
| memcpy(v->data, val, vlen); |
| v->data[vlen] = 0; |
| v->dlen = vlen; |
| |
| v->name = v->data + vlen + 1; |
| if (nlen && name != NULL) |
| memcpy(v->name, name, nlen); |
| v->name[nlen] = 0; |
| v->nlen = nlen; |
| |
| return param; |
| } |
| |
| APREQ_DECLARE(apr_status_t) apreq_param_decode(apreq_param_t **param, |
| apr_pool_t *pool, |
| const char *word, |
| apr_size_t nlen, |
| apr_size_t vlen) |
| { |
| apr_status_t status; |
| apreq_value_t *v; |
| apreq_param_t *p; |
| apreq_charset_t charset; |
| |
| if (nlen == 0) { |
| *param = NULL; |
| return APR_EBADARG; |
| } |
| |
| p = apr_palloc(pool, nlen + vlen + 1 + sizeof *p); |
| p->info = NULL; |
| p->upload = NULL; |
| p->flags = 0; |
| *(const apreq_value_t **)&v = &p->v; |
| |
| if (vlen > 0) { |
| status = apreq_decode(v->data, &v->dlen, word + nlen + 1, vlen); |
| if (status != APR_SUCCESS) { |
| *param = NULL; |
| return status; |
| } |
| charset = apreq_charset_divine(v->data, v->dlen); |
| } |
| else { |
| v->data[0] = 0; |
| v->dlen = 0; |
| charset = APREQ_CHARSET_ASCII; |
| } |
| v->name = v->data + vlen + 1; |
| |
| status = apreq_decode(v->name, &v->nlen, word, nlen); |
| if (status != APR_SUCCESS) { |
| *param = NULL; |
| return status; |
| } |
| |
| switch (apreq_charset_divine(v->name, v->nlen)) { |
| case APREQ_CHARSET_UTF8: |
| if (charset == APREQ_CHARSET_ASCII) |
| charset = APREQ_CHARSET_UTF8; |
| case APREQ_CHARSET_ASCII: |
| break; |
| |
| case APREQ_CHARSET_LATIN1: |
| if (charset != APREQ_CHARSET_CP1252) |
| charset = APREQ_CHARSET_LATIN1; |
| break; |
| case APREQ_CHARSET_CP1252: |
| charset = APREQ_CHARSET_CP1252; |
| } |
| |
| apreq_param_charset_set(p, charset); |
| *param = p; |
| |
| return APR_SUCCESS; |
| } |
| |
| |
| APREQ_DECLARE(char *) apreq_param_encode(apr_pool_t *pool, |
| const apreq_param_t *param) |
| { |
| apr_size_t dlen; |
| char *data; |
| data = apr_palloc(pool, 3 * (param->v.nlen + param->v.dlen) + 2); |
| dlen = apreq_encode(data, param->v.name, param->v.nlen); |
| data[dlen++] = '='; |
| dlen += apreq_encode(data + dlen, param->v.data, param->v.dlen); |
| |
| return data; |
| } |
| |
| APREQ_DECLARE(apr_status_t) apreq_parse_query_string(apr_pool_t *pool, |
| apr_table_t *t, |
| const char *qs) |
| { |
| const char *start = qs; |
| apr_size_t nlen = 0; |
| |
| for (;;++qs) { |
| switch (*qs) { |
| |
| case '=': |
| if (nlen == 0) { |
| nlen = qs - start; |
| } |
| break; |
| |
| case '&': |
| case ';': |
| case 0: |
| if (qs > start) { |
| apr_size_t vlen = 0; |
| apreq_param_t *param; |
| apr_status_t s; |
| if (nlen == 0) |
| nlen = qs - start; |
| else |
| vlen = qs - start - nlen - 1; |
| |
| s = apreq_param_decode(¶m, pool, start, nlen, vlen); |
| if (s != APR_SUCCESS) |
| return s; |
| |
| apreq_param_tainted_on(param); |
| apreq_value_table_add(¶m->v, t); |
| } |
| |
| if (*qs == 0) |
| return APR_SUCCESS; |
| |
| nlen = 0; |
| start = qs + 1; |
| } |
| } |
| /* not reached */ |
| return APR_INCOMPLETE; |
| } |
| |
| |
| |
| |
| static int param_push(void *data, const char *key, const char *val) |
| { |
| apr_array_header_t *arr = data; |
| *(apreq_param_t **)apr_array_push(arr) = |
| apreq_value_to_param(val); |
| return 1; /* keep going */ |
| } |
| |
| |
| APREQ_DECLARE(apr_array_header_t *) apreq_params_as_array(apr_pool_t *p, |
| const apr_table_t *t, |
| const char *key) |
| { |
| apr_array_header_t *arr; |
| |
| arr = apr_array_make(p, apr_table_elts(t)->nelts, |
| sizeof(apreq_param_t *)); |
| |
| apr_table_do(param_push, arr, t, key, NULL); |
| return arr; |
| } |
| |
| APREQ_DECLARE(const char *) apreq_params_as_string(apr_pool_t *p, |
| const apr_table_t *t, |
| const char *key, |
| apreq_join_t mode) |
| { |
| apr_array_header_t *arr = apreq_params_as_array(p, t, key); |
| apreq_param_t **elt = (apreq_param_t **)arr->elts; |
| apreq_param_t **const end = elt + arr->nelts; |
| if (arr->nelts == 0) |
| return apr_pstrdup(p, ""); |
| |
| while (elt < end) { |
| *(const apreq_value_t **)elt = &(**elt).v; |
| ++elt; |
| } |
| return apreq_join(p, ", ", arr, mode); |
| } |
| |
| |
| |
| static int upload_push(void *data, const char *key, const char *val) |
| { |
| apr_table_t *t = data; |
| apreq_param_t *p = apreq_value_to_param(val); |
| |
| if (p->upload != NULL) |
| apreq_value_table_add(&p->v, t); |
| return 1; /* keep going */ |
| } |
| |
| |
| APREQ_DECLARE(const apr_table_t *) apreq_uploads(const apr_table_t *body, |
| apr_pool_t *pool) |
| { |
| apr_table_t *t = apr_table_make(pool, APREQ_DEFAULT_NELTS); |
| apr_table_do(upload_push, t, body, NULL); |
| return t; |
| } |
| |
| static int upload_set(void *data, const char *key, const char *val) |
| { |
| const apreq_param_t **q = data; |
| apreq_param_t *p = apreq_value_to_param(val); |
| |
| if (p->upload != NULL) { |
| *q = p; |
| return 0; /* upload found, stop */ |
| } |
| else |
| return 1; /* keep searching */ |
| } |
| |
| |
| APREQ_DECLARE(const apreq_param_t *) apreq_upload(const apr_table_t *body, |
| const char *name) |
| { |
| apreq_param_t *param = NULL; |
| apr_table_do(upload_set, ¶m, body, name, NULL); |
| return param; |
| } |