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.
http_parser/http_parser.c@0:910f5949759f, 2017-02-16 (annotated)
- 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?
User | Revision | Line number | New 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 | } |