/src/httpd/server/apreq_param.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | ** Licensed to the Apache Software Foundation (ASF) under one or more |
3 | | ** contributor license agreements. See the NOTICE file distributed with |
4 | | ** this work for additional information regarding copyright ownership. |
5 | | ** The ASF licenses this file to You under the Apache License, Version 2.0 |
6 | | ** (the "License"); you may not use this file except in compliance with |
7 | | ** the License. You may obtain a copy of the License at |
8 | | ** |
9 | | ** http://www.apache.org/licenses/LICENSE-2.0 |
10 | | ** |
11 | | ** Unless required by applicable law or agreed to in writing, software |
12 | | ** distributed under the License is distributed on an "AS IS" BASIS, |
13 | | ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
14 | | ** See the License for the specific language governing permissions and |
15 | | ** limitations under the License. |
16 | | */ |
17 | | |
18 | | #include "apreq_param.h" |
19 | | #include "apreq_error.h" |
20 | | #include "apreq_util.h" |
21 | | #include "apr_strings.h" |
22 | | #include "apr_lib.h" |
23 | | |
24 | | #define MAX_LEN (1024 * 1024) |
25 | | #define MAX_BRIGADE_LEN (1024 * 256) |
26 | | #define MAX_READ_AHEAD (1024 * 64) |
27 | | |
28 | | |
29 | | APREQ_DECLARE(apreq_param_t *) apreq_param_make(apr_pool_t *p, |
30 | | const char *name, |
31 | | const apr_size_t nlen, |
32 | | const char *val, |
33 | | const apr_size_t vlen) |
34 | 2.56k | { |
35 | 2.56k | apreq_param_t *param; |
36 | 2.56k | apreq_value_t *v; |
37 | | |
38 | 2.56k | param = apr_palloc(p, nlen + vlen + 1 + sizeof *param); |
39 | | |
40 | 2.56k | if (param == NULL) |
41 | 0 | return NULL; |
42 | | |
43 | 2.56k | param->info = NULL; |
44 | 2.56k | param->upload = NULL; |
45 | 2.56k | param->flags = 0; |
46 | | |
47 | 2.56k | *(const apreq_value_t **)&v = ¶m->v; |
48 | | |
49 | 2.56k | if (vlen && val != NULL) |
50 | 4 | memcpy(v->data, val, vlen); |
51 | 2.56k | v->data[vlen] = 0; |
52 | 2.56k | v->dlen = vlen; |
53 | | |
54 | 2.56k | v->name = v->data + vlen + 1; |
55 | 2.56k | if (nlen && name != NULL) |
56 | 65 | memcpy(v->name, name, nlen); |
57 | 2.56k | v->name[nlen] = 0; |
58 | 2.56k | v->nlen = nlen; |
59 | | |
60 | 2.56k | return param; |
61 | 2.56k | } |
62 | | |
63 | | APREQ_DECLARE(apr_status_t) apreq_param_decode(apreq_param_t **param, |
64 | | apr_pool_t *pool, |
65 | | const char *word, |
66 | | apr_size_t nlen, |
67 | | apr_size_t vlen) |
68 | 0 | { |
69 | 0 | apr_status_t status; |
70 | 0 | apreq_value_t *v; |
71 | 0 | apreq_param_t *p; |
72 | 0 | apreq_charset_t charset; |
73 | |
|
74 | 0 | if (nlen == 0) { |
75 | 0 | *param = NULL; |
76 | 0 | return APR_EBADARG; |
77 | 0 | } |
78 | | |
79 | 0 | p = apr_palloc(pool, nlen + vlen + 1 + sizeof *p); |
80 | 0 | p->info = NULL; |
81 | 0 | p->upload = NULL; |
82 | 0 | p->flags = 0; |
83 | 0 | *(const apreq_value_t **)&v = &p->v; |
84 | |
|
85 | 0 | if (vlen > 0) { |
86 | 0 | status = apreq_decode(v->data, &v->dlen, word + nlen + 1, vlen); |
87 | 0 | if (status != APR_SUCCESS) { |
88 | 0 | *param = NULL; |
89 | 0 | return status; |
90 | 0 | } |
91 | 0 | charset = apreq_charset_divine(v->data, v->dlen); |
92 | 0 | } |
93 | 0 | else { |
94 | 0 | v->data[0] = 0; |
95 | 0 | v->dlen = 0; |
96 | 0 | charset = APREQ_CHARSET_ASCII; |
97 | 0 | } |
98 | 0 | v->name = v->data + vlen + 1; |
99 | |
|
100 | 0 | status = apreq_decode(v->name, &v->nlen, word, nlen); |
101 | 0 | if (status != APR_SUCCESS) { |
102 | 0 | *param = NULL; |
103 | 0 | return status; |
104 | 0 | } |
105 | | |
106 | 0 | switch (apreq_charset_divine(v->name, v->nlen)) { |
107 | 0 | case APREQ_CHARSET_UTF8: |
108 | 0 | if (charset == APREQ_CHARSET_ASCII) |
109 | 0 | charset = APREQ_CHARSET_UTF8; |
110 | 0 | case APREQ_CHARSET_ASCII: |
111 | 0 | break; |
112 | | |
113 | 0 | case APREQ_CHARSET_LATIN1: |
114 | 0 | if (charset != APREQ_CHARSET_CP1252) |
115 | 0 | charset = APREQ_CHARSET_LATIN1; |
116 | 0 | break; |
117 | 0 | case APREQ_CHARSET_CP1252: |
118 | 0 | charset = APREQ_CHARSET_CP1252; |
119 | 0 | } |
120 | | |
121 | 0 | apreq_param_charset_set(p, charset); |
122 | 0 | *param = p; |
123 | |
|
124 | 0 | return APR_SUCCESS; |
125 | 0 | } |
126 | | |
127 | | |
128 | | APREQ_DECLARE(char *) apreq_param_encode(apr_pool_t *pool, |
129 | | const apreq_param_t *param) |
130 | 0 | { |
131 | 0 | apr_size_t dlen; |
132 | 0 | char *data; |
133 | 0 | data = apr_palloc(pool, 3 * (param->v.nlen + param->v.dlen) + 2); |
134 | 0 | dlen = apreq_encode(data, param->v.name, param->v.nlen); |
135 | 0 | data[dlen++] = '='; |
136 | 0 | dlen += apreq_encode(data + dlen, param->v.data, param->v.dlen); |
137 | |
|
138 | 0 | return data; |
139 | 0 | } |
140 | | |
141 | | APREQ_DECLARE(apr_status_t) apreq_parse_query_string(apr_pool_t *pool, |
142 | | apr_table_t *t, |
143 | | const char *qs) |
144 | 0 | { |
145 | 0 | const char *start = qs; |
146 | 0 | apr_size_t nlen = 0; |
147 | |
|
148 | 0 | for (;;++qs) { |
149 | 0 | switch (*qs) { |
150 | | |
151 | 0 | case '=': |
152 | 0 | if (nlen == 0) { |
153 | 0 | nlen = qs - start; |
154 | 0 | } |
155 | 0 | break; |
156 | | |
157 | 0 | case '&': |
158 | 0 | case ';': |
159 | 0 | case 0: |
160 | 0 | if (qs > start) { |
161 | 0 | apr_size_t vlen = 0; |
162 | 0 | apreq_param_t *param; |
163 | 0 | apr_status_t s; |
164 | 0 | if (nlen == 0) |
165 | 0 | nlen = qs - start; |
166 | 0 | else |
167 | 0 | vlen = qs - start - nlen - 1; |
168 | |
|
169 | 0 | s = apreq_param_decode(¶m, pool, start, nlen, vlen); |
170 | 0 | if (s != APR_SUCCESS) |
171 | 0 | return s; |
172 | | |
173 | 0 | apreq_param_tainted_on(param); |
174 | 0 | apreq_value_table_add(¶m->v, t); |
175 | 0 | } |
176 | | |
177 | 0 | if (*qs == 0) |
178 | 0 | return APR_SUCCESS; |
179 | | |
180 | 0 | nlen = 0; |
181 | 0 | start = qs + 1; |
182 | 0 | } |
183 | 0 | } |
184 | | /* not reached */ |
185 | 0 | return APR_INCOMPLETE; |
186 | 0 | } |
187 | | |
188 | | |
189 | | |
190 | | |
191 | | static int param_push(void *data, const char *key, const char *val) |
192 | 0 | { |
193 | 0 | apr_array_header_t *arr = data; |
194 | 0 | *(apreq_param_t **)apr_array_push(arr) = |
195 | 0 | apreq_value_to_param(val); |
196 | 0 | return 1; /* keep going */ |
197 | 0 | } |
198 | | |
199 | | |
200 | | APREQ_DECLARE(apr_array_header_t *) apreq_params_as_array(apr_pool_t *p, |
201 | | const apr_table_t *t, |
202 | | const char *key) |
203 | 0 | { |
204 | 0 | apr_array_header_t *arr; |
205 | |
|
206 | 0 | arr = apr_array_make(p, apr_table_elts(t)->nelts, |
207 | 0 | sizeof(apreq_param_t *)); |
208 | |
|
209 | 0 | apr_table_do(param_push, arr, t, key, NULL); |
210 | 0 | return arr; |
211 | 0 | } |
212 | | |
213 | | APREQ_DECLARE(const char *) apreq_params_as_string(apr_pool_t *p, |
214 | | const apr_table_t *t, |
215 | | const char *key, |
216 | | apreq_join_t mode) |
217 | 0 | { |
218 | 0 | apr_array_header_t *arr = apreq_params_as_array(p, t, key); |
219 | 0 | apreq_param_t **elt = (apreq_param_t **)arr->elts; |
220 | 0 | apreq_param_t **const end = elt + arr->nelts; |
221 | 0 | if (arr->nelts == 0) |
222 | 0 | return apr_pstrdup(p, ""); |
223 | | |
224 | 0 | while (elt < end) { |
225 | 0 | *(const apreq_value_t **)elt = &(**elt).v; |
226 | 0 | ++elt; |
227 | 0 | } |
228 | 0 | return apreq_join(p, ", ", arr, mode); |
229 | 0 | } |
230 | | |
231 | | |
232 | | |
233 | | static int upload_push(void *data, const char *key, const char *val) |
234 | 0 | { |
235 | 0 | apr_table_t *t = data; |
236 | 0 | apreq_param_t *p = apreq_value_to_param(val); |
237 | |
|
238 | 0 | if (p->upload != NULL) |
239 | 0 | apreq_value_table_add(&p->v, t); |
240 | 0 | return 1; /* keep going */ |
241 | 0 | } |
242 | | |
243 | | |
244 | | APREQ_DECLARE(const apr_table_t *) apreq_uploads(const apr_table_t *body, |
245 | | apr_pool_t *pool) |
246 | 0 | { |
247 | 0 | apr_table_t *t = apr_table_make(pool, APREQ_DEFAULT_NELTS); |
248 | 0 | apr_table_do(upload_push, t, body, NULL); |
249 | 0 | return t; |
250 | 0 | } |
251 | | |
252 | | static int upload_set(void *data, const char *key, const char *val) |
253 | 0 | { |
254 | 0 | const apreq_param_t **q = data; |
255 | 0 | apreq_param_t *p = apreq_value_to_param(val); |
256 | |
|
257 | 0 | if (p->upload != NULL) { |
258 | 0 | *q = p; |
259 | 0 | return 0; /* upload found, stop */ |
260 | 0 | } |
261 | 0 | else |
262 | 0 | return 1; /* keep searching */ |
263 | 0 | } |
264 | | |
265 | | |
266 | | APREQ_DECLARE(const apreq_param_t *) apreq_upload(const apr_table_t *body, |
267 | | const char *name) |
268 | 0 | { |
269 | 0 | apreq_param_t *param = NULL; |
270 | 0 | apr_table_do(upload_set, ¶m, body, name, NULL); |
271 | 0 | return param; |
272 | 0 | } |