HTTP and HTTPS library for Mbed OS 5

Dependents:   MQTTGateway2 MQTTGatewayK64 http-example-wnc GuardRoom ... more

For the example program, see: sandbox/http-example.

This library is used to make HTTP and HTTPS calls from Mbed OS 5 applications.

HTTP Request API

NetworkInterface* network = /* obtain a NetworkInterface object */

const char body[] = "{\"hello\":\"world\"}";

HttpRequest* request = new HttpRequest(network, HTTP_POST, "http://httpbin.org/post");
request->set_header("Content-Type", "application/json");
HttpResponse* response = request->send(body, strlen(body));
// if response is NULL, check response->get_error()

printf("status is %d - %s\n", response->get_status_code(), response->get_status_message());
printf("body is:\n%s\n", response->get_body_as_string().c_str());

delete request; // also clears out the response

HTTPS Request API

// pass in the root certificates that you trust, there is no central CA registry in Mbed OS
const char SSL_CA_PEM[] = "-----BEGIN CERTIFICATE-----\n"
    /* rest of the CA root certificates */;

NetworkInterface* network = /* obtain a NetworkInterface object */

const char body[] = "{\"hello\":\"world\"}";

HttpsRequest* request = new HttpsRequest(network, SSL_CA_PEM, HTTP_GET "https://httpbin.org/status/418");
HttpResponse* response = request->send();
// if response is NULL, check response->get_error()

printf("status is %d - %s\n", response->get_status_code(), response->get_status_message());
printf("body is:\n%s\n", response->get_body().c_str());

delete request;

Note: You can get the root CA for a domain easily from Firefox. Click on the green padlock, click More information > Security > View certificate > Details. Select the top entry in the 'Certificate Hierarchy' and click Export.... This gives you a PEM file. Add the content of the PEM file to your root CA list (here's an image).

Mbed TLS Entropy configuration

If your target does not have a built-in TRNG, or other entropy sources, add the following macros to your mbed_app.json file to disable entropy:

{
    "macros": [
        "MBEDTLS_TEST_NULL_ENTROPY",
        "MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES"
    ]
}

Note that this is not secure, and you should not deploy this device into production with this configuration.

Memory usage

Small requests where the body of the response is cached by the library (like the one found in main-http.cpp), require 4K of RAM. When the request is finished they require 1.5K of RAM, depending on the size of the response. This applies both to HTTP and HTTPS. If you need to handle requests that return a large response body, see 'Dealing with large body'.

HTTPS requires additional memory: on FRDM-K64F about 50K of heap space (at its peak). This means that you cannot use HTTPS on devices with less than 128K of memory, asyou also need to reserve memory for the stack and network interface.

Dealing with large response body

By default the library will store the full request body on the heap. This works well for small responses, but you'll run out of memory when receiving a large response body. To mitigate this you can pass in a callback as the last argument to the request constructor. This callback will be called whenever a chunk of the body is received. You can set the request chunk size in the HTTP_RECEIVE_BUFFER_SIZE macro (see mbed_lib.json for the definition) although it also depends on the buffer size ofthe underlying network connection.

void body_callback(const char* data, uint32_t data_len) {
    // do something with the data
}

HttpRequest* req = new HttpRequest(network, HTTP_GET, "http://pathtolargefile.com", &body_callback);
req->send(NULL, 0);

Dealing with a large request body

If you cannot load the full request into memory, you can pass a callback into the send function. Through this callback you can feed in chunks of the request body. This is very useful if you want to send files from a file system.

const void * get_chunk(uint32_t* out_size) {
    // set the value of out_size (via *out_size = 10) to the size of the buffer
    // return the buffer

    // if you don't have any more data, set *out_size to 0
}

HttpRequest* req = new HttpRequest(network, HTTP_POST, "http://my_api.com/upload");
req->send(callback(&get_chunk));

Socket re-use

By default the library opens a new socket per request. This is wasteful, especially when dealing with TLS requests. You can re-use sockets like this:

HTTP

TCPSocket* socket = new TCPSocket();

nsapi_error_t open_result = socket->open(network);
// check open_result

nsapi_error_t connect_result = socket->connect("httpbin.org", 80);
// check connect_result

// Pass in `socket`, instead of `network` as first argument
HttpRequest* req = new HttpRequest(socket, HTTP_GET, "http://httpbin.org/status/418");

HTTPS

TLSSocket* socket = new TLSSocket();

nsapi_error_t r;
// make sure to check the return values for the calls below (should return NSAPI_ERROR_OK)
r = socket->open(network);
r = socket->set_root_ca_cert(SSL_CA_PEM);
r = socket->connect("httpbin.org", 443);

// Pass in `socket`, instead of `network` as first argument, and omit the `SSL_CA_PEM` argument
HttpsRequest* get_req = new HttpsRequest(socket, HTTP_GET, "https://httpbin.org/status/418");

Request logging

To make debugging easier you can log the raw request body that goes over the line. This also works with chunked encoding.

uint8_t *request_buffer = (uint8_t*)calloc(2048, 1);
req->set_request_log_buffer(request_buffer, 2048);

// after the request is done:
printf("\n----- Request buffer -----\n");
for (size_t ix = 0; ix < req->get_request_log_buffer_length(); ix++) {
    printf("%02x ", request_buffer[ix]);
}
printf("\n");

Integration tests

Integration tests are located in the TESTS folder and are ran through Greentea. Instructions on how to run the tests are in http-example.

Mbed OS 5.10 or lower

If you want to use this library on Mbed OS 5.10 or lower, you need to add the TLSSocket library to your project. This library is included in Mbed OS 5.11 and up.

Tested on

  • K64F with Ethernet.
  • NUCLEO_F411RE with ESP8266.
  • ODIN-W2 with WiFi.
  • K64F with Atmel 6LoWPAN shield.
  • DISCO-L475VG-IOT01A with WiFi.
  • Mbed Simulator.
Committer:
Jan Jongboom
Date:
Thu Feb 16 11:35:56 2017 +0100
Revision:
0:910f5949759f
Child:
29:383e9bfbfbed
Initial commit

Who changed what in which revision?

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