HTTP and HTTPS example application for Mbed OS 5

Dependencies:   mbed-http

This application demonstrates how to make HTTP and HTTPS requests and parse the response from Mbed OS 5.

It consists of six example applications, which you can select in source/select-demo.h:

Response parsing is done through nodejs/http-parser.

Note: HTTPS requests do not work on targets with less than 128K of RAM due to the size of the TLS handshake. For more background see mbed-http.

To build

  1. If you're using WiFi, specify the credentials in mbed_app.json.
  2. Build the project in the online compiler or using Mbed CLI.
  3. Flash the project to your development board.
  4. Attach a serial monitor to your board to see the debug messages.

Defining the network interface

This application uses the on-board network interface for your board. If you use an external network interface (f.e. a WiFi module) you need to add the driver to this project. Then, open network-helper.h and specify which network driver to use.

More information is in the Mbed OS documentation under IP Networking.

Entropy (or lack thereof)

On all platforms that do not have the TRNG feature, the application is compiled without TLS entropy sources. This means that your code is inherently unsafe and should not be deployed to any production systems. To enable entropy, remove the MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES and MBEDTLS_TEST_NULL_ENTROPY macros from mbed_app.json.

Flash size

Default flash size for HTTPS is very large, as the application is loading the default Mbed TLS configuration. To use a more optimized version, you can disable unused cypher suites and other Mbed TLS features with a custom configuration file. Create a new configuration file, then add in mbed_app.json:

"MBEDTLS_CONFIG_FILE=\"mbedtls_config.h\""

to the macros array.

Running tests

You can run the integration tests from this project via Mbed CLI.

  1. In select-demo.h set the DEMO macro to DEMO_TESTS.
  2. Set your WiFi credentials in mbed_app.json.
  3. Then run the tests via:

$ mbed test -v -n mbed-http-tests-tests-*

Tested on

  • K64F with Ethernet.
  • NUCLEO_F411RE with ESP8266 (not working on Mbed OS 5.12+)
  • ODIN-W2 with WiFi.
  • K64F with Atmel 6LoWPAN shield.
  • DISCO-L475VG-IOT01A with WiFi (requires the wifi-ism43362 driver).
Committer:
Jan Jongboom
Date:
Wed Feb 15 21:57:31 2017 +0100
Revision:
0:85fdc69bc10c
Initial commit

Who changed what in which revision?

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