]> granicus.if.org Git - apache/blob - server/apreq_parser_header.c
Fix a corner case where automatic APLOGNO number generation generates invalid code...
[apache] / server / apreq_parser_header.c
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 #include <assert.h>
18 #include "apreq_parser.h"
19 #include "apreq_error.h"
20 #include "apreq_util.h"
21
22 #define PARSER_STATUS_CHECK(PREFIX)   do {         \
23     if (ctx->status == PREFIX##_ERROR)             \
24         return APREQ_ERROR_GENERAL;                \
25     else if (ctx->status == PREFIX##_COMPLETE)     \
26         return APR_SUCCESS;                        \
27     else if (bb == NULL)                           \
28         return APR_INCOMPLETE;                     \
29 } while (0);
30
31
32 struct hdr_ctx {
33     apr_bucket_brigade *bb;
34     apr_size_t          nlen;
35     apr_size_t          glen;
36     apr_size_t          vlen;
37     enum {
38         HDR_NAME,
39         HDR_GAP,
40         HDR_VALUE,
41         HDR_NEWLINE,
42         HDR_CONTINUE,
43         HDR_COMPLETE,
44         HDR_ERROR
45     }                   status;
46 };
47
48 /********************* header parsing utils ********************/
49
50
51 static apr_status_t split_header_line(apreq_param_t **p,
52                                       apr_pool_t *pool,
53                                       apr_bucket_brigade *bb,
54                                       apr_size_t nlen,
55                                       apr_size_t glen,
56                                       apr_size_t vlen)
57 {
58     apreq_param_t *param;
59     apreq_value_t *v;
60     apr_bucket *e, *f;
61     apr_status_t s;
62     struct iovec vec[APREQ_DEFAULT_NELTS], *iov, *end;
63     apr_array_header_t arr;
64     char *dest;
65     const char *data;
66     apr_size_t dlen;
67
68     if (nlen == 0)
69         return APR_EBADARG;
70
71     param = apreq_param_make(pool, NULL, nlen, NULL, vlen - 1); /*drop (CR)LF */
72     *(const apreq_value_t **)&v = &param->v;
73
74     arr.pool     = pool;
75     arr.elt_size = sizeof(struct iovec);
76     arr.nelts    = 0;
77     arr.nalloc   = APREQ_DEFAULT_NELTS;
78     arr.elts     = (char *)vec;
79
80     e = APR_BRIGADE_FIRST(bb);
81
82     /* store name in a temporary iovec array */
83
84     while (nlen > 0) {
85         apr_size_t len;
86         end = apr_array_push(&arr);
87         s = apr_bucket_read(e, (const char **)&end->iov_base,
88                             &len, APR_BLOCK_READ);
89         if (s != APR_SUCCESS)
90             return s;
91
92         assert(nlen >= len);
93         end->iov_len = len;
94         nlen -= len;
95
96         e = APR_BUCKET_NEXT(e);
97     }
98
99     /* skip gap */
100
101     while (glen > 0) {
102         s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
103         if (s != APR_SUCCESS)
104             return s;
105
106         assert(glen >= dlen);
107         glen -= dlen;
108         e = APR_BUCKET_NEXT(e);
109     }
110
111     /* copy value */
112     assert(vlen > 0);
113     dest = v->data;
114     while (vlen > 0) {
115
116         s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
117         if (s != APR_SUCCESS)
118             return s;
119
120         memcpy(dest, data, dlen);
121         dest += dlen;
122         assert(vlen >= dlen);
123         vlen -= dlen;
124         e = APR_BUCKET_NEXT(e);
125     }
126
127     assert(dest[-1] == '\n');
128
129     if (dest[-2] == '\r')
130         --dest;
131
132     dest[-1] = 0;
133     v->dlen = (dest - v->data) - 1;
134
135     /* write name */
136     v->name = dest;
137     iov = (struct iovec *)arr.elts;
138
139     while (iov <= end) {
140         memcpy(dest, iov->iov_base, iov->iov_len);
141         dest += iov->iov_len;
142         ++iov;
143     }
144     *dest = 0;
145
146     while ((f = APR_BRIGADE_FIRST(bb)) != e)
147         apr_bucket_delete(f);
148
149     apreq_param_tainted_on(param);
150     *p = param;
151     return APR_SUCCESS;
152
153 }
154
155
156 APREQ_DECLARE_PARSER(apreq_parse_headers)
157 {
158     apr_pool_t *pool = parser->pool;
159     apr_bucket *e;
160     struct hdr_ctx *ctx;
161
162     if (parser->ctx == NULL) {
163         ctx = apr_pcalloc(pool, sizeof *ctx);
164         ctx->bb = apr_brigade_create(pool, parser->bucket_alloc);
165         parser->ctx = ctx;
166         ctx->status = HDR_NAME;
167     }
168     else
169         ctx = parser->ctx;
170
171     PARSER_STATUS_CHECK(HDR);
172     e = APR_BRIGADE_LAST(ctx->bb);
173     APR_BRIGADE_CONCAT(ctx->bb, bb);
174
175  parse_hdr_brigade:
176
177
178     /* parse the brigade for CRLF_CRLF-terminated header block,
179      * each time starting from the front of the brigade.
180      */
181
182     for (e = APR_BUCKET_NEXT(e);
183          e != APR_BRIGADE_SENTINEL(ctx->bb);
184          e = APR_BUCKET_NEXT(e))
185     {
186         apr_size_t off = 0, dlen;
187         const char *data;
188         apr_status_t s;
189         apreq_param_t *param = NULL; /* silences gcc-4.0 warning */
190
191         if (APR_BUCKET_IS_EOS(e)) {
192             ctx->status = HDR_COMPLETE;
193             APR_BRIGADE_CONCAT(bb, ctx->bb);
194             return APR_SUCCESS;
195         }
196         s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
197
198         if ( s != APR_SUCCESS ) {
199             ctx->status = HDR_ERROR;
200             return s;
201         }
202         if (dlen == 0)
203             continue;
204
205     parse_hdr_bucket:
206
207         /*              gap           nlen = 13
208          *              vvv           glen =  3
209          * Sample-Header:  grape      vlen =  5
210          * ^^^^^^^^^^^^^   ^^^^^
211          *     name        value
212          */
213
214         switch (ctx->status) {
215
216         case HDR_NAME:
217
218             while (off < dlen) {
219                 switch (data[off++]) {
220
221                 case '\n':
222                     if (off < dlen)
223                         apr_bucket_split(e, off);
224                     e = APR_BUCKET_NEXT(e);
225
226                     do {
227                         apr_bucket *f = APR_BRIGADE_FIRST(ctx->bb);
228                         apr_bucket_delete(f);
229                     } while (e != APR_BRIGADE_FIRST(ctx->bb));
230                     APR_BRIGADE_CONCAT(bb, ctx->bb);
231                     ctx->status = HDR_COMPLETE;
232                     return APR_SUCCESS;
233
234                 case ':':
235                     if (off > 1) {
236                         apr_bucket_split(e, off - 1);
237                         dlen -= off - 1;
238                         data += off - 1;
239                         off = 1;
240                         e = APR_BUCKET_NEXT(e);
241                     }
242                     ++ctx->glen;
243                     ctx->status = HDR_GAP;
244                     goto parse_hdr_bucket;
245
246                 default:
247                     ++ctx->nlen;
248                 }
249
250             }
251
252             break;
253
254
255         case HDR_GAP:
256
257             while (off < dlen) {
258                 switch (data[off++]) {
259                 case ' ':
260                 case '\t':
261                     ++ctx->glen;
262                     break;
263
264                 case '\n':
265                     ctx->status = HDR_NEWLINE;
266                     goto parse_hdr_bucket;
267
268                 default:
269                     ctx->status = HDR_VALUE;
270                     if (off > 1) {
271                         apr_bucket_split(e, off - 1);
272                         dlen -= off - 1;
273                         data += off - 1;
274                         off = 1;
275                         e = APR_BUCKET_NEXT(e);
276                     }
277                     ++ctx->vlen;
278                     goto parse_hdr_bucket;
279                 }
280             }
281             break;
282
283
284         case HDR_VALUE:
285
286             while (off < dlen) {
287                 ++ctx->vlen;
288                 if (data[off++] == '\n') {
289                     ctx->status = HDR_NEWLINE;
290                     goto parse_hdr_bucket;
291                 }
292             }
293             break;
294
295
296         case HDR_NEWLINE:
297
298             if (off == dlen)
299                 break;
300             else {
301                 switch (data[off]) {
302
303                 case ' ':
304                 case '\t':
305                     ctx->status = HDR_CONTINUE;
306                     ++off;
307                     ++ctx->vlen;
308                     break;
309
310                 default:
311                     /* can parse brigade now */
312                     if (off > 0)
313                         apr_bucket_split(e, off);
314                     s = split_header_line(&param, pool, ctx->bb, ctx->nlen, ctx->glen, ctx->vlen);
315                     if (parser->hook != NULL && s == APR_SUCCESS)
316                         s = apreq_hook_run(parser->hook, param, NULL);
317
318                     if (s != APR_SUCCESS) {
319                         ctx->status = HDR_ERROR;
320                         return s;
321                     }
322
323                     apreq_value_table_add(&param->v, t);
324                     e = APR_BRIGADE_SENTINEL(ctx->bb);
325                     ctx->status = HDR_NAME;
326                     ctx->nlen = 0;
327                     ctx->vlen = 0;
328                     ctx->glen = 0;
329
330                     goto parse_hdr_brigade;
331                 }
332
333                 /* cases ' ', '\t' fall through to HDR_CONTINUE */
334             }
335
336
337         case HDR_CONTINUE:
338
339             while (off < dlen) {
340                 switch (data[off++]) {
341                 case ' ':
342                 case '\t':
343                     ++ctx->vlen;
344                     break;
345
346                 case '\n':
347                     ctx->status = HDR_NEWLINE;
348                     goto parse_hdr_bucket;
349
350                 default:
351                     ctx->status = HDR_VALUE;
352                     ++ctx->vlen;
353                     goto parse_hdr_bucket;
354                 }
355             }
356             break;
357
358         default:
359             ; /* not reached */
360         }
361     }
362     apreq_brigade_setaside(ctx->bb,pool);
363     return APR_INCOMPLETE;
364 }