/src/httpd/server/apreq_parser_urlencoded.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_parser.h" |
19 | | #include "apreq_util.h" |
20 | | #include "apreq_error.h" |
21 | | |
22 | | |
23 | 150 | #define PARSER_STATUS_CHECK(PREFIX) do { \ |
24 | 150 | if (ctx->status == PREFIX##_ERROR) \ |
25 | 150 | return APREQ_ERROR_GENERAL; \ |
26 | 150 | else if (ctx->status == PREFIX##_COMPLETE) \ |
27 | 150 | return APR_SUCCESS; \ |
28 | 150 | else if (bb == NULL) \ |
29 | 150 | return APR_INCOMPLETE; \ |
30 | 150 | } while (0); |
31 | | |
32 | | |
33 | | |
34 | | struct url_ctx { |
35 | | apr_bucket_brigade *bb; |
36 | | apr_size_t nlen; |
37 | | apr_size_t vlen; |
38 | | enum { |
39 | | URL_NAME, |
40 | | URL_VALUE, |
41 | | URL_COMPLETE, |
42 | | URL_ERROR |
43 | | } status; |
44 | | }; |
45 | | |
46 | | |
47 | | /******************** application/x-www-form-urlencoded ********************/ |
48 | | |
49 | | static apr_status_t split_urlword(apreq_param_t **p, apr_pool_t *pool, |
50 | | apr_bucket_brigade *bb, |
51 | | apr_size_t nlen, |
52 | | apr_size_t vlen) |
53 | 552 | { |
54 | 552 | apreq_param_t *param; |
55 | 552 | apreq_value_t *v; |
56 | 552 | apr_bucket *e, *f; |
57 | 552 | apr_status_t s; |
58 | 552 | struct iovec vec[APREQ_DEFAULT_NELTS]; |
59 | 552 | apr_array_header_t arr; |
60 | 552 | apr_size_t mark; |
61 | 552 | apreq_charset_t charset; |
62 | | |
63 | 552 | if (nlen == 0) |
64 | 1 | return APR_EBADARG; |
65 | | |
66 | 551 | param = apreq_param_make(pool, NULL, nlen, NULL, vlen); |
67 | 551 | if (param == NULL) |
68 | 0 | return APR_ENOMEM; |
69 | 551 | *(const apreq_value_t **)&v = ¶m->v; |
70 | | |
71 | 551 | arr.pool = pool; |
72 | 551 | arr.elt_size = sizeof(struct iovec); |
73 | 551 | arr.nelts = 0; |
74 | 551 | arr.nalloc = APREQ_DEFAULT_NELTS; |
75 | 551 | arr.elts = (char *)vec; |
76 | | |
77 | 551 | ++nlen, ++vlen; |
78 | 551 | e = APR_BRIGADE_FIRST(bb); |
79 | | |
80 | 551 | while (!APR_BUCKET_IS_EOS(e)) { |
81 | 551 | struct iovec *iov = apr_array_push(&arr); |
82 | 551 | apr_size_t len; |
83 | 551 | s = apr_bucket_read(e, (const char **)&iov->iov_base, |
84 | 551 | &len, APR_BLOCK_READ); |
85 | 551 | if (s != APR_SUCCESS) |
86 | 0 | return s; |
87 | | |
88 | 551 | iov->iov_len = len; |
89 | 551 | nlen -= len; |
90 | | |
91 | 551 | e = APR_BUCKET_NEXT(e); |
92 | | |
93 | 551 | if (nlen == 0) { |
94 | 551 | iov->iov_len--; |
95 | 551 | break; |
96 | 551 | } |
97 | 551 | } |
98 | | |
99 | 551 | mark = arr.nelts; |
100 | | |
101 | 551 | while (!APR_BUCKET_IS_EOS(e)) { |
102 | 551 | struct iovec *iov = apr_array_push(&arr); |
103 | 551 | apr_size_t len; |
104 | 551 | s = apr_bucket_read(e, (const char **)&iov->iov_base, |
105 | 551 | &len, APR_BLOCK_READ); |
106 | 551 | if (s != APR_SUCCESS) |
107 | 0 | return s; |
108 | | |
109 | 551 | iov->iov_len = len; |
110 | 551 | vlen -= len; |
111 | | |
112 | 551 | e = APR_BUCKET_NEXT(e); |
113 | | |
114 | 551 | if (vlen == 0) { |
115 | 551 | iov->iov_len--; |
116 | 551 | break; |
117 | 551 | } |
118 | | |
119 | 551 | } |
120 | | |
121 | 551 | s = apreq_decodev(v->data, &vlen, |
122 | 551 | (struct iovec *)arr.elts + mark, arr.nelts - mark); |
123 | 551 | if (s != APR_SUCCESS) |
124 | 29 | return s; |
125 | | |
126 | 522 | charset = apreq_charset_divine(v->data, vlen); |
127 | | |
128 | 522 | v->name = v->data + vlen + 1; |
129 | 522 | v->dlen = vlen; |
130 | | |
131 | 522 | s = apreq_decodev(v->name, &nlen, (struct iovec *)arr.elts, mark); |
132 | 522 | if (s != APR_SUCCESS) |
133 | 41 | return s; |
134 | | |
135 | 481 | switch (apreq_charset_divine(v->name, nlen)) { |
136 | 62 | case APREQ_CHARSET_UTF8: |
137 | 62 | if (charset == APREQ_CHARSET_ASCII) |
138 | 39 | charset = APREQ_CHARSET_UTF8; |
139 | 227 | case APREQ_CHARSET_ASCII: |
140 | 227 | break; |
141 | | |
142 | 177 | case APREQ_CHARSET_LATIN1: |
143 | 177 | if (charset != APREQ_CHARSET_CP1252) |
144 | 148 | charset = APREQ_CHARSET_LATIN1; |
145 | 177 | break; |
146 | 77 | case APREQ_CHARSET_CP1252: |
147 | 77 | charset = APREQ_CHARSET_CP1252; |
148 | 481 | } |
149 | | |
150 | 481 | v->nlen = nlen; |
151 | | |
152 | 1.44k | while ((f = APR_BRIGADE_FIRST(bb)) != e) |
153 | 962 | apr_bucket_delete(f); |
154 | | |
155 | 481 | apreq_param_tainted_on(param); |
156 | 481 | apreq_param_charset_set(param, charset); |
157 | 481 | *p = param; |
158 | 481 | return APR_SUCCESS; |
159 | 481 | } |
160 | | |
161 | | APREQ_DECLARE_PARSER(apreq_parse_urlencoded) |
162 | 150 | { |
163 | 150 | apr_pool_t *pool = parser->pool; |
164 | 150 | apr_bucket *e; |
165 | 150 | struct url_ctx *ctx; |
166 | | |
167 | 150 | if (parser->ctx == NULL) { |
168 | 150 | ctx = apr_pcalloc(pool, sizeof *ctx); |
169 | 150 | ctx->bb = apr_brigade_create(pool, parser->bucket_alloc); |
170 | 150 | parser->ctx = ctx; |
171 | 150 | ctx->status = URL_NAME; |
172 | 150 | } |
173 | 0 | else |
174 | 0 | ctx = parser->ctx; |
175 | | |
176 | 150 | PARSER_STATUS_CHECK(URL); |
177 | 150 | e = APR_BRIGADE_LAST(ctx->bb); |
178 | 150 | APR_BRIGADE_CONCAT(ctx->bb, bb); |
179 | | |
180 | 631 | parse_url_brigade: |
181 | | |
182 | 631 | for (e = APR_BUCKET_NEXT(e); |
183 | 710 | e != APR_BRIGADE_SENTINEL(ctx->bb); |
184 | 631 | e = APR_BUCKET_NEXT(e)) |
185 | 631 | { |
186 | 631 | apreq_param_t *param; |
187 | 631 | apr_size_t off = 0, dlen; |
188 | 631 | const char *data; |
189 | 631 | apr_status_t s; |
190 | | |
191 | 631 | if (APR_BUCKET_IS_EOS(e)) { |
192 | 0 | if (ctx->status == URL_NAME) { |
193 | 0 | s = APR_SUCCESS; |
194 | 0 | } |
195 | 0 | else { |
196 | 0 | s = split_urlword(¶m, pool, ctx->bb, ctx->nlen, ctx->vlen); |
197 | 0 | if (parser->hook != NULL && s == APR_SUCCESS) |
198 | 0 | s = apreq_hook_run(parser->hook, param, NULL); |
199 | |
|
200 | 0 | if (s == APR_SUCCESS) { |
201 | 0 | apreq_value_table_add(¶m->v, t); |
202 | 0 | ctx->status = URL_COMPLETE; |
203 | 0 | } |
204 | 0 | else { |
205 | 0 | ctx->status = URL_ERROR; |
206 | 0 | } |
207 | 0 | } |
208 | |
|
209 | 0 | APR_BRIGADE_CONCAT(bb, ctx->bb); |
210 | 0 | return s; |
211 | 0 | } |
212 | | |
213 | 631 | s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ); |
214 | 631 | if ( s != APR_SUCCESS ) { |
215 | 0 | ctx->status = URL_ERROR; |
216 | 0 | return s; |
217 | 0 | } |
218 | | |
219 | 1.19k | parse_url_bucket: |
220 | | |
221 | 1.19k | switch (ctx->status) { |
222 | | |
223 | 631 | case URL_NAME: |
224 | 5.29k | while (off < dlen) { |
225 | 5.23k | switch (data[off++]) { |
226 | 568 | case '=': |
227 | 568 | apr_bucket_split(e, off); |
228 | 568 | dlen -= off; |
229 | 568 | data += off; |
230 | 568 | off = 0; |
231 | 568 | e = APR_BUCKET_NEXT(e); |
232 | 568 | ctx->status = URL_VALUE; |
233 | 568 | goto parse_url_bucket; |
234 | 4.66k | default: |
235 | 4.66k | ++ctx->nlen; |
236 | 5.23k | } |
237 | 5.23k | } |
238 | 63 | break; |
239 | | |
240 | 568 | case URL_VALUE: |
241 | 3.48k | while (off < dlen) { |
242 | | |
243 | 3.46k | switch (data[off++]) { |
244 | 141 | case '&': |
245 | 552 | case ';': |
246 | 552 | apr_bucket_split(e, off); |
247 | 552 | s = split_urlword(¶m, pool, ctx->bb, |
248 | 552 | ctx->nlen, ctx->vlen); |
249 | 552 | if (parser->hook != NULL && s == APR_SUCCESS) |
250 | 481 | s = apreq_hook_run(parser->hook, param, NULL); |
251 | | |
252 | 552 | if (s != APR_SUCCESS) { |
253 | 71 | ctx->status = URL_ERROR; |
254 | 71 | return s; |
255 | 71 | } |
256 | | |
257 | 481 | apreq_value_table_add(¶m->v, t); |
258 | 481 | ctx->status = URL_NAME; |
259 | 481 | ctx->nlen = 0; |
260 | 481 | ctx->vlen = 0; |
261 | 481 | e = APR_BRIGADE_SENTINEL(ctx->bb); |
262 | 481 | goto parse_url_brigade; |
263 | | |
264 | 2.91k | default: |
265 | 2.91k | ++ctx->vlen; |
266 | 3.46k | } |
267 | 3.46k | } |
268 | 16 | break; |
269 | 16 | default: |
270 | 0 | ; /* not reached */ |
271 | 1.19k | } |
272 | 1.19k | } |
273 | 79 | apreq_brigade_setaside(ctx->bb, pool); |
274 | 79 | return APR_INCOMPLETE; |
275 | 631 | } |
276 | | |
277 | | |