source: EcnlProtoTool/trunk/prototool/webserver/http_parser.c@ 270

Last change on this file since 270 was 270, checked in by coas-nagasima, 7 years ago

mruby版ECNLプロトタイピング・ツールを追加

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-csrc
File size: 68.0 KB
Line 
1/* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev
2 *
3 * Additional changes are licensed under the same terms as NGINX and
4 * copyright Joyent, Inc. and other Node contributors. All rights reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 */
24#include "http_parser.h"
25//#include <assert.h>
26#include <stddef.h>
27#include <ctype.h>
28#include <stdlib.h>
29#include <string.h>
30#include <limits.h>
31
32#ifndef ULLONG_MAX
33# define ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */
34#endif
35
36#ifndef MIN
37# define MIN(a,b) ((a) < (b) ? (a) : (b))
38#endif
39
40#ifndef ARRAY_SIZE
41# define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
42#endif
43
44#ifndef BIT_AT
45# define BIT_AT(a, i) \
46 (!!((unsigned int) (a)[(unsigned int) (i) >> 3] & \
47 (1 << ((unsigned int) (i) & 7))))
48#endif
49
50#ifndef ELEM_AT
51# define ELEM_AT(a, i, v) ((unsigned int) (i) < ARRAY_SIZE(a) ? (a)[(i)] : (v))
52#endif
53
54#define SET_ERRNO(e) \
55do { \
56 parser->http_errno = (e); \
57} while(0)
58
59#define CURRENT_STATE() p_state
60#define UPDATE_STATE(V) p_state = (enum state) (V);
61#define RETURN(V) \
62do { \
63 parser->state = CURRENT_STATE(); \
64 return (V); \
65} while (0);
66#define REEXECUTE() \
67 --p; \
68 break;
69
70
71#ifdef __GNUC__
72# define LIKELY(X) __builtin_expect(!!(X), 1)
73# define UNLIKELY(X) __builtin_expect(!!(X), 0)
74#else
75# define LIKELY(X) (X)
76# define UNLIKELY(X) (X)
77#endif
78
79
80/* Run the notify callback FOR, returning ER if it fails */
81#define CALLBACK_NOTIFY_(FOR, ER) \
82do { \
83 assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \
84 \
85 if (LIKELY(settings->on_##FOR)) { \
86 parser->state = CURRENT_STATE(); \
87 if (UNLIKELY(0 != settings->on_##FOR(parser))) { \
88 SET_ERRNO(HPE_CB_##FOR); \
89 } \
90 UPDATE_STATE(parser->state); \
91 \
92 /* We either errored above or got paused; get out */ \
93 if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) { \
94 return (ER); \
95 } \
96 } \
97} while (0)
98
99/* Run the notify callback FOR and consume the current byte */
100#define CALLBACK_NOTIFY(FOR) CALLBACK_NOTIFY_(FOR, p - data + 1)
101
102/* Run the notify callback FOR and don't consume the current byte */
103#define CALLBACK_NOTIFY_NOADVANCE(FOR) CALLBACK_NOTIFY_(FOR, p - data)
104
105/* Run data callback FOR with LEN bytes, returning ER if it fails */
106#define CALLBACK_DATA_(FOR, LEN, ER) \
107do { \
108 assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \
109 \
110 if (FOR##_mark) { \
111 if (LIKELY(settings->on_##FOR)) { \
112 parser->state = CURRENT_STATE(); \
113 if (UNLIKELY(0 != \
114 settings->on_##FOR(parser, FOR##_mark, (LEN)))) { \
115 SET_ERRNO(HPE_CB_##FOR); \
116 } \
117 UPDATE_STATE(parser->state); \
118 \
119 /* We either errored above or got paused; get out */ \
120 if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) { \
121 return (ER); \
122 } \
123 } \
124 FOR##_mark = NULL; \
125 } \
126} while (0)
127
128/* Run the data callback FOR and consume the current byte */
129#define CALLBACK_DATA(FOR) \
130 CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1)
131
132/* Run the data callback FOR and don't consume the current byte */
133#define CALLBACK_DATA_NOADVANCE(FOR) \
134 CALLBACK_DATA_(FOR, p - FOR##_mark, p - data)
135
136/* Set the mark FOR; non-destructive if mark is already set */
137#define MARK(FOR) \
138do { \
139 if (!FOR##_mark) { \
140 FOR##_mark = p; \
141 } \
142} while (0)
143
144/* Don't allow the total size of the HTTP headers (including the status
145 * line) to exceed HTTP_MAX_HEADER_SIZE. This check is here to protect
146 * embedders against denial-of-service attacks where the attacker feeds
147 * us a never-ending header that the embedder keeps buffering.
148 *
149 * This check is arguably the responsibility of embedders but we're doing
150 * it on the embedder's behalf because most won't bother and this way we
151 * make the web a little safer. HTTP_MAX_HEADER_SIZE is still far bigger
152 * than any reasonable request or response so this should never affect
153 * day-to-day operation.
154 */
155#define COUNT_HEADER_SIZE(V) \
156do { \
157 parser->nread += (V); \
158 if (UNLIKELY(parser->nread > (HTTP_MAX_HEADER_SIZE))) { \
159 SET_ERRNO(HPE_HEADER_OVERFLOW); \
160 goto error; \
161 } \
162} while (0)
163
164
165#define PROXY_CONNECTION "proxy-connection"
166#define CONNECTION "connection"
167#define CONTENT_LENGTH "content-length"
168#define TRANSFER_ENCODING "transfer-encoding"
169#define UPGRADE "upgrade"
170#define CHUNKED "chunked"
171#define KEEP_ALIVE "keep-alive"
172#define CLOSE "close"
173
174
175static const char *method_strings[] =
176 {
177#define XX(num, name, string) #string,
178 HTTP_METHOD_MAP(XX)
179#undef XX
180 };
181
182
183/* Tokens as defined by rfc 2616. Also lowercases them.
184 * token = 1*<any CHAR except CTLs or separators>
185 * separators = "(" | ")" | "<" | ">" | "@"
186 * | "," | ";" | ":" | "\" | <">
187 * | "/" | "[" | "]" | "?" | "="
188 * | "{" | "}" | SP | HT
189 */
190static const char tokens[256] = {
191/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */
192 0, 0, 0, 0, 0, 0, 0, 0,
193/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */
194 0, 0, 0, 0, 0, 0, 0, 0,
195/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */
196 0, 0, 0, 0, 0, 0, 0, 0,
197/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */
198 0, 0, 0, 0, 0, 0, 0, 0,
199/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */
200 0, '!', 0, '#', '$', '%', '&', '\'',
201/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */
202 0, 0, '*', '+', 0, '-', '.', 0,
203/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */
204 '0', '1', '2', '3', '4', '5', '6', '7',
205/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */
206 '8', '9', 0, 0, 0, 0, 0, 0,
207/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */
208 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
209/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */
210 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
211/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */
212 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
213/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */
214 'x', 'y', 'z', 0, 0, 0, '^', '_',
215/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */
216 '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
217/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */
218 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
219/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
220 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
221/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
222 'x', 'y', 'z', 0, '|', 0, '~', 0 };
223
224
225static const int8_t unhex[256] =
226 {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
227 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
228 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
229 , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1
230 ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
231 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
232 ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
233 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
234 };
235
236
237#if HTTP_PARSER_STRICT
238# define T(v) 0
239#else
240# define T(v) v
241#endif
242
243
244static const uint8_t normal_url_char[32] = {
245/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */
246 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
247/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */
248 0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0,
249/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */
250 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
251/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */
252 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
253/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */
254 0 | 2 | 4 | 0 | 16 | 32 | 64 | 128,
255/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */
256 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
257/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */
258 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
259/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */
260 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0,
261/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */
262 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
263/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */
264 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
265/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */
266 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
267/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */
268 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
269/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */
270 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
271/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */
272 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
273/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
274 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
275/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
276 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, };
277
278#undef T
279
280enum state
281 { s_dead = 1 /* important that this is > 0 */
282
283 , s_start_req_or_res
284 , s_res_or_resp_H
285 , s_start_res
286 , s_res_H
287 , s_res_HT
288 , s_res_HTT
289 , s_res_HTTP
290 , s_res_first_http_major
291 , s_res_http_major
292 , s_res_first_http_minor
293 , s_res_http_minor
294 , s_res_first_status_code
295 , s_res_status_code
296 , s_res_status_start
297 , s_res_status
298 , s_res_line_almost_done
299
300 , s_start_req
301
302 , s_req_method
303 , s_req_spaces_before_url
304 , s_req_schema
305 , s_req_schema_slash
306 , s_req_schema_slash_slash
307 , s_req_server_start
308 , s_req_server
309 , s_req_server_with_at
310 , s_req_path
311 , s_req_query_string_start
312 , s_req_query_string
313 , s_req_fragment_start
314 , s_req_fragment
315 , s_req_http_start
316 , s_req_http_H
317 , s_req_http_HT
318 , s_req_http_HTT
319 , s_req_http_HTTP
320 , s_req_first_http_major
321 , s_req_http_major
322 , s_req_first_http_minor
323 , s_req_http_minor
324 , s_req_line_almost_done
325
326 , s_header_field_start
327 , s_header_field
328 , s_header_value_discard_ws
329 , s_header_value_discard_ws_almost_done
330 , s_header_value_discard_lws
331 , s_header_value_start
332 , s_header_value
333 , s_header_value_lws
334
335 , s_header_almost_done
336
337 , s_chunk_size_start
338 , s_chunk_size
339 , s_chunk_parameters
340 , s_chunk_size_almost_done
341
342 , s_headers_almost_done
343 , s_headers_done
344
345 /* Important: 's_headers_done' must be the last 'header' state. All
346 * states beyond this must be 'body' states. It is used for overflow
347 * checking. See the PARSING_HEADER() macro.
348 */
349
350 , s_chunk_data
351 , s_chunk_data_almost_done
352 , s_chunk_data_done
353
354 , s_body_identity
355 , s_body_identity_eof
356
357 , s_message_done
358 };
359
360
361#define PARSING_HEADER(state) (state <= s_headers_done)
362
363
364enum header_states
365 { h_general = 0
366 , h_C
367 , h_CO
368 , h_CON
369
370 , h_matching_connection
371 , h_matching_proxy_connection
372 , h_matching_content_length
373 , h_matching_transfer_encoding
374 , h_matching_upgrade
375
376 , h_connection
377 , h_content_length
378 , h_transfer_encoding
379 , h_upgrade
380
381 , h_matching_transfer_encoding_chunked
382 , h_matching_connection_token_start
383 , h_matching_connection_keep_alive
384 , h_matching_connection_close
385 , h_matching_connection_upgrade
386 , h_matching_connection_token
387
388 , h_transfer_encoding_chunked
389 , h_connection_keep_alive
390 , h_connection_close
391 , h_connection_upgrade
392 };
393
394enum http_host_state
395 {
396 s_http_host_dead = 1
397 , s_http_userinfo_start
398 , s_http_userinfo
399 , s_http_host_start
400 , s_http_host_v6_start
401 , s_http_host
402 , s_http_host_v6
403 , s_http_host_v6_end
404 , s_http_host_port_start
405 , s_http_host_port
406};
407
408/* Macros for character classes; depends on strict-mode */
409#define CR '\r'
410#define LF '\n'
411#define LOWER(c) (unsigned char)(c | 0x20)
412#define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z')
413#define IS_NUM(c) ((c) >= '0' && (c) <= '9')
414#define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c))
415#define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f'))
416#define IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || \
417 (c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' || \
418 (c) == ')')
419#define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || \
420 (c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \
421 (c) == '$' || (c) == ',')
422
423#define STRICT_TOKEN(c) (tokens[(unsigned char)c])
424
425#if HTTP_PARSER_STRICT
426#define TOKEN(c) (tokens[(unsigned char)c])
427#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c))
428#define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-')
429#else
430#define TOKEN(c) ((c == ' ') ? ' ' : tokens[(unsigned char)c])
431#define IS_URL_CHAR(c) \
432 (BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80))
433#define IS_HOST_CHAR(c) \
434 (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_')
435#endif
436
437
438#define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res)
439
440
441#if HTTP_PARSER_STRICT
442# define STRICT_CHECK(cond) \
443do { \
444 if (cond) { \
445 SET_ERRNO(HPE_STRICT); \
446 goto error; \
447 } \
448} while (0)
449# define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead)
450#else
451# define STRICT_CHECK(cond)
452# define NEW_MESSAGE() start_state
453#endif
454
455
456/* Map errno values to strings for human-readable output */
457#define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s },
458static struct {
459 const char *name;
460 const char *description;
461} http_strerror_tab[] = {
462 HTTP_ERRNO_MAP(HTTP_STRERROR_GEN)
463};
464#undef HTTP_STRERROR_GEN
465
466int http_message_needs_eof(const http_parser *parser);
467
468/* Our URL parser.
469 *
470 * This is designed to be shared by http_parser_execute() for URL validation,
471 * hence it has a state transition + byte-for-byte interface. In addition, it
472 * is meant to be embedded in http_parser_parse_url(), which does the dirty
473 * work of turning state transitions URL components for its API.
474 *
475 * This function should only be invoked with non-space characters. It is
476 * assumed that the caller cares about (and can detect) the transition between
477 * URL and non-URL states by looking for these.
478 */
479static enum state
480parse_url_char(enum state s, const char ch)
481{
482 if (ch == ' ' || ch == '\r' || ch == '\n') {
483 return s_dead;
484 }
485
486#if HTTP_PARSER_STRICT
487 if (ch == '\t' || ch == '\f') {
488 return s_dead;
489 }
490#endif
491
492 switch (s) {
493 case s_req_spaces_before_url:
494 /* Proxied requests are followed by scheme of an absolute URI (alpha).
495 * All methods except CONNECT are followed by '/' or '*'.
496 */
497
498 if (ch == '/' || ch == '*') {
499 return s_req_path;
500 }
501
502 if (IS_ALPHA(ch)) {
503 return s_req_schema;
504 }
505
506 break;
507
508 case s_req_schema:
509 if (IS_ALPHA(ch)) {
510 return s;
511 }
512
513 if (ch == ':') {
514 return s_req_schema_slash;
515 }
516
517 break;
518
519 case s_req_schema_slash:
520 if (ch == '/') {
521 return s_req_schema_slash_slash;
522 }
523
524 break;
525
526 case s_req_schema_slash_slash:
527 if (ch == '/') {
528 return s_req_server_start;
529 }
530
531 break;
532
533 case s_req_server_with_at:
534 if (ch == '@') {
535 return s_dead;
536 }
537
538 /* FALLTHROUGH */
539 case s_req_server_start:
540 case s_req_server:
541 if (ch == '/') {
542 return s_req_path;
543 }
544
545 if (ch == '?') {
546 return s_req_query_string_start;
547 }
548
549 if (ch == '@') {
550 return s_req_server_with_at;
551 }
552
553 if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') {
554 return s_req_server;
555 }
556
557 break;
558
559 case s_req_path:
560 if (IS_URL_CHAR(ch)) {
561 return s;
562 }
563
564 switch (ch) {
565 case '?':
566 return s_req_query_string_start;
567
568 case '#':
569 return s_req_fragment_start;
570 }
571
572 break;
573
574 case s_req_query_string_start:
575 case s_req_query_string:
576 if (IS_URL_CHAR(ch)) {
577 return s_req_query_string;
578 }
579
580 switch (ch) {
581 case '?':
582 /* allow extra '?' in query string */
583 return s_req_query_string;
584
585 case '#':
586 return s_req_fragment_start;
587 }
588
589 break;
590
591 case s_req_fragment_start:
592 if (IS_URL_CHAR(ch)) {
593 return s_req_fragment;
594 }
595
596 switch (ch) {
597 case '?':
598 return s_req_fragment;
599
600 case '#':
601 return s;
602 }
603
604 break;
605
606 case s_req_fragment:
607 if (IS_URL_CHAR(ch)) {
608 return s;
609 }
610
611 switch (ch) {
612 case '?':
613 case '#':
614 return s;
615 }
616
617 break;
618
619 default:
620 break;
621 }
622
623 /* We should never fall out of the switch above unless there's an error */
624 return s_dead;
625}
626
627size_t http_parser_execute (http_parser *parser,
628 const http_parser_settings *settings,
629 const char *data,
630 size_t len)
631{
632 char c, ch;
633 int8_t unhex_val;
634 const char *p = data;
635 const char *header_field_mark = 0;
636 const char *header_value_mark = 0;
637 const char *url_mark = 0;
638 const char *body_mark = 0;
639 const char *status_mark = 0;
640 enum state p_state = (enum state) parser->state;
641
642 /* We're in an error state. Don't bother doing anything. */
643 if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
644 return 0;
645 }
646
647 if (len == 0) {
648 switch (CURRENT_STATE()) {
649 case s_body_identity_eof:
650 /* Use of CALLBACK_NOTIFY() here would erroneously return 1 byte read if
651 * we got paused.
652 */
653 CALLBACK_NOTIFY_NOADVANCE(message_complete);
654 return 0;
655
656 case s_dead:
657 case s_start_req_or_res:
658 case s_start_res:
659 case s_start_req:
660 return 0;
661
662 default:
663 SET_ERRNO(HPE_INVALID_EOF_STATE);
664 return 1;
665 }
666 }
667
668
669 if (CURRENT_STATE() == s_header_field)
670 header_field_mark = data;
671 if (CURRENT_STATE() == s_header_value)
672 header_value_mark = data;
673 switch (CURRENT_STATE()) {
674 case s_req_path:
675 case s_req_schema:
676 case s_req_schema_slash:
677 case s_req_schema_slash_slash:
678 case s_req_server_start:
679 case s_req_server:
680 case s_req_server_with_at:
681 case s_req_query_string_start:
682 case s_req_query_string:
683 case s_req_fragment_start:
684 case s_req_fragment:
685 url_mark = data;
686 break;
687 case s_res_status:
688 status_mark = data;
689 break;
690 default:
691 break;
692 }
693
694 for (p=data; p != data + len; p++) {
695 ch = *p;
696
697 if (PARSING_HEADER(CURRENT_STATE()))
698 COUNT_HEADER_SIZE(1);
699
700 switch (CURRENT_STATE()) {
701
702 case s_dead:
703 /* this state is used after a 'Connection: close' message
704 * the parser will error out if it reads another message
705 */
706 if (LIKELY(ch == CR || ch == LF))
707 break;
708
709 SET_ERRNO(HPE_CLOSED_CONNECTION);
710 goto error;
711
712 case s_start_req_or_res:
713 {
714 if (ch == CR || ch == LF)
715 break;
716 parser->flags = 0;
717 parser->content_length = ULLONG_MAX;
718
719 if (ch == 'H') {
720 UPDATE_STATE(s_res_or_resp_H);
721
722 CALLBACK_NOTIFY(message_begin);
723 } else {
724 parser->type = HTTP_REQUEST;
725 UPDATE_STATE(s_start_req);
726 REEXECUTE();
727 }
728
729 break;
730 }
731
732 case s_res_or_resp_H:
733 if (ch == 'T') {
734 parser->type = HTTP_RESPONSE;
735 UPDATE_STATE(s_res_HT);
736 } else {
737 if (UNLIKELY(ch != 'E')) {
738 SET_ERRNO(HPE_INVALID_CONSTANT);
739 goto error;
740 }
741
742 parser->type = HTTP_REQUEST;
743 parser->method = HTTP_HEAD;
744 parser->index = 2;
745 UPDATE_STATE(s_req_method);
746 }
747 break;
748
749 case s_start_res:
750 {
751 parser->flags = 0;
752 parser->content_length = ULLONG_MAX;
753
754 switch (ch) {
755 case 'H':
756 UPDATE_STATE(s_res_H);
757 break;
758
759 case CR:
760 case LF:
761 break;
762
763 default:
764 SET_ERRNO(HPE_INVALID_CONSTANT);
765 goto error;
766 }
767
768 CALLBACK_NOTIFY(message_begin);
769 break;
770 }
771
772 case s_res_H:
773 STRICT_CHECK(ch != 'T');
774 UPDATE_STATE(s_res_HT);
775 break;
776
777 case s_res_HT:
778 STRICT_CHECK(ch != 'T');
779 UPDATE_STATE(s_res_HTT);
780 break;
781
782 case s_res_HTT:
783 STRICT_CHECK(ch != 'P');
784 UPDATE_STATE(s_res_HTTP);
785 break;
786
787 case s_res_HTTP:
788 STRICT_CHECK(ch != '/');
789 UPDATE_STATE(s_res_first_http_major);
790 break;
791
792 case s_res_first_http_major:
793 if (UNLIKELY(ch < '0' || ch > '9')) {
794 SET_ERRNO(HPE_INVALID_VERSION);
795 goto error;
796 }
797
798 parser->http_major = ch - '0';
799 UPDATE_STATE(s_res_http_major);
800 break;
801
802 /* major HTTP version or dot */
803 case s_res_http_major:
804 {
805 if (ch == '.') {
806 UPDATE_STATE(s_res_first_http_minor);
807 break;
808 }
809
810 if (!IS_NUM(ch)) {
811 SET_ERRNO(HPE_INVALID_VERSION);
812 goto error;
813 }
814
815 parser->http_major *= 10;
816 parser->http_major += ch - '0';
817
818 if (UNLIKELY(parser->http_major > 999)) {
819 SET_ERRNO(HPE_INVALID_VERSION);
820 goto error;
821 }
822
823 break;
824 }
825
826 /* first digit of minor HTTP version */
827 case s_res_first_http_minor:
828 if (UNLIKELY(!IS_NUM(ch))) {
829 SET_ERRNO(HPE_INVALID_VERSION);
830 goto error;
831 }
832
833 parser->http_minor = ch - '0';
834 UPDATE_STATE(s_res_http_minor);
835 break;
836
837 /* minor HTTP version or end of request line */
838 case s_res_http_minor:
839 {
840 if (ch == ' ') {
841 UPDATE_STATE(s_res_first_status_code);
842 break;
843 }
844
845 if (UNLIKELY(!IS_NUM(ch))) {
846 SET_ERRNO(HPE_INVALID_VERSION);
847 goto error;
848 }
849
850 parser->http_minor *= 10;
851 parser->http_minor += ch - '0';
852
853 if (UNLIKELY(parser->http_minor > 999)) {
854 SET_ERRNO(HPE_INVALID_VERSION);
855 goto error;
856 }
857
858 break;
859 }
860
861 case s_res_first_status_code:
862 {
863 if (!IS_NUM(ch)) {
864 if (ch == ' ') {
865 break;
866 }
867
868 SET_ERRNO(HPE_INVALID_STATUS);
869 goto error;
870 }
871 parser->status_code = ch - '0';
872 UPDATE_STATE(s_res_status_code);
873 break;
874 }
875
876 case s_res_status_code:
877 {
878 if (!IS_NUM(ch)) {
879 switch (ch) {
880 case ' ':
881 UPDATE_STATE(s_res_status_start);
882 break;
883 case CR:
884 UPDATE_STATE(s_res_line_almost_done);
885 break;
886 case LF:
887 UPDATE_STATE(s_header_field_start);
888 break;
889 default:
890 SET_ERRNO(HPE_INVALID_STATUS);
891 goto error;
892 }
893 break;
894 }
895
896 parser->status_code *= 10;
897 parser->status_code += ch - '0';
898
899 if (UNLIKELY(parser->status_code > 999)) {
900 SET_ERRNO(HPE_INVALID_STATUS);
901 goto error;
902 }
903
904 break;
905 }
906
907 case s_res_status_start:
908 {
909 if (ch == CR) {
910 UPDATE_STATE(s_res_line_almost_done);
911 break;
912 }
913
914 if (ch == LF) {
915 UPDATE_STATE(s_header_field_start);
916 break;
917 }
918
919 MARK(status);
920 UPDATE_STATE(s_res_status);
921 parser->index = 0;
922 break;
923 }
924
925 case s_res_status:
926 if (ch == CR) {
927 UPDATE_STATE(s_res_line_almost_done);
928 CALLBACK_DATA(status);
929 break;
930 }
931
932 if (ch == LF) {
933 UPDATE_STATE(s_header_field_start);
934 CALLBACK_DATA(status);
935 break;
936 }
937
938 break;
939
940 case s_res_line_almost_done:
941 STRICT_CHECK(ch != LF);
942 UPDATE_STATE(s_header_field_start);
943 break;
944
945 case s_start_req:
946 {
947 if (ch == CR || ch == LF)
948 break;
949 parser->flags = 0;
950 parser->content_length = ULLONG_MAX;
951
952 if (UNLIKELY(!IS_ALPHA(ch))) {
953 SET_ERRNO(HPE_INVALID_METHOD);
954 goto error;
955 }
956
957 parser->method = (enum http_method) 0;
958 parser->index = 1;
959 switch (ch) {
960 case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break;
961 case 'D': parser->method = HTTP_DELETE; break;
962 case 'G': parser->method = HTTP_GET; break;
963 case 'H': parser->method = HTTP_HEAD; break;
964 case 'L': parser->method = HTTP_LOCK; break;
965 case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH, MKCALENDAR */ break;
966 case 'N': parser->method = HTTP_NOTIFY; break;
967 case 'O': parser->method = HTTP_OPTIONS; break;
968 case 'P': parser->method = HTTP_POST;
969 /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */
970 break;
971 case 'R': parser->method = HTTP_REPORT; break;
972 case 'S': parser->method = HTTP_SUBSCRIBE; /* or SEARCH */ break;
973 case 'T': parser->method = HTTP_TRACE; break;
974 case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE */ break;
975 default:
976 SET_ERRNO(HPE_INVALID_METHOD);
977 goto error;
978 }
979 UPDATE_STATE(s_req_method);
980
981 CALLBACK_NOTIFY(message_begin);
982
983 break;
984 }
985
986 case s_req_method:
987 {
988 const char *matcher;
989 if (UNLIKELY(ch == '\0')) {
990 SET_ERRNO(HPE_INVALID_METHOD);
991 goto error;
992 }
993
994 matcher = method_strings[parser->method];
995 if (ch == ' ' && matcher[parser->index] == '\0') {
996 UPDATE_STATE(s_req_spaces_before_url);
997 } else if (ch == matcher[parser->index]) {
998 ; /* nada */
999 } else if (parser->method == HTTP_CONNECT) {
1000 if (parser->index == 1 && ch == 'H') {
1001 parser->method = HTTP_CHECKOUT;
1002 } else if (parser->index == 2 && ch == 'P') {
1003 parser->method = HTTP_COPY;
1004 } else {
1005 SET_ERRNO(HPE_INVALID_METHOD);
1006 goto error;
1007 }
1008 } else if (parser->method == HTTP_MKCOL) {
1009 if (parser->index == 1 && ch == 'O') {
1010 parser->method = HTTP_MOVE;
1011 } else if (parser->index == 1 && ch == 'E') {
1012 parser->method = HTTP_MERGE;
1013 } else if (parser->index == 1 && ch == '-') {
1014 parser->method = HTTP_MSEARCH;
1015 } else if (parser->index == 2 && ch == 'A') {
1016 parser->method = HTTP_MKACTIVITY;
1017 } else if (parser->index == 3 && ch == 'A') {
1018 parser->method = HTTP_MKCALENDAR;
1019 } else {
1020 SET_ERRNO(HPE_INVALID_METHOD);
1021 goto error;
1022 }
1023 } else if (parser->method == HTTP_SUBSCRIBE) {
1024 if (parser->index == 1 && ch == 'E') {
1025 parser->method = HTTP_SEARCH;
1026 } else {
1027 SET_ERRNO(HPE_INVALID_METHOD);
1028 goto error;
1029 }
1030 } else if (parser->index == 1 && parser->method == HTTP_POST) {
1031 if (ch == 'R') {
1032 parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */
1033 } else if (ch == 'U') {
1034 parser->method = HTTP_PUT; /* or HTTP_PURGE */
1035 } else if (ch == 'A') {
1036 parser->method = HTTP_PATCH;
1037 } else {
1038 SET_ERRNO(HPE_INVALID_METHOD);
1039 goto error;
1040 }
1041 } else if (parser->index == 2) {
1042 if (parser->method == HTTP_PUT) {
1043 if (ch == 'R') {
1044 parser->method = HTTP_PURGE;
1045 } else {
1046 SET_ERRNO(HPE_INVALID_METHOD);
1047 goto error;
1048 }
1049 } else if (parser->method == HTTP_UNLOCK) {
1050 if (ch == 'S') {
1051 parser->method = HTTP_UNSUBSCRIBE;
1052 } else {
1053 SET_ERRNO(HPE_INVALID_METHOD);
1054 goto error;
1055 }
1056 } else {
1057 SET_ERRNO(HPE_INVALID_METHOD);
1058 goto error;
1059 }
1060 } else if (parser->index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') {
1061 parser->method = HTTP_PROPPATCH;
1062 } else {
1063 SET_ERRNO(HPE_INVALID_METHOD);
1064 goto error;
1065 }
1066
1067 ++parser->index;
1068 break;
1069 }
1070
1071 case s_req_spaces_before_url:
1072 {
1073 if (ch == ' ') break;
1074
1075 MARK(url);
1076 if (parser->method == HTTP_CONNECT) {
1077 UPDATE_STATE(s_req_server_start);
1078 }
1079
1080 UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch));
1081 if (UNLIKELY(CURRENT_STATE() == s_dead)) {
1082 SET_ERRNO(HPE_INVALID_URL);
1083 goto error;
1084 }
1085
1086 break;
1087 }
1088
1089 case s_req_schema:
1090 case s_req_schema_slash:
1091 case s_req_schema_slash_slash:
1092 case s_req_server_start:
1093 {
1094 switch (ch) {
1095 /* No whitespace allowed here */
1096 case ' ':
1097 case CR:
1098 case LF:
1099 SET_ERRNO(HPE_INVALID_URL);
1100 goto error;
1101 default:
1102 UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch));
1103 if (UNLIKELY(CURRENT_STATE() == s_dead)) {
1104 SET_ERRNO(HPE_INVALID_URL);
1105 goto error;
1106 }
1107 }
1108
1109 break;
1110 }
1111
1112 case s_req_server:
1113 case s_req_server_with_at:
1114 case s_req_path:
1115 case s_req_query_string_start:
1116 case s_req_query_string:
1117 case s_req_fragment_start:
1118 case s_req_fragment:
1119 {
1120 switch (ch) {
1121 case ' ':
1122 UPDATE_STATE(s_req_http_start);
1123 CALLBACK_DATA(url);
1124 break;
1125 case CR:
1126 case LF:
1127 parser->http_major = 0;
1128 parser->http_minor = 9;
1129 UPDATE_STATE((ch == CR) ?
1130 s_req_line_almost_done :
1131 s_header_field_start);
1132 CALLBACK_DATA(url);
1133 break;
1134 default:
1135 UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch));
1136 if (UNLIKELY(CURRENT_STATE() == s_dead)) {
1137 SET_ERRNO(HPE_INVALID_URL);
1138 goto error;
1139 }
1140 }
1141 break;
1142 }
1143
1144 case s_req_http_start:
1145 switch (ch) {
1146 case 'H':
1147 UPDATE_STATE(s_req_http_H);
1148 break;
1149 case ' ':
1150 break;
1151 default:
1152 SET_ERRNO(HPE_INVALID_CONSTANT);
1153 goto error;
1154 }
1155 break;
1156
1157 case s_req_http_H:
1158 STRICT_CHECK(ch != 'T');
1159 UPDATE_STATE(s_req_http_HT);
1160 break;
1161
1162 case s_req_http_HT:
1163 STRICT_CHECK(ch != 'T');
1164 UPDATE_STATE(s_req_http_HTT);
1165 break;
1166
1167 case s_req_http_HTT:
1168 STRICT_CHECK(ch != 'P');
1169 UPDATE_STATE(s_req_http_HTTP);
1170 break;
1171
1172 case s_req_http_HTTP:
1173 STRICT_CHECK(ch != '/');
1174 UPDATE_STATE(s_req_first_http_major);
1175 break;
1176
1177 /* first digit of major HTTP version */
1178 case s_req_first_http_major:
1179 if (UNLIKELY(ch < '1' || ch > '9')) {
1180 SET_ERRNO(HPE_INVALID_VERSION);
1181 goto error;
1182 }
1183
1184 parser->http_major = ch - '0';
1185 UPDATE_STATE(s_req_http_major);
1186 break;
1187
1188 /* major HTTP version or dot */
1189 case s_req_http_major:
1190 {
1191 if (ch == '.') {
1192 UPDATE_STATE(s_req_first_http_minor);
1193 break;
1194 }
1195
1196 if (UNLIKELY(!IS_NUM(ch))) {
1197 SET_ERRNO(HPE_INVALID_VERSION);
1198 goto error;
1199 }
1200
1201 parser->http_major *= 10;
1202 parser->http_major += ch - '0';
1203
1204 if (UNLIKELY(parser->http_major > 999)) {
1205 SET_ERRNO(HPE_INVALID_VERSION);
1206 goto error;
1207 }
1208
1209 break;
1210 }
1211
1212 /* first digit of minor HTTP version */
1213 case s_req_first_http_minor:
1214 if (UNLIKELY(!IS_NUM(ch))) {
1215 SET_ERRNO(HPE_INVALID_VERSION);
1216 goto error;
1217 }
1218
1219 parser->http_minor = ch - '0';
1220 UPDATE_STATE(s_req_http_minor);
1221 break;
1222
1223 /* minor HTTP version or end of request line */
1224 case s_req_http_minor:
1225 {
1226 if (ch == CR) {
1227 UPDATE_STATE(s_req_line_almost_done);
1228 break;
1229 }
1230
1231 if (ch == LF) {
1232 UPDATE_STATE(s_header_field_start);
1233 break;
1234 }
1235
1236 /* XXX allow spaces after digit? */
1237
1238 if (UNLIKELY(!IS_NUM(ch))) {
1239 SET_ERRNO(HPE_INVALID_VERSION);
1240 goto error;
1241 }
1242
1243 parser->http_minor *= 10;
1244 parser->http_minor += ch - '0';
1245
1246 if (UNLIKELY(parser->http_minor > 999)) {
1247 SET_ERRNO(HPE_INVALID_VERSION);
1248 goto error;
1249 }
1250
1251 break;
1252 }
1253
1254 /* end of request line */
1255 case s_req_line_almost_done:
1256 {
1257 if (UNLIKELY(ch != LF)) {
1258 SET_ERRNO(HPE_LF_EXPECTED);
1259 goto error;
1260 }
1261
1262 UPDATE_STATE(s_header_field_start);
1263 break;
1264 }
1265
1266 case s_header_field_start:
1267 {
1268 if (ch == CR) {
1269 UPDATE_STATE(s_headers_almost_done);
1270 break;
1271 }
1272
1273 if (ch == LF) {
1274 /* they might be just sending \n instead of \r\n so this would be
1275 * the second \n to denote the end of headers*/
1276 UPDATE_STATE(s_headers_almost_done);
1277 REEXECUTE();
1278 }
1279
1280 c = TOKEN(ch);
1281
1282 if (UNLIKELY(!c)) {
1283 SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
1284 goto error;
1285 }
1286
1287 MARK(header_field);
1288
1289 parser->index = 0;
1290 UPDATE_STATE(s_header_field);
1291
1292 switch (c) {
1293 case 'c':
1294 parser->header_state = h_C;
1295 break;
1296
1297 case 'p':
1298 parser->header_state = h_matching_proxy_connection;
1299 break;
1300
1301 case 't':
1302 parser->header_state = h_matching_transfer_encoding;
1303 break;
1304
1305 case 'u':
1306 parser->header_state = h_matching_upgrade;
1307 break;
1308
1309 default:
1310 parser->header_state = h_general;
1311 break;
1312 }
1313 break;
1314 }
1315
1316 case s_header_field:
1317 {
1318 const char* start = p;
1319 for (; p != data + len; p++) {
1320 ch = *p;
1321 c = TOKEN(ch);
1322
1323 if (!c)
1324 break;
1325
1326 switch (parser->header_state) {
1327 case h_general:
1328 break;
1329
1330 case h_C:
1331 parser->index++;
1332 parser->header_state = (c == 'o' ? h_CO : h_general);
1333 break;
1334
1335 case h_CO:
1336 parser->index++;
1337 parser->header_state = (c == 'n' ? h_CON : h_general);
1338 break;
1339
1340 case h_CON:
1341 parser->index++;
1342 switch (c) {
1343 case 'n':
1344 parser->header_state = h_matching_connection;
1345 break;
1346 case 't':
1347 parser->header_state = h_matching_content_length;
1348 break;
1349 default:
1350 parser->header_state = h_general;
1351 break;
1352 }
1353 break;
1354
1355 /* connection */
1356
1357 case h_matching_connection:
1358 parser->index++;
1359 if (parser->index > sizeof(CONNECTION)-1
1360 || c != CONNECTION[parser->index]) {
1361 parser->header_state = h_general;
1362 } else if (parser->index == sizeof(CONNECTION)-2) {
1363 parser->header_state = h_connection;
1364 }
1365 break;
1366
1367 /* proxy-connection */
1368
1369 case h_matching_proxy_connection:
1370 parser->index++;
1371 if (parser->index > sizeof(PROXY_CONNECTION)-1
1372 || c != PROXY_CONNECTION[parser->index]) {
1373 parser->header_state = h_general;
1374 } else if (parser->index == sizeof(PROXY_CONNECTION)-2) {
1375 parser->header_state = h_connection;
1376 }
1377 break;
1378
1379 /* content-length */
1380
1381 case h_matching_content_length:
1382 parser->index++;
1383 if (parser->index > sizeof(CONTENT_LENGTH)-1
1384 || c != CONTENT_LENGTH[parser->index]) {
1385 parser->header_state = h_general;
1386 } else if (parser->index == sizeof(CONTENT_LENGTH)-2) {
1387 parser->header_state = h_content_length;
1388 }
1389 break;
1390
1391 /* transfer-encoding */
1392
1393 case h_matching_transfer_encoding:
1394 parser->index++;
1395 if (parser->index > sizeof(TRANSFER_ENCODING)-1
1396 || c != TRANSFER_ENCODING[parser->index]) {
1397 parser->header_state = h_general;
1398 } else if (parser->index == sizeof(TRANSFER_ENCODING)-2) {
1399 parser->header_state = h_transfer_encoding;
1400 }
1401 break;
1402
1403 /* upgrade */
1404
1405 case h_matching_upgrade:
1406 parser->index++;
1407 if (parser->index > sizeof(UPGRADE)-1
1408 || c != UPGRADE[parser->index]) {
1409 parser->header_state = h_general;
1410 } else if (parser->index == sizeof(UPGRADE)-2) {
1411 parser->header_state = h_upgrade;
1412 }
1413 break;
1414
1415 case h_connection:
1416 case h_content_length:
1417 case h_transfer_encoding:
1418 case h_upgrade:
1419 if (ch != ' ') parser->header_state = h_general;
1420 break;
1421
1422 default:
1423 assert(0 && "Unknown header_state");
1424 break;
1425 }
1426 }
1427
1428 COUNT_HEADER_SIZE(p - start);
1429
1430 if (p == data + len) {
1431 --p;
1432 break;
1433 }
1434
1435 if (ch == ':') {
1436 UPDATE_STATE(s_header_value_discard_ws);
1437 CALLBACK_DATA(header_field);
1438 break;
1439 }
1440
1441 SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
1442 goto error;
1443 }
1444
1445 case s_header_value_discard_ws:
1446 if (ch == ' ' || ch == '\t') break;
1447
1448 if (ch == CR) {
1449 UPDATE_STATE(s_header_value_discard_ws_almost_done);
1450 break;
1451 }
1452
1453 if (ch == LF) {
1454 UPDATE_STATE(s_header_value_discard_lws);
1455 break;
1456 }
1457
1458 /* FALLTHROUGH */
1459
1460 case s_header_value_start:
1461 {
1462 MARK(header_value);
1463
1464 UPDATE_STATE(s_header_value);
1465 parser->index = 0;
1466
1467 c = LOWER(ch);
1468
1469 switch (parser->header_state) {
1470 case h_upgrade:
1471 parser->flags |= F_UPGRADE;
1472 parser->header_state = h_general;
1473 break;
1474
1475 case h_transfer_encoding:
1476 /* looking for 'Transfer-Encoding: chunked' */
1477 if ('c' == c) {
1478 parser->header_state = h_matching_transfer_encoding_chunked;
1479 } else {
1480 parser->header_state = h_general;
1481 }
1482 break;
1483
1484 case h_content_length:
1485 if (UNLIKELY(!IS_NUM(ch))) {
1486 SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
1487 goto error;
1488 }
1489
1490 parser->content_length = ch - '0';
1491 break;
1492
1493 case h_connection:
1494 /* looking for 'Connection: keep-alive' */
1495 if (c == 'k') {
1496 parser->header_state = h_matching_connection_keep_alive;
1497 /* looking for 'Connection: close' */
1498 } else if (c == 'c') {
1499 parser->header_state = h_matching_connection_close;
1500 } else if (c == 'u') {
1501 parser->header_state = h_matching_connection_upgrade;
1502 } else {
1503 parser->header_state = h_matching_connection_token;
1504 }
1505 break;
1506
1507 /* Multi-value `Connection` header */
1508 case h_matching_connection_token_start:
1509 break;
1510
1511 default:
1512 parser->header_state = h_general;
1513 break;
1514 }
1515 break;
1516 }
1517
1518 case s_header_value:
1519 {
1520 const char* start = p;
1521 enum header_states h_state = (enum header_states) parser->header_state;
1522 for (; p != data + len; p++) {
1523 ch = *p;
1524 if (ch == CR) {
1525 UPDATE_STATE(s_header_almost_done);
1526 parser->header_state = h_state;
1527 CALLBACK_DATA(header_value);
1528 break;
1529 }
1530
1531 if (ch == LF) {
1532 UPDATE_STATE(s_header_almost_done);
1533 COUNT_HEADER_SIZE(p - start);
1534 parser->header_state = h_state;
1535 CALLBACK_DATA_NOADVANCE(header_value);
1536 REEXECUTE();
1537 }
1538
1539 c = LOWER(ch);
1540
1541 switch (h_state) {
1542 case h_general:
1543 {
1544 const char* p_cr;
1545 const char* p_lf;
1546 size_t limit = data + len - p;
1547
1548 limit = MIN(limit, HTTP_MAX_HEADER_SIZE);
1549
1550 p_cr = (const char*) memchr(p, CR, limit);
1551 p_lf = (const char*) memchr(p, LF, limit);
1552 if (p_cr != NULL) {
1553 if (p_lf != NULL && p_cr >= p_lf)
1554 p = p_lf;
1555 else
1556 p = p_cr;
1557 } else if (UNLIKELY(p_lf != NULL)) {
1558 p = p_lf;
1559 } else {
1560 p = data + len;
1561 }
1562 --p;
1563
1564 break;
1565 }
1566
1567 case h_connection:
1568 case h_transfer_encoding:
1569 assert(0 && "Shouldn't get here.");
1570 break;
1571
1572 case h_content_length:
1573 {
1574 uint64_t t;
1575
1576 if (ch == ' ') break;
1577
1578 if (UNLIKELY(!IS_NUM(ch))) {
1579 SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
1580 parser->header_state = h_state;
1581 goto error;
1582 }
1583
1584 t = parser->content_length;
1585 t *= 10;
1586 t += ch - '0';
1587
1588 /* Overflow? Test against a conservative limit for simplicity. */
1589 if (UNLIKELY((ULLONG_MAX - 10) / 10 < parser->content_length)) {
1590 SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
1591 parser->header_state = h_state;
1592 goto error;
1593 }
1594
1595 parser->content_length = t;
1596 break;
1597 }
1598
1599 /* Transfer-Encoding: chunked */
1600 case h_matching_transfer_encoding_chunked:
1601 parser->index++;
1602 if (parser->index > sizeof(CHUNKED)-1
1603 || c != CHUNKED[parser->index]) {
1604 h_state = h_general;
1605 } else if (parser->index == sizeof(CHUNKED)-2) {
1606 h_state = h_transfer_encoding_chunked;
1607 }
1608 break;
1609
1610 case h_matching_connection_token_start:
1611 /* looking for 'Connection: keep-alive' */
1612 if (c == 'k') {
1613 h_state = h_matching_connection_keep_alive;
1614 /* looking for 'Connection: close' */
1615 } else if (c == 'c') {
1616 h_state = h_matching_connection_close;
1617 } else if (c == 'u') {
1618 h_state = h_matching_connection_upgrade;
1619 } else if (STRICT_TOKEN(c)) {
1620 h_state = h_matching_connection_token;
1621 } else {
1622 h_state = h_general;
1623 }
1624 break;
1625
1626 /* looking for 'Connection: keep-alive' */
1627 case h_matching_connection_keep_alive:
1628 parser->index++;
1629 if (parser->index > sizeof(KEEP_ALIVE)-1
1630 || c != KEEP_ALIVE[parser->index]) {
1631 h_state = h_matching_connection_token;
1632 } else if (parser->index == sizeof(KEEP_ALIVE)-2) {
1633 h_state = h_connection_keep_alive;
1634 }
1635 break;
1636
1637 /* looking for 'Connection: close' */
1638 case h_matching_connection_close:
1639 parser->index++;
1640 if (parser->index > sizeof(CLOSE)-1 || c != CLOSE[parser->index]) {
1641 h_state = h_matching_connection_token;
1642 } else if (parser->index == sizeof(CLOSE)-2) {
1643 h_state = h_connection_close;
1644 }
1645 break;
1646
1647 /* looking for 'Connection: upgrade' */
1648 case h_matching_connection_upgrade:
1649 parser->index++;
1650 if (parser->index > sizeof(UPGRADE) - 1 ||
1651 c != UPGRADE[parser->index]) {
1652 h_state = h_matching_connection_token;
1653 } else if (parser->index == sizeof(UPGRADE)-2) {
1654 h_state = h_connection_upgrade;
1655 }
1656 break;
1657
1658 case h_matching_connection_token:
1659 if (ch == ',') {
1660 h_state = h_matching_connection_token_start;
1661 parser->index = 0;
1662 }
1663 break;
1664
1665 case h_transfer_encoding_chunked:
1666 if (ch != ' ') h_state = h_general;
1667 break;
1668
1669 case h_connection_keep_alive:
1670 case h_connection_close:
1671 case h_connection_upgrade:
1672 if (ch == ',') {
1673 if (h_state == h_connection_keep_alive) {
1674 parser->flags |= F_CONNECTION_KEEP_ALIVE;
1675 } else if (h_state == h_connection_close) {
1676 parser->flags |= F_CONNECTION_CLOSE;
1677 } else if (h_state == h_connection_upgrade) {
1678 parser->flags |= F_CONNECTION_UPGRADE;
1679 }
1680 h_state = h_matching_connection_token_start;
1681 parser->index = 0;
1682 } else if (ch != ' ') {
1683 h_state = h_matching_connection_token;
1684 }
1685 break;
1686
1687 default:
1688 UPDATE_STATE(s_header_value);
1689 h_state = h_general;
1690 break;
1691 }
1692 }
1693 parser->header_state = h_state;
1694
1695 COUNT_HEADER_SIZE(p - start);
1696
1697 if (p == data + len)
1698 --p;
1699 break;
1700 }
1701
1702 case s_header_almost_done:
1703 {
1704 STRICT_CHECK(ch != LF);
1705
1706 UPDATE_STATE(s_header_value_lws);
1707 break;
1708 }
1709
1710 case s_header_value_lws:
1711 {
1712 if (ch == ' ' || ch == '\t') {
1713 UPDATE_STATE(s_header_value_start);
1714 REEXECUTE();
1715 }
1716
1717 /* finished the header */
1718 switch (parser->header_state) {
1719 case h_connection_keep_alive:
1720 parser->flags |= F_CONNECTION_KEEP_ALIVE;
1721 break;
1722 case h_connection_close:
1723 parser->flags |= F_CONNECTION_CLOSE;
1724 break;
1725 case h_transfer_encoding_chunked:
1726 parser->flags |= F_CHUNKED;
1727 break;
1728 case h_connection_upgrade:
1729 parser->flags |= F_CONNECTION_UPGRADE;
1730 break;
1731 default:
1732 break;
1733 }
1734
1735 UPDATE_STATE(s_header_field_start);
1736 REEXECUTE();
1737 }
1738
1739 case s_header_value_discard_ws_almost_done:
1740 {
1741 STRICT_CHECK(ch != LF);
1742 UPDATE_STATE(s_header_value_discard_lws);
1743 break;
1744 }
1745
1746 case s_header_value_discard_lws:
1747 {
1748 if (ch == ' ' || ch == '\t') {
1749 UPDATE_STATE(s_header_value_discard_ws);
1750 break;
1751 } else {
1752 switch (parser->header_state) {
1753 case h_connection_keep_alive:
1754 parser->flags |= F_CONNECTION_KEEP_ALIVE;
1755 break;
1756 case h_connection_close:
1757 parser->flags |= F_CONNECTION_CLOSE;
1758 break;
1759 case h_connection_upgrade:
1760 parser->flags |= F_CONNECTION_UPGRADE;
1761 break;
1762 case h_transfer_encoding_chunked:
1763 parser->flags |= F_CHUNKED;
1764 break;
1765 default:
1766 break;
1767 }
1768
1769 /* header value was empty */
1770 MARK(header_value);
1771 UPDATE_STATE(s_header_field_start);
1772 CALLBACK_DATA_NOADVANCE(header_value);
1773 REEXECUTE();
1774 }
1775 }
1776
1777 case s_headers_almost_done:
1778 {
1779 STRICT_CHECK(ch != LF);
1780
1781 if (parser->flags & F_TRAILING) {
1782 /* End of a chunked request */
1783 UPDATE_STATE(NEW_MESSAGE());
1784 CALLBACK_NOTIFY(message_complete);
1785 break;
1786 }
1787
1788 UPDATE_STATE(s_headers_done);
1789
1790 /* Set this here so that on_headers_complete() callbacks can see it */
1791 parser->upgrade =
1792 ((parser->flags & (F_UPGRADE | F_CONNECTION_UPGRADE)) ==
1793 (F_UPGRADE | F_CONNECTION_UPGRADE) ||
1794 parser->method == HTTP_CONNECT);
1795
1796 /* Here we call the headers_complete callback. This is somewhat
1797 * different than other callbacks because if the user returns 1, we
1798 * will interpret that as saying that this message has no body. This
1799 * is needed for the annoying case of recieving a response to a HEAD
1800 * request.
1801 *
1802 * We'd like to use CALLBACK_NOTIFY_NOADVANCE() here but we cannot, so
1803 * we have to simulate it by handling a change in errno below.
1804 */
1805 if (settings->on_headers_complete) {
1806 switch (settings->on_headers_complete(parser)) {
1807 case 0:
1808 break;
1809
1810 case 1:
1811 parser->flags |= F_SKIPBODY;
1812 break;
1813
1814 default:
1815 SET_ERRNO(HPE_CB_headers_complete);
1816 RETURN(p - data); /* Error */
1817 }
1818 }
1819
1820 if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
1821 RETURN(p - data);
1822 }
1823
1824 REEXECUTE();
1825 }
1826
1827 case s_headers_done:
1828 {
1829 STRICT_CHECK(ch != LF);
1830
1831 parser->nread = 0;
1832
1833 /* Exit, the rest of the connect is in a different protocol. */
1834 if (parser->upgrade) {
1835 UPDATE_STATE(NEW_MESSAGE());
1836 CALLBACK_NOTIFY(message_complete);
1837 RETURN((p - data) + 1);
1838 }
1839
1840 if (parser->flags & F_SKIPBODY) {
1841 UPDATE_STATE(NEW_MESSAGE());
1842 CALLBACK_NOTIFY(message_complete);
1843 } else if (parser->flags & F_CHUNKED) {
1844 /* chunked encoding - ignore Content-Length header */
1845 UPDATE_STATE(s_chunk_size_start);
1846 } else {
1847 if (parser->content_length == 0) {
1848 /* Content-Length header given but zero: Content-Length: 0\r\n */
1849 UPDATE_STATE(NEW_MESSAGE());
1850 CALLBACK_NOTIFY(message_complete);
1851 } else if (parser->content_length != ULLONG_MAX) {
1852 /* Content-Length header given and non-zero */
1853 UPDATE_STATE(s_body_identity);
1854 } else {
1855 if (parser->type == HTTP_REQUEST ||
1856 !http_message_needs_eof(parser)) {
1857 /* Assume content-length 0 - read the next */
1858 UPDATE_STATE(NEW_MESSAGE());
1859 CALLBACK_NOTIFY(message_complete);
1860 } else {
1861 /* Read body until EOF */
1862 UPDATE_STATE(s_body_identity_eof);
1863 }
1864 }
1865 }
1866
1867 break;
1868 }
1869
1870 case s_body_identity:
1871 {
1872 uint64_t to_read = MIN(parser->content_length,
1873 (uint64_t) ((data + len) - p));
1874
1875 assert(parser->content_length != 0
1876 && parser->content_length != ULLONG_MAX);
1877
1878 /* The difference between advancing content_length and p is because
1879 * the latter will automaticaly advance on the next loop iteration.
1880 * Further, if content_length ends up at 0, we want to see the last
1881 * byte again for our message complete callback.
1882 */
1883 MARK(body);
1884 parser->content_length -= to_read;
1885 p += to_read - 1;
1886
1887 if (parser->content_length == 0) {
1888 UPDATE_STATE(s_message_done);
1889
1890 /* Mimic CALLBACK_DATA_NOADVANCE() but with one extra byte.
1891 *
1892 * The alternative to doing this is to wait for the next byte to
1893 * trigger the data callback, just as in every other case. The
1894 * problem with this is that this makes it difficult for the test
1895 * harness to distinguish between complete-on-EOF and
1896 * complete-on-length. It's not clear that this distinction is
1897 * important for applications, but let's keep it for now.
1898 */
1899 CALLBACK_DATA_(body, p - body_mark + 1, p - data);
1900 REEXECUTE();
1901 }
1902
1903 break;
1904 }
1905
1906 /* read until EOF */
1907 case s_body_identity_eof:
1908 MARK(body);
1909 p = data + len - 1;
1910
1911 break;
1912
1913 case s_message_done:
1914 UPDATE_STATE(NEW_MESSAGE());
1915 CALLBACK_NOTIFY(message_complete);
1916 break;
1917
1918 case s_chunk_size_start:
1919 {
1920 assert(parser->nread == 1);
1921 assert(parser->flags & F_CHUNKED);
1922
1923 unhex_val = unhex[(unsigned char)ch];
1924 if (UNLIKELY(unhex_val == -1)) {
1925 SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
1926 goto error;
1927 }
1928
1929 parser->content_length = unhex_val;
1930 UPDATE_STATE(s_chunk_size);
1931 break;
1932 }
1933
1934 case s_chunk_size:
1935 {
1936 uint64_t t;
1937
1938 assert(parser->flags & F_CHUNKED);
1939
1940 if (ch == CR) {
1941 UPDATE_STATE(s_chunk_size_almost_done);
1942 break;
1943 }
1944
1945 unhex_val = unhex[(unsigned char)ch];
1946
1947 if (unhex_val == -1) {
1948 if (ch == ';' || ch == ' ') {
1949 UPDATE_STATE(s_chunk_parameters);
1950 break;
1951 }
1952
1953 SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
1954 goto error;
1955 }
1956
1957 t = parser->content_length;
1958 t *= 16;
1959 t += unhex_val;
1960
1961 /* Overflow? Test against a conservative limit for simplicity. */
1962 if (UNLIKELY((ULLONG_MAX - 16) / 16 < parser->content_length)) {
1963 SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
1964 goto error;
1965 }
1966
1967 parser->content_length = t;
1968 break;
1969 }
1970
1971 case s_chunk_parameters:
1972 {
1973 assert(parser->flags & F_CHUNKED);
1974 /* just ignore this shit. TODO check for overflow */
1975 if (ch == CR) {
1976 UPDATE_STATE(s_chunk_size_almost_done);
1977 break;
1978 }
1979 break;
1980 }
1981
1982 case s_chunk_size_almost_done:
1983 {
1984 assert(parser->flags & F_CHUNKED);
1985 STRICT_CHECK(ch != LF);
1986
1987 parser->nread = 0;
1988
1989 if (parser->content_length == 0) {
1990 parser->flags |= F_TRAILING;
1991 UPDATE_STATE(s_header_field_start);
1992 } else {
1993 UPDATE_STATE(s_chunk_data);
1994 }
1995 break;
1996 }
1997
1998 case s_chunk_data:
1999 {
2000 uint64_t to_read = MIN(parser->content_length,
2001 (uint64_t) ((data + len) - p));
2002
2003 assert(parser->flags & F_CHUNKED);
2004 assert(parser->content_length != 0
2005 && parser->content_length != ULLONG_MAX);
2006
2007 /* See the explanation in s_body_identity for why the content
2008 * length and data pointers are managed this way.
2009 */
2010 MARK(body);
2011 parser->content_length -= to_read;
2012 p += to_read - 1;
2013
2014 if (parser->content_length == 0) {
2015 UPDATE_STATE(s_chunk_data_almost_done);
2016 }
2017
2018 break;
2019 }
2020
2021 case s_chunk_data_almost_done:
2022 assert(parser->flags & F_CHUNKED);
2023 assert(parser->content_length == 0);
2024 STRICT_CHECK(ch != CR);
2025 UPDATE_STATE(s_chunk_data_done);
2026 CALLBACK_DATA(body);
2027 break;
2028
2029 case s_chunk_data_done:
2030 assert(parser->flags & F_CHUNKED);
2031 STRICT_CHECK(ch != LF);
2032 parser->nread = 0;
2033 UPDATE_STATE(s_chunk_size_start);
2034 break;
2035
2036 default:
2037 assert(0 && "unhandled state");
2038 SET_ERRNO(HPE_INVALID_INTERNAL_STATE);
2039 goto error;
2040 }
2041 }
2042
2043 /* Run callbacks for any marks that we have leftover after we ran our of
2044 * bytes. There should be at most one of these set, so it's OK to invoke
2045 * them in series (unset marks will not result in callbacks).
2046 *
2047 * We use the NOADVANCE() variety of callbacks here because 'p' has already
2048 * overflowed 'data' and this allows us to correct for the off-by-one that
2049 * we'd otherwise have (since CALLBACK_DATA() is meant to be run with a 'p'
2050 * value that's in-bounds).
2051 */
2052
2053 assert(((header_field_mark ? 1 : 0) +
2054 (header_value_mark ? 1 : 0) +
2055 (url_mark ? 1 : 0) +
2056 (body_mark ? 1 : 0) +
2057 (status_mark ? 1 : 0)) <= 1);
2058
2059 CALLBACK_DATA_NOADVANCE(header_field);
2060 CALLBACK_DATA_NOADVANCE(header_value);
2061 CALLBACK_DATA_NOADVANCE(url);
2062 CALLBACK_DATA_NOADVANCE(body);
2063 CALLBACK_DATA_NOADVANCE(status);
2064
2065 RETURN(len);
2066
2067error:
2068 if (HTTP_PARSER_ERRNO(parser) == HPE_OK) {
2069 SET_ERRNO(HPE_UNKNOWN);
2070 }
2071
2072 RETURN(p - data);
2073}
2074
2075
2076/* Does the parser need to see an EOF to find the end of the message? */
2077int
2078http_message_needs_eof (const http_parser *parser)
2079{
2080 if (parser->type == HTTP_REQUEST) {
2081 return 0;
2082 }
2083
2084 /* See RFC 2616 section 4.4 */
2085 if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */
2086 parser->status_code == 204 || /* No Content */
2087 parser->status_code == 304 || /* Not Modified */
2088 parser->flags & F_SKIPBODY) { /* response to a HEAD request */
2089 return 0;
2090 }
2091
2092 if ((parser->flags & F_CHUNKED) || parser->content_length != ULLONG_MAX) {
2093 return 0;
2094 }
2095
2096 return 1;
2097}
2098
2099
2100int
2101http_should_keep_alive (const http_parser *parser)
2102{
2103 if (parser->http_major > 0 && parser->http_minor > 0) {
2104 /* HTTP/1.1 */
2105 if (parser->flags & F_CONNECTION_CLOSE) {
2106 return 0;
2107 }
2108 } else {
2109 /* HTTP/1.0 or earlier */
2110 if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) {
2111 return 0;
2112 }
2113 }
2114
2115 return !http_message_needs_eof(parser);
2116}
2117
2118
2119const char *
2120http_method_str (enum http_method m)
2121{
2122 return ELEM_AT(method_strings, m, "<unknown>");
2123}
2124
2125
2126void
2127http_parser_init (http_parser *parser, enum http_parser_type t)
2128{
2129 void *data = parser->data; /* preserve application data */
2130 memset(parser, 0, sizeof(*parser));
2131 parser->data = data;
2132 parser->type = t;
2133 parser->state = (t == HTTP_REQUEST ? s_start_req : (t == HTTP_RESPONSE ? s_start_res : s_start_req_or_res));
2134 parser->http_errno = HPE_OK;
2135}
2136
2137const char *
2138http_errno_name(enum http_errno err) {
2139 assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0])));
2140 return http_strerror_tab[err].name;
2141}
2142
2143const char *
2144http_errno_description(enum http_errno err) {
2145 assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0])));
2146 return http_strerror_tab[err].description;
2147}
2148
2149static enum http_host_state
2150http_parse_host_char(enum http_host_state s, const char ch) {
2151 switch(s) {
2152 case s_http_userinfo:
2153 case s_http_userinfo_start:
2154 if (ch == '@') {
2155 return s_http_host_start;
2156 }
2157
2158 if (IS_USERINFO_CHAR(ch)) {
2159 return s_http_userinfo;
2160 }
2161 break;
2162
2163 case s_http_host_start:
2164 if (ch == '[') {
2165 return s_http_host_v6_start;
2166 }
2167
2168 if (IS_HOST_CHAR(ch)) {
2169 return s_http_host;
2170 }
2171
2172 break;
2173
2174 case s_http_host:
2175 if (IS_HOST_CHAR(ch)) {
2176 return s_http_host;
2177 }
2178
2179 /* FALLTHROUGH */
2180 case s_http_host_v6_end:
2181 if (ch == ':') {
2182 return s_http_host_port_start;
2183 }
2184
2185 break;
2186
2187 case s_http_host_v6:
2188 if (ch == ']') {
2189 return s_http_host_v6_end;
2190 }
2191
2192 /* FALLTHROUGH */
2193 case s_http_host_v6_start:
2194 if (IS_HEX(ch) || ch == ':' || ch == '.') {
2195 return s_http_host_v6;
2196 }
2197
2198 break;
2199
2200 case s_http_host_port:
2201 case s_http_host_port_start:
2202 if (IS_NUM(ch)) {
2203 return s_http_host_port;
2204 }
2205
2206 break;
2207
2208 default:
2209 break;
2210 }
2211 return s_http_host_dead;
2212}
2213
2214static int
2215http_parse_host(const char * buf, struct http_parser_url *u, int found_at) {
2216 enum http_host_state s;
2217
2218 const char *p;
2219 size_t buflen = u->field_data[UF_HOST].off + u->field_data[UF_HOST].len;
2220
2221 u->field_data[UF_HOST].len = 0;
2222
2223 s = found_at ? s_http_userinfo_start : s_http_host_start;
2224
2225 for (p = buf + u->field_data[UF_HOST].off; p < buf + buflen; p++) {
2226 enum http_host_state new_s = http_parse_host_char(s, *p);
2227
2228 if (new_s == s_http_host_dead) {
2229 return 1;
2230 }
2231
2232 switch(new_s) {
2233 case s_http_host:
2234 if (s != s_http_host) {
2235 u->field_data[UF_HOST].off = p - buf;
2236 }
2237 u->field_data[UF_HOST].len++;
2238 break;
2239
2240 case s_http_host_v6:
2241 if (s != s_http_host_v6) {
2242 u->field_data[UF_HOST].off = p - buf;
2243 }
2244 u->field_data[UF_HOST].len++;
2245 break;
2246
2247 case s_http_host_port:
2248 if (s != s_http_host_port) {
2249 u->field_data[UF_PORT].off = p - buf;
2250 u->field_data[UF_PORT].len = 0;
2251 u->field_set |= (1 << UF_PORT);
2252 }
2253 u->field_data[UF_PORT].len++;
2254 break;
2255
2256 case s_http_userinfo:
2257 if (s != s_http_userinfo) {
2258 u->field_data[UF_USERINFO].off = p - buf ;
2259 u->field_data[UF_USERINFO].len = 0;
2260 u->field_set |= (1 << UF_USERINFO);
2261 }
2262 u->field_data[UF_USERINFO].len++;
2263 break;
2264
2265 default:
2266 break;
2267 }
2268 s = new_s;
2269 }
2270
2271 /* Make sure we don't end somewhere unexpected */
2272 switch (s) {
2273 case s_http_host_start:
2274 case s_http_host_v6_start:
2275 case s_http_host_v6:
2276 case s_http_host_port_start:
2277 case s_http_userinfo:
2278 case s_http_userinfo_start:
2279 return 1;
2280 default:
2281 break;
2282 }
2283
2284 return 0;
2285}
2286
2287int
2288http_parser_parse_url(const char *buf, size_t buflen, int is_connect,
2289 struct http_parser_url *u)
2290{
2291 enum state s;
2292 const char *p;
2293 enum http_parser_url_fields uf, old_uf;
2294 int found_at = 0;
2295
2296 u->port = u->field_set = 0;
2297 s = is_connect ? s_req_server_start : s_req_spaces_before_url;
2298 old_uf = UF_MAX;
2299
2300 for (p = buf; p < buf + buflen; p++) {
2301 s = parse_url_char(s, *p);
2302
2303 /* Figure out the next field that we're operating on */
2304 switch (s) {
2305 case s_dead:
2306 return 1;
2307
2308 /* Skip delimeters */
2309 case s_req_schema_slash:
2310 case s_req_schema_slash_slash:
2311 case s_req_server_start:
2312 case s_req_query_string_start:
2313 case s_req_fragment_start:
2314 continue;
2315
2316 case s_req_schema:
2317 uf = UF_SCHEMA;
2318 break;
2319
2320 case s_req_server_with_at:
2321 found_at = 1;
2322
2323 /* FALLTROUGH */
2324 case s_req_server:
2325 uf = UF_HOST;
2326 break;
2327
2328 case s_req_path:
2329 uf = UF_PATH;
2330 break;
2331
2332 case s_req_query_string:
2333 uf = UF_QUERY;
2334 break;
2335
2336 case s_req_fragment:
2337 uf = UF_FRAGMENT;
2338 break;
2339
2340 default:
2341 assert(!"Unexpected state");
2342 return 1;
2343 }
2344
2345 /* Nothing's changed; soldier on */
2346 if (uf == old_uf) {
2347 u->field_data[uf].len++;
2348 continue;
2349 }
2350
2351 u->field_data[uf].off = p - buf;
2352 u->field_data[uf].len = 1;
2353
2354 u->field_set |= (1 << uf);
2355 old_uf = uf;
2356 }
2357
2358 /* host must be present if there is a schema */
2359 /* parsing http:///toto will fail */
2360 if ((u->field_set & ((1 << UF_SCHEMA) | (1 << UF_HOST))) != 0) {
2361 if (http_parse_host(buf, u, found_at) != 0) {
2362 return 1;
2363 }
2364 }
2365
2366 /* CONNECT requests can only contain "hostname:port" */
2367 if (is_connect && u->field_set != ((1 << UF_HOST)|(1 << UF_PORT))) {
2368 return 1;
2369 }
2370
2371 if (u->field_set & (1 << UF_PORT)) {
2372 /* Don't bother with endp; we've already validated the string */
2373 unsigned long v = strtoul(buf + u->field_data[UF_PORT].off, NULL, 10);
2374
2375 /* Ports have a max value of 2^16 */
2376 if (v > 0xffff) {
2377 return 1;
2378 }
2379
2380 u->port = (uint16_t) v;
2381 }
2382
2383 return 0;
2384}
2385
2386void
2387http_parser_pause(http_parser *parser, int paused) {
2388 /* Users should only be pausing/unpausing a parser that is not in an error
2389 * state. In non-debug builds, there's not much that we can do about this
2390 * other than ignore it.
2391 */
2392 if (HTTP_PARSER_ERRNO(parser) == HPE_OK ||
2393 HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) {
2394 SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK);
2395 } else {
2396 assert(0 && "Attempting to pause parser in error state");
2397 }
2398}
2399
2400int
2401http_body_is_final(const struct http_parser *parser) {
2402 return parser->state == s_message_done;
2403}
2404
2405unsigned long
2406http_parser_version(void) {
2407 return HTTP_PARSER_VERSION_MAJOR * 0x10000 |
2408 HTTP_PARSER_VERSION_MINOR * 0x00100 |
2409 HTTP_PARSER_VERSION_PATCH * 0x00001;
2410}
Note: See TracBrowser for help on using the repository browser.