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