http

Committer:
DuaaAbusharkh
Date:
Mon Apr 15 08:30:22 2019 +0000
Revision:
0:a49e37a83a7a
blink

Who changed what in which revision?

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