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.h@39:a8d157986ad8, 2019-08-12 (annotated)
- Committer:
- Jan Jongboom
- Date:
- Mon Aug 12 11:45:31 2019 +0200
- Revision:
- 39:a8d157986ad8
- Parent:
- 32:fa4d71265625
Fix parsed url leaking memory if path is empty
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Jan Jongboom |
0:910f5949759f | 1 | /* Copyright Joyent, Inc. and other Node contributors. All rights reserved. |
Jan Jongboom |
0:910f5949759f | 2 | * |
Jan Jongboom |
0:910f5949759f | 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
Jan Jongboom |
0:910f5949759f | 4 | * of this software and associated documentation files (the "Software"), to |
Jan Jongboom |
0:910f5949759f | 5 | * deal in the Software without restriction, including without limitation the |
Jan Jongboom |
0:910f5949759f | 6 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
Jan Jongboom |
0:910f5949759f | 7 | * sell copies of the Software, and to permit persons to whom the Software is |
Jan Jongboom |
0:910f5949759f | 8 | * furnished to do so, subject to the following conditions: |
Jan Jongboom |
0:910f5949759f | 9 | * |
Jan Jongboom |
0:910f5949759f | 10 | * The above copyright notice and this permission notice shall be included in |
Jan Jongboom |
0:910f5949759f | 11 | * all copies or substantial portions of the Software. |
Jan Jongboom |
0:910f5949759f | 12 | * |
Jan Jongboom |
0:910f5949759f | 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
Jan Jongboom |
0:910f5949759f | 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
Jan Jongboom |
0:910f5949759f | 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
Jan Jongboom |
0:910f5949759f | 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
Jan Jongboom |
0:910f5949759f | 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
Jan Jongboom |
0:910f5949759f | 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
Jan Jongboom |
0:910f5949759f | 19 | * IN THE SOFTWARE. |
Jan Jongboom |
0:910f5949759f | 20 | */ |
Jan Jongboom |
0:910f5949759f | 21 | #ifndef http_parser_h |
Jan Jongboom |
0:910f5949759f | 22 | #define http_parser_h |
Jan Jongboom |
31:b3730a2c4f39 | 23 | |
Jan Jongboom |
0:910f5949759f | 24 | #ifdef __cplusplus |
Jan Jongboom |
0:910f5949759f | 25 | extern "C" { |
Jan Jongboom |
0:910f5949759f | 26 | #endif |
Jan Jongboom |
0:910f5949759f | 27 | |
Jan Jongboom |
0:910f5949759f | 28 | /* Also update SONAME in the Makefile whenever you change these. */ |
Jan Jongboom |
0:910f5949759f | 29 | #define HTTP_PARSER_VERSION_MAJOR 2 |
Jan Jongboom |
0:910f5949759f | 30 | #define HTTP_PARSER_VERSION_MINOR 7 |
Jan Jongboom |
0:910f5949759f | 31 | #define HTTP_PARSER_VERSION_PATCH 1 |
Jan Jongboom |
0:910f5949759f | 32 | |
Jan Jongboom |
0:910f5949759f | 33 | #if defined(_WIN32) && !defined(__MINGW32__) && \ |
Jan Jongboom |
0:910f5949759f | 34 | (!defined(_MSC_VER) || _MSC_VER<1600) && !defined(__WINE__) |
Jan Jongboom |
0:910f5949759f | 35 | #include <BaseTsd.h> |
Jan Jongboom |
0:910f5949759f | 36 | #include <stddef.h> |
Jan Jongboom |
0:910f5949759f | 37 | typedef __int8 int8_t; |
Jan Jongboom |
0:910f5949759f | 38 | typedef unsigned __int8 uint8_t; |
Jan Jongboom |
0:910f5949759f | 39 | typedef __int16 int16_t; |
Jan Jongboom |
0:910f5949759f | 40 | typedef unsigned __int16 uint16_t; |
Jan Jongboom |
0:910f5949759f | 41 | typedef __int32 int32_t; |
Jan Jongboom |
0:910f5949759f | 42 | typedef unsigned __int32 uint32_t; |
Jan Jongboom |
0:910f5949759f | 43 | typedef __int64 int64_t; |
Jan Jongboom |
0:910f5949759f | 44 | typedef unsigned __int64 uint64_t; |
Jan Jongboom |
0:910f5949759f | 45 | #else |
Jan Jongboom |
0:910f5949759f | 46 | #include <stdint.h> |
Jan Jongboom |
0:910f5949759f | 47 | #endif |
Jan Jongboom |
0:910f5949759f | 48 | |
Jan Jongboom |
0:910f5949759f | 49 | /* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run |
Jan Jongboom |
0:910f5949759f | 50 | * faster |
Jan Jongboom |
0:910f5949759f | 51 | */ |
Jan Jongboom |
0:910f5949759f | 52 | #ifndef HTTP_PARSER_STRICT |
Jan Jongboom |
0:910f5949759f | 53 | # define HTTP_PARSER_STRICT 1 |
Jan Jongboom |
0:910f5949759f | 54 | #endif |
Jan Jongboom |
0:910f5949759f | 55 | |
Jan Jongboom |
0:910f5949759f | 56 | /* Maximium header size allowed. If the macro is not defined |
Jan Jongboom |
0:910f5949759f | 57 | * before including this header then the default is used. To |
Jan Jongboom |
0:910f5949759f | 58 | * change the maximum header size, define the macro in the build |
Jan Jongboom |
0:910f5949759f | 59 | * environment (e.g. -DHTTP_MAX_HEADER_SIZE=<value>). To remove |
Jan Jongboom |
0:910f5949759f | 60 | * the effective limit on the size of the header, define the macro |
Jan Jongboom |
0:910f5949759f | 61 | * to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff) |
Jan Jongboom |
0:910f5949759f | 62 | */ |
Jan Jongboom |
0:910f5949759f | 63 | #ifndef HTTP_MAX_HEADER_SIZE |
Jan Jongboom |
0:910f5949759f | 64 | # define HTTP_MAX_HEADER_SIZE (80*1024) |
Jan Jongboom |
0:910f5949759f | 65 | #endif |
Jan Jongboom |
0:910f5949759f | 66 | |
Jan Jongboom |
0:910f5949759f | 67 | typedef struct http_parser http_parser; |
Jan Jongboom |
0:910f5949759f | 68 | typedef struct http_parser_settings http_parser_settings; |
Jan Jongboom |
0:910f5949759f | 69 | |
Jan Jongboom |
0:910f5949759f | 70 | |
Jan Jongboom |
0:910f5949759f | 71 | /* Callbacks should return non-zero to indicate an error. The parser will |
Jan Jongboom |
0:910f5949759f | 72 | * then halt execution. |
Jan Jongboom |
0:910f5949759f | 73 | * |
Jan Jongboom |
0:910f5949759f | 74 | * The one exception is on_headers_complete. In a HTTP_RESPONSE parser |
Jan Jongboom |
0:910f5949759f | 75 | * returning '1' from on_headers_complete will tell the parser that it |
Jan Jongboom |
0:910f5949759f | 76 | * should not expect a body. This is used when receiving a response to a |
Jan Jongboom |
0:910f5949759f | 77 | * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding: |
Jan Jongboom |
0:910f5949759f | 78 | * chunked' headers that indicate the presence of a body. |
Jan Jongboom |
0:910f5949759f | 79 | * |
Jan Jongboom |
0:910f5949759f | 80 | * Returning `2` from on_headers_complete will tell parser that it should not |
Jan Jongboom |
0:910f5949759f | 81 | * expect neither a body nor any futher responses on this connection. This is |
Jan Jongboom |
0:910f5949759f | 82 | * useful for handling responses to a CONNECT request which may not contain |
Jan Jongboom |
0:910f5949759f | 83 | * `Upgrade` or `Connection: upgrade` headers. |
Jan Jongboom |
0:910f5949759f | 84 | * |
Jan Jongboom |
0:910f5949759f | 85 | * http_data_cb does not return data chunks. It will be called arbitrarily |
Jan Jongboom |
0:910f5949759f | 86 | * many times for each string. E.G. you might get 10 callbacks for "on_url" |
Jan Jongboom |
0:910f5949759f | 87 | * each providing just a few characters more data. |
Jan Jongboom |
0:910f5949759f | 88 | */ |
Jan Jongboom |
31:b3730a2c4f39 | 89 | typedef int (*http_data_cb) (http_parser*, const char *at, uint32_t length); |
Jan Jongboom |
0:910f5949759f | 90 | typedef int (*http_cb) (http_parser*); |
Jan Jongboom |
0:910f5949759f | 91 | |
Jan Jongboom |
0:910f5949759f | 92 | |
Jan Jongboom |
0:910f5949759f | 93 | /* Status Codes */ |
Jan Jongboom |
0:910f5949759f | 94 | #define HTTP_STATUS_MAP(XX) \ |
Jan Jongboom |
0:910f5949759f | 95 | XX(100, CONTINUE, Continue) \ |
Jan Jongboom |
0:910f5949759f | 96 | XX(101, SWITCHING_PROTOCOLS, Switching Protocols) \ |
Jan Jongboom |
0:910f5949759f | 97 | XX(102, PROCESSING, Processing) \ |
Jan Jongboom |
0:910f5949759f | 98 | XX(200, OK, OK) \ |
Jan Jongboom |
0:910f5949759f | 99 | XX(201, CREATED, Created) \ |
Jan Jongboom |
0:910f5949759f | 100 | XX(202, ACCEPTED, Accepted) \ |
Jan Jongboom |
0:910f5949759f | 101 | XX(203, NON_AUTHORITATIVE_INFORMATION, Non-Authoritative Information) \ |
Jan Jongboom |
0:910f5949759f | 102 | XX(204, NO_CONTENT, No Content) \ |
Jan Jongboom |
0:910f5949759f | 103 | XX(205, RESET_CONTENT, Reset Content) \ |
Jan Jongboom |
0:910f5949759f | 104 | XX(206, PARTIAL_CONTENT, Partial Content) \ |
Jan Jongboom |
0:910f5949759f | 105 | XX(207, MULTI_STATUS, Multi-Status) \ |
Jan Jongboom |
0:910f5949759f | 106 | XX(208, ALREADY_REPORTED, Already Reported) \ |
Jan Jongboom |
0:910f5949759f | 107 | XX(226, IM_USED, IM Used) \ |
Jan Jongboom |
0:910f5949759f | 108 | XX(300, MULTIPLE_CHOICES, Multiple Choices) \ |
Jan Jongboom |
0:910f5949759f | 109 | XX(301, MOVED_PERMANENTLY, Moved Permanently) \ |
Jan Jongboom |
0:910f5949759f | 110 | XX(302, FOUND, Found) \ |
Jan Jongboom |
0:910f5949759f | 111 | XX(303, SEE_OTHER, See Other) \ |
Jan Jongboom |
0:910f5949759f | 112 | XX(304, NOT_MODIFIED, Not Modified) \ |
Jan Jongboom |
0:910f5949759f | 113 | XX(305, USE_PROXY, Use Proxy) \ |
Jan Jongboom |
0:910f5949759f | 114 | XX(307, TEMPORARY_REDIRECT, Temporary Redirect) \ |
Jan Jongboom |
0:910f5949759f | 115 | XX(308, PERMANENT_REDIRECT, Permanent Redirect) \ |
Jan Jongboom |
0:910f5949759f | 116 | XX(400, BAD_REQUEST, Bad Request) \ |
Jan Jongboom |
0:910f5949759f | 117 | XX(401, UNAUTHORIZED, Unauthorized) \ |
Jan Jongboom |
0:910f5949759f | 118 | XX(402, PAYMENT_REQUIRED, Payment Required) \ |
Jan Jongboom |
0:910f5949759f | 119 | XX(403, FORBIDDEN, Forbidden) \ |
Jan Jongboom |
0:910f5949759f | 120 | XX(404, NOT_FOUND, Not Found) \ |
Jan Jongboom |
0:910f5949759f | 121 | XX(405, METHOD_NOT_ALLOWED, Method Not Allowed) \ |
Jan Jongboom |
0:910f5949759f | 122 | XX(406, NOT_ACCEPTABLE, Not Acceptable) \ |
Jan Jongboom |
0:910f5949759f | 123 | XX(407, PROXY_AUTHENTICATION_REQUIRED, Proxy Authentication Required) \ |
Jan Jongboom |
0:910f5949759f | 124 | XX(408, REQUEST_TIMEOUT, Request Timeout) \ |
Jan Jongboom |
0:910f5949759f | 125 | XX(409, CONFLICT, Conflict) \ |
Jan Jongboom |
0:910f5949759f | 126 | XX(410, GONE, Gone) \ |
Jan Jongboom |
0:910f5949759f | 127 | XX(411, LENGTH_REQUIRED, Length Required) \ |
Jan Jongboom |
0:910f5949759f | 128 | XX(412, PRECONDITION_FAILED, Precondition Failed) \ |
Jan Jongboom |
0:910f5949759f | 129 | XX(413, PAYLOAD_TOO_LARGE, Payload Too Large) \ |
Jan Jongboom |
0:910f5949759f | 130 | XX(414, URI_TOO_LONG, URI Too Long) \ |
Jan Jongboom |
0:910f5949759f | 131 | XX(415, UNSUPPORTED_MEDIA_TYPE, Unsupported Media Type) \ |
Jan Jongboom |
0:910f5949759f | 132 | XX(416, RANGE_NOT_SATISFIABLE, Range Not Satisfiable) \ |
Jan Jongboom |
0:910f5949759f | 133 | XX(417, EXPECTATION_FAILED, Expectation Failed) \ |
Jan Jongboom |
0:910f5949759f | 134 | XX(421, MISDIRECTED_REQUEST, Misdirected Request) \ |
Jan Jongboom |
0:910f5949759f | 135 | XX(422, UNPROCESSABLE_ENTITY, Unprocessable Entity) \ |
Jan Jongboom |
0:910f5949759f | 136 | XX(423, LOCKED, Locked) \ |
Jan Jongboom |
0:910f5949759f | 137 | XX(424, FAILED_DEPENDENCY, Failed Dependency) \ |
Jan Jongboom |
0:910f5949759f | 138 | XX(426, UPGRADE_REQUIRED, Upgrade Required) \ |
Jan Jongboom |
0:910f5949759f | 139 | XX(428, PRECONDITION_REQUIRED, Precondition Required) \ |
Jan Jongboom |
0:910f5949759f | 140 | XX(429, TOO_MANY_REQUESTS, Too Many Requests) \ |
Jan Jongboom |
0:910f5949759f | 141 | XX(431, REQUEST_HEADER_FIELDS_TOO_LARGE, Request Header Fields Too Large) \ |
Jan Jongboom |
0:910f5949759f | 142 | XX(451, UNAVAILABLE_FOR_LEGAL_REASONS, Unavailable For Legal Reasons) \ |
Jan Jongboom |
0:910f5949759f | 143 | XX(500, INTERNAL_SERVER_ERROR, Internal Server Error) \ |
Jan Jongboom |
0:910f5949759f | 144 | XX(501, NOT_IMPLEMENTED, Not Implemented) \ |
Jan Jongboom |
0:910f5949759f | 145 | XX(502, BAD_GATEWAY, Bad Gateway) \ |
Jan Jongboom |
0:910f5949759f | 146 | XX(503, SERVICE_UNAVAILABLE, Service Unavailable) \ |
Jan Jongboom |
0:910f5949759f | 147 | XX(504, GATEWAY_TIMEOUT, Gateway Timeout) \ |
Jan Jongboom |
0:910f5949759f | 148 | XX(505, HTTP_VERSION_NOT_SUPPORTED, HTTP Version Not Supported) \ |
Jan Jongboom |
0:910f5949759f | 149 | XX(506, VARIANT_ALSO_NEGOTIATES, Variant Also Negotiates) \ |
Jan Jongboom |
0:910f5949759f | 150 | XX(507, INSUFFICIENT_STORAGE, Insufficient Storage) \ |
Jan Jongboom |
0:910f5949759f | 151 | XX(508, LOOP_DETECTED, Loop Detected) \ |
Jan Jongboom |
0:910f5949759f | 152 | XX(510, NOT_EXTENDED, Not Extended) \ |
Jan Jongboom |
0:910f5949759f | 153 | XX(511, NETWORK_AUTHENTICATION_REQUIRED, Network Authentication Required) \ |
Jan Jongboom |
0:910f5949759f | 154 | |
Jan Jongboom |
0:910f5949759f | 155 | enum http_status |
Jan Jongboom |
0:910f5949759f | 156 | { |
Jan Jongboom |
0:910f5949759f | 157 | #define XX(num, name, string) HTTP_STATUS_##name = num, |
Jan Jongboom |
0:910f5949759f | 158 | HTTP_STATUS_MAP(XX) |
Jan Jongboom |
0:910f5949759f | 159 | #undef XX |
Jan Jongboom |
0:910f5949759f | 160 | }; |
Jan Jongboom |
0:910f5949759f | 161 | |
Jan Jongboom |
0:910f5949759f | 162 | |
Jan Jongboom |
0:910f5949759f | 163 | /* Request Methods */ |
Jan Jongboom |
0:910f5949759f | 164 | #define HTTP_METHOD_MAP(XX) \ |
Jan Jongboom |
0:910f5949759f | 165 | XX(0, DELETE, DELETE) \ |
Jan Jongboom |
0:910f5949759f | 166 | XX(1, GET, GET) \ |
Jan Jongboom |
0:910f5949759f | 167 | XX(2, HEAD, HEAD) \ |
Jan Jongboom |
0:910f5949759f | 168 | XX(3, POST, POST) \ |
Jan Jongboom |
0:910f5949759f | 169 | XX(4, PUT, PUT) \ |
Jan Jongboom |
0:910f5949759f | 170 | /* pathological */ \ |
Jan Jongboom |
0:910f5949759f | 171 | XX(5, CONNECT, CONNECT) \ |
Jan Jongboom |
0:910f5949759f | 172 | XX(6, OPTIONS, OPTIONS) \ |
Jan Jongboom |
0:910f5949759f | 173 | XX(7, TRACE, TRACE) \ |
Jan Jongboom |
0:910f5949759f | 174 | /* WebDAV */ \ |
Jan Jongboom |
0:910f5949759f | 175 | XX(8, COPY, COPY) \ |
Jan Jongboom |
0:910f5949759f | 176 | XX(9, LOCK, LOCK) \ |
Jan Jongboom |
0:910f5949759f | 177 | XX(10, MKCOL, MKCOL) \ |
Jan Jongboom |
0:910f5949759f | 178 | XX(11, MOVE, MOVE) \ |
Jan Jongboom |
0:910f5949759f | 179 | XX(12, PROPFIND, PROPFIND) \ |
Jan Jongboom |
0:910f5949759f | 180 | XX(13, PROPPATCH, PROPPATCH) \ |
Jan Jongboom |
0:910f5949759f | 181 | XX(14, SEARCH, SEARCH) \ |
Jan Jongboom |
0:910f5949759f | 182 | XX(15, UNLOCK, UNLOCK) \ |
Jan Jongboom |
0:910f5949759f | 183 | XX(16, BIND, BIND) \ |
Jan Jongboom |
0:910f5949759f | 184 | XX(17, REBIND, REBIND) \ |
Jan Jongboom |
0:910f5949759f | 185 | XX(18, UNBIND, UNBIND) \ |
Jan Jongboom |
0:910f5949759f | 186 | XX(19, ACL, ACL) \ |
Jan Jongboom |
0:910f5949759f | 187 | /* subversion */ \ |
Jan Jongboom |
0:910f5949759f | 188 | XX(20, REPORT, REPORT) \ |
Jan Jongboom |
0:910f5949759f | 189 | XX(21, MKACTIVITY, MKACTIVITY) \ |
Jan Jongboom |
0:910f5949759f | 190 | XX(22, CHECKOUT, CHECKOUT) \ |
Jan Jongboom |
0:910f5949759f | 191 | XX(23, MERGE, MERGE) \ |
Jan Jongboom |
0:910f5949759f | 192 | /* upnp */ \ |
Jan Jongboom |
0:910f5949759f | 193 | XX(24, MSEARCH, M-SEARCH) \ |
Jan Jongboom |
0:910f5949759f | 194 | XX(25, NOTIFY, NOTIFY) \ |
Jan Jongboom |
0:910f5949759f | 195 | XX(26, SUBSCRIBE, SUBSCRIBE) \ |
Jan Jongboom |
0:910f5949759f | 196 | XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \ |
Jan Jongboom |
0:910f5949759f | 197 | /* RFC-5789 */ \ |
Jan Jongboom |
0:910f5949759f | 198 | XX(28, PATCH, PATCH) \ |
Jan Jongboom |
0:910f5949759f | 199 | XX(29, PURGE, PURGE) \ |
Jan Jongboom |
0:910f5949759f | 200 | /* CalDAV */ \ |
Jan Jongboom |
0:910f5949759f | 201 | XX(30, MKCALENDAR, MKCALENDAR) \ |
Jan Jongboom |
0:910f5949759f | 202 | /* RFC-2068, section 19.6.1.2 */ \ |
Jan Jongboom |
0:910f5949759f | 203 | XX(31, LINK, LINK) \ |
Jan Jongboom |
0:910f5949759f | 204 | XX(32, UNLINK, UNLINK) \ |
Jan Jongboom |
0:910f5949759f | 205 | |
Jan Jongboom |
0:910f5949759f | 206 | enum http_method |
Jan Jongboom |
0:910f5949759f | 207 | { |
Jan Jongboom |
0:910f5949759f | 208 | #define XX(num, name, string) HTTP_##name = num, |
Jan Jongboom |
0:910f5949759f | 209 | HTTP_METHOD_MAP(XX) |
Jan Jongboom |
0:910f5949759f | 210 | #undef XX |
Jan Jongboom |
0:910f5949759f | 211 | }; |
Jan Jongboom |
0:910f5949759f | 212 | |
Jan Jongboom |
0:910f5949759f | 213 | |
Jan Jongboom |
0:910f5949759f | 214 | enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH }; |
Jan Jongboom |
0:910f5949759f | 215 | |
Jan Jongboom |
0:910f5949759f | 216 | |
Jan Jongboom |
0:910f5949759f | 217 | /* Flag values for http_parser.flags field */ |
Jan Jongboom |
0:910f5949759f | 218 | enum flags |
Jan Jongboom |
0:910f5949759f | 219 | { F_CHUNKED = 1 << 0 |
Jan Jongboom |
0:910f5949759f | 220 | , F_CONNECTION_KEEP_ALIVE = 1 << 1 |
Jan Jongboom |
0:910f5949759f | 221 | , F_CONNECTION_CLOSE = 1 << 2 |
Jan Jongboom |
0:910f5949759f | 222 | , F_CONNECTION_UPGRADE = 1 << 3 |
Jan Jongboom |
0:910f5949759f | 223 | , F_TRAILING = 1 << 4 |
Jan Jongboom |
0:910f5949759f | 224 | , F_UPGRADE = 1 << 5 |
Jan Jongboom |
0:910f5949759f | 225 | , F_SKIPBODY = 1 << 6 |
Jan Jongboom |
0:910f5949759f | 226 | , F_CONTENTLENGTH = 1 << 7 |
Jan Jongboom |
0:910f5949759f | 227 | }; |
Jan Jongboom |
0:910f5949759f | 228 | |
Jan Jongboom |
0:910f5949759f | 229 | |
Jan Jongboom |
0:910f5949759f | 230 | /* Map for errno-related constants |
Jan Jongboom |
0:910f5949759f | 231 | * |
Jan Jongboom |
0:910f5949759f | 232 | * The provided argument should be a macro that takes 2 arguments. |
Jan Jongboom |
0:910f5949759f | 233 | */ |
Jan Jongboom |
0:910f5949759f | 234 | #define HTTP_ERRNO_MAP(XX) \ |
Jan Jongboom |
0:910f5949759f | 235 | /* No error */ \ |
Jan Jongboom |
0:910f5949759f | 236 | XX(OK, "success") \ |
Jan Jongboom |
0:910f5949759f | 237 | \ |
Jan Jongboom |
0:910f5949759f | 238 | /* Callback-related errors */ \ |
Jan Jongboom |
0:910f5949759f | 239 | XX(CB_message_begin, "the on_message_begin callback failed") \ |
Jan Jongboom |
0:910f5949759f | 240 | XX(CB_url, "the on_url callback failed") \ |
Jan Jongboom |
0:910f5949759f | 241 | XX(CB_header_field, "the on_header_field callback failed") \ |
Jan Jongboom |
0:910f5949759f | 242 | XX(CB_header_value, "the on_header_value callback failed") \ |
Jan Jongboom |
0:910f5949759f | 243 | XX(CB_headers_complete, "the on_headers_complete callback failed") \ |
Jan Jongboom |
0:910f5949759f | 244 | XX(CB_body, "the on_body callback failed") \ |
Jan Jongboom |
0:910f5949759f | 245 | XX(CB_message_complete, "the on_message_complete callback failed") \ |
Jan Jongboom |
0:910f5949759f | 246 | XX(CB_status, "the on_status callback failed") \ |
Jan Jongboom |
0:910f5949759f | 247 | XX(CB_chunk_header, "the on_chunk_header callback failed") \ |
Jan Jongboom |
0:910f5949759f | 248 | XX(CB_chunk_complete, "the on_chunk_complete callback failed") \ |
Jan Jongboom |
0:910f5949759f | 249 | \ |
Jan Jongboom |
0:910f5949759f | 250 | /* Parsing-related errors */ \ |
Jan Jongboom |
0:910f5949759f | 251 | XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \ |
Jan Jongboom |
0:910f5949759f | 252 | XX(HEADER_OVERFLOW, \ |
Jan Jongboom |
0:910f5949759f | 253 | "too many header bytes seen; overflow detected") \ |
Jan Jongboom |
0:910f5949759f | 254 | XX(CLOSED_CONNECTION, \ |
Jan Jongboom |
0:910f5949759f | 255 | "data received after completed connection: close message") \ |
Jan Jongboom |
0:910f5949759f | 256 | XX(INVALID_VERSION, "invalid HTTP version") \ |
Jan Jongboom |
0:910f5949759f | 257 | XX(INVALID_STATUS, "invalid HTTP status code") \ |
Jan Jongboom |
0:910f5949759f | 258 | XX(INVALID_METHOD, "invalid HTTP method") \ |
Jan Jongboom |
0:910f5949759f | 259 | XX(INVALID_URL, "invalid URL") \ |
Jan Jongboom |
0:910f5949759f | 260 | XX(INVALID_HOST, "invalid host") \ |
Jan Jongboom |
0:910f5949759f | 261 | XX(INVALID_PORT, "invalid port") \ |
Jan Jongboom |
0:910f5949759f | 262 | XX(INVALID_PATH, "invalid path") \ |
Jan Jongboom |
0:910f5949759f | 263 | XX(INVALID_QUERY_STRING, "invalid query string") \ |
Jan Jongboom |
0:910f5949759f | 264 | XX(INVALID_FRAGMENT, "invalid fragment") \ |
Jan Jongboom |
0:910f5949759f | 265 | XX(LF_EXPECTED, "LF character expected") \ |
Jan Jongboom |
0:910f5949759f | 266 | XX(INVALID_HEADER_TOKEN, "invalid character in header") \ |
Jan Jongboom |
0:910f5949759f | 267 | XX(INVALID_CONTENT_LENGTH, \ |
Jan Jongboom |
0:910f5949759f | 268 | "invalid character in content-length header") \ |
Jan Jongboom |
0:910f5949759f | 269 | XX(UNEXPECTED_CONTENT_LENGTH, \ |
Jan Jongboom |
0:910f5949759f | 270 | "unexpected content-length header") \ |
Jan Jongboom |
0:910f5949759f | 271 | XX(INVALID_CHUNK_SIZE, \ |
Jan Jongboom |
0:910f5949759f | 272 | "invalid character in chunk size header") \ |
Jan Jongboom |
0:910f5949759f | 273 | XX(INVALID_CONSTANT, "invalid constant string") \ |
Jan Jongboom |
0:910f5949759f | 274 | XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\ |
Jan Jongboom |
0:910f5949759f | 275 | XX(STRICT, "strict mode assertion failed") \ |
Jan Jongboom |
0:910f5949759f | 276 | XX(PAUSED, "parser is paused") \ |
Jan Jongboom |
0:910f5949759f | 277 | XX(UNKNOWN, "an unknown error occurred") |
Jan Jongboom |
0:910f5949759f | 278 | |
Jan Jongboom |
0:910f5949759f | 279 | |
Jan Jongboom |
0:910f5949759f | 280 | /* Define HPE_* values for each errno value above */ |
Jan Jongboom |
0:910f5949759f | 281 | #define HTTP_ERRNO_GEN(n, s) HPE_##n, |
Jan Jongboom |
0:910f5949759f | 282 | enum http_errno { |
Jan Jongboom |
0:910f5949759f | 283 | HTTP_ERRNO_MAP(HTTP_ERRNO_GEN) |
Jan Jongboom |
0:910f5949759f | 284 | }; |
Jan Jongboom |
0:910f5949759f | 285 | #undef HTTP_ERRNO_GEN |
Jan Jongboom |
0:910f5949759f | 286 | |
Jan Jongboom |
0:910f5949759f | 287 | |
Jan Jongboom |
0:910f5949759f | 288 | /* Get an http_errno value from an http_parser */ |
Jan Jongboom |
0:910f5949759f | 289 | #define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno) |
Jan Jongboom |
0:910f5949759f | 290 | |
Jan Jongboom |
0:910f5949759f | 291 | |
Jan Jongboom |
0:910f5949759f | 292 | struct http_parser { |
Jan Jongboom |
0:910f5949759f | 293 | /** PRIVATE **/ |
Jan Jongboom |
0:910f5949759f | 294 | unsigned int type : 2; /* enum http_parser_type */ |
Jan Jongboom |
0:910f5949759f | 295 | unsigned int flags : 8; /* F_* values from 'flags' enum; semi-public */ |
Jan Jongboom |
0:910f5949759f | 296 | unsigned int state : 7; /* enum state from http_parser.c */ |
Jan Jongboom |
0:910f5949759f | 297 | unsigned int header_state : 7; /* enum header_state from http_parser.c */ |
Jan Jongboom |
0:910f5949759f | 298 | unsigned int index : 7; /* index into current matcher */ |
Jan Jongboom |
0:910f5949759f | 299 | unsigned int lenient_http_headers : 1; |
Jan Jongboom |
0:910f5949759f | 300 | |
Jan Jongboom |
0:910f5949759f | 301 | uint32_t nread; /* # bytes read in various scenarios */ |
Jan Jongboom |
0:910f5949759f | 302 | uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */ |
Jan Jongboom |
0:910f5949759f | 303 | |
Jan Jongboom |
0:910f5949759f | 304 | /** READ-ONLY **/ |
Jan Jongboom |
0:910f5949759f | 305 | unsigned short http_major; |
Jan Jongboom |
0:910f5949759f | 306 | unsigned short http_minor; |
Jan Jongboom |
0:910f5949759f | 307 | unsigned int status_code : 16; /* responses only */ |
Jan Jongboom |
0:910f5949759f | 308 | unsigned int method : 8; /* requests only */ |
Jan Jongboom |
0:910f5949759f | 309 | unsigned int http_errno : 7; |
Jan Jongboom |
0:910f5949759f | 310 | |
Jan Jongboom |
0:910f5949759f | 311 | /* 1 = Upgrade header was present and the parser has exited because of that. |
Jan Jongboom |
0:910f5949759f | 312 | * 0 = No upgrade header present. |
Jan Jongboom |
0:910f5949759f | 313 | * Should be checked when http_parser_execute() returns in addition to |
Jan Jongboom |
0:910f5949759f | 314 | * error checking. |
Jan Jongboom |
0:910f5949759f | 315 | */ |
Jan Jongboom |
0:910f5949759f | 316 | unsigned int upgrade : 1; |
Jan Jongboom |
0:910f5949759f | 317 | |
Jan Jongboom |
0:910f5949759f | 318 | /** PUBLIC **/ |
Jan Jongboom |
0:910f5949759f | 319 | void *data; /* A pointer to get hook to the "connection" or "socket" object */ |
Jan Jongboom |
0:910f5949759f | 320 | }; |
Jan Jongboom |
0:910f5949759f | 321 | |
Jan Jongboom |
0:910f5949759f | 322 | |
Jan Jongboom |
0:910f5949759f | 323 | struct http_parser_settings { |
Jan Jongboom |
0:910f5949759f | 324 | http_cb on_message_begin; |
Jan Jongboom |
0:910f5949759f | 325 | http_data_cb on_url; |
Jan Jongboom |
0:910f5949759f | 326 | http_data_cb on_status; |
Jan Jongboom |
0:910f5949759f | 327 | http_data_cb on_header_field; |
Jan Jongboom |
0:910f5949759f | 328 | http_data_cb on_header_value; |
Jan Jongboom |
0:910f5949759f | 329 | http_cb on_headers_complete; |
Jan Jongboom |
0:910f5949759f | 330 | http_data_cb on_body; |
Jan Jongboom |
0:910f5949759f | 331 | http_cb on_message_complete; |
Jan Jongboom |
0:910f5949759f | 332 | /* When on_chunk_header is called, the current chunk length is stored |
Jan Jongboom |
0:910f5949759f | 333 | * in parser->content_length. |
Jan Jongboom |
0:910f5949759f | 334 | */ |
Jan Jongboom |
0:910f5949759f | 335 | http_cb on_chunk_header; |
Jan Jongboom |
0:910f5949759f | 336 | http_cb on_chunk_complete; |
Jan Jongboom |
0:910f5949759f | 337 | }; |
Jan Jongboom |
0:910f5949759f | 338 | |
Jan Jongboom |
0:910f5949759f | 339 | |
Jan Jongboom |
0:910f5949759f | 340 | enum http_parser_url_fields |
Jan Jongboom |
0:910f5949759f | 341 | { UF_SCHEMA = 0 |
Jan Jongboom |
0:910f5949759f | 342 | , UF_HOST = 1 |
Jan Jongboom |
0:910f5949759f | 343 | , UF_PORT = 2 |
Jan Jongboom |
0:910f5949759f | 344 | , UF_PATH = 3 |
Jan Jongboom |
0:910f5949759f | 345 | , UF_QUERY = 4 |
Jan Jongboom |
0:910f5949759f | 346 | , UF_FRAGMENT = 5 |
Jan Jongboom |
0:910f5949759f | 347 | , UF_USERINFO = 6 |
Jan Jongboom |
0:910f5949759f | 348 | , UF_MAX = 7 |
Jan Jongboom |
0:910f5949759f | 349 | }; |
Jan Jongboom |
0:910f5949759f | 350 | |
Jan Jongboom |
0:910f5949759f | 351 | |
Jan Jongboom |
0:910f5949759f | 352 | /* Result structure for http_parser_parse_url(). |
Jan Jongboom |
0:910f5949759f | 353 | * |
Jan Jongboom |
0:910f5949759f | 354 | * Callers should index into field_data[] with UF_* values iff field_set |
Jan Jongboom |
0:910f5949759f | 355 | * has the relevant (1 << UF_*) bit set. As a courtesy to clients (and |
Jan Jongboom |
0:910f5949759f | 356 | * because we probably have padding left over), we convert any port to |
Jan Jongboom |
0:910f5949759f | 357 | * a uint16_t. |
Jan Jongboom |
0:910f5949759f | 358 | */ |
Jan Jongboom |
0:910f5949759f | 359 | struct http_parser_url { |
Jan Jongboom |
0:910f5949759f | 360 | uint16_t field_set; /* Bitmask of (1 << UF_*) values */ |
Jan Jongboom |
0:910f5949759f | 361 | uint16_t port; /* Converted UF_PORT string */ |
Jan Jongboom |
0:910f5949759f | 362 | |
Jan Jongboom |
0:910f5949759f | 363 | struct { |
Jan Jongboom |
0:910f5949759f | 364 | uint16_t off; /* Offset into buffer in which field starts */ |
Jan Jongboom |
0:910f5949759f | 365 | uint16_t len; /* Length of run in buffer */ |
Jan Jongboom |
0:910f5949759f | 366 | } field_data[UF_MAX]; |
Jan Jongboom |
0:910f5949759f | 367 | }; |
Jan Jongboom |
0:910f5949759f | 368 | |
Jan Jongboom |
0:910f5949759f | 369 | |
Jan Jongboom |
0:910f5949759f | 370 | /* Returns the library version. Bits 16-23 contain the major version number, |
Jan Jongboom |
0:910f5949759f | 371 | * bits 8-15 the minor version number and bits 0-7 the patch level. |
Jan Jongboom |
0:910f5949759f | 372 | * Usage example: |
Jan Jongboom |
0:910f5949759f | 373 | * |
Jan Jongboom |
0:910f5949759f | 374 | * unsigned long version = http_parser_version(); |
Jan Jongboom |
0:910f5949759f | 375 | * unsigned major = (version >> 16) & 255; |
Jan Jongboom |
0:910f5949759f | 376 | * unsigned minor = (version >> 8) & 255; |
Jan Jongboom |
0:910f5949759f | 377 | * unsigned patch = version & 255; |
Jan Jongboom |
0:910f5949759f | 378 | * printf("http_parser v%u.%u.%u\n", major, minor, patch); |
Jan Jongboom |
0:910f5949759f | 379 | */ |
Jan Jongboom |
0:910f5949759f | 380 | unsigned long http_parser_version(void); |
Jan Jongboom |
0:910f5949759f | 381 | |
Jan Jongboom |
0:910f5949759f | 382 | void http_parser_init(http_parser *parser, enum http_parser_type type); |
Jan Jongboom |
0:910f5949759f | 383 | |
Jan Jongboom |
0:910f5949759f | 384 | |
Jan Jongboom |
0:910f5949759f | 385 | /* Initialize http_parser_settings members to 0 |
Jan Jongboom |
0:910f5949759f | 386 | */ |
Jan Jongboom |
0:910f5949759f | 387 | void http_parser_settings_init(http_parser_settings *settings); |
Jan Jongboom |
0:910f5949759f | 388 | |
Jan Jongboom |
0:910f5949759f | 389 | |
Jan Jongboom |
0:910f5949759f | 390 | /* Executes the parser. Returns number of parsed bytes. Sets |
Jan Jongboom |
0:910f5949759f | 391 | * `parser->http_errno` on error. */ |
Jan Jongboom |
31:b3730a2c4f39 | 392 | uint32_t http_parser_execute(http_parser *parser, |
Jan Jongboom |
0:910f5949759f | 393 | const http_parser_settings *settings, |
Jan Jongboom |
0:910f5949759f | 394 | const char *data, |
Jan Jongboom |
31:b3730a2c4f39 | 395 | uint32_t len); |
Jan Jongboom |
0:910f5949759f | 396 | |
Jan Jongboom |
0:910f5949759f | 397 | |
Jan Jongboom |
0:910f5949759f | 398 | /* If http_should_keep_alive() in the on_headers_complete or |
Jan Jongboom |
0:910f5949759f | 399 | * on_message_complete callback returns 0, then this should be |
Jan Jongboom |
0:910f5949759f | 400 | * the last message on the connection. |
Jan Jongboom |
0:910f5949759f | 401 | * If you are the server, respond with the "Connection: close" header. |
Jan Jongboom |
0:910f5949759f | 402 | * If you are the client, close the connection. |
Jan Jongboom |
0:910f5949759f | 403 | */ |
Jan Jongboom |
0:910f5949759f | 404 | int http_should_keep_alive(const http_parser *parser); |
Jan Jongboom |
0:910f5949759f | 405 | |
Jan Jongboom |
0:910f5949759f | 406 | /* Returns a string version of the HTTP method. */ |
Jan Jongboom |
0:910f5949759f | 407 | const char *http_method_str(enum http_method m); |
Jan Jongboom |
0:910f5949759f | 408 | |
Jan Jongboom |
0:910f5949759f | 409 | /* Return a string name of the given error */ |
Jan Jongboom |
0:910f5949759f | 410 | const char *http_errno_name(enum http_errno err); |
Jan Jongboom |
0:910f5949759f | 411 | |
Jan Jongboom |
0:910f5949759f | 412 | /* Return a string description of the given error */ |
Jan Jongboom |
0:910f5949759f | 413 | const char *http_errno_description(enum http_errno err); |
Jan Jongboom |
0:910f5949759f | 414 | |
Jan Jongboom |
0:910f5949759f | 415 | /* Initialize all http_parser_url members to 0 */ |
Jan Jongboom |
0:910f5949759f | 416 | void http_parser_url_init(struct http_parser_url *u); |
Jan Jongboom |
0:910f5949759f | 417 | |
Jan Jongboom |
0:910f5949759f | 418 | /* Parse a URL; return nonzero on failure */ |
Jan Jongboom |
31:b3730a2c4f39 | 419 | int http_parser_parse_url(const char *buf, uint32_t buflen, |
Jan Jongboom |
0:910f5949759f | 420 | int is_connect, |
Jan Jongboom |
0:910f5949759f | 421 | struct http_parser_url *u); |
Jan Jongboom |
0:910f5949759f | 422 | |
Jan Jongboom |
0:910f5949759f | 423 | /* Pause or un-pause the parser; a nonzero value pauses */ |
Jan Jongboom |
0:910f5949759f | 424 | void http_parser_pause(http_parser *parser, int paused); |
Jan Jongboom |
0:910f5949759f | 425 | |
Jan Jongboom |
0:910f5949759f | 426 | /* Checks if this is the final chunk of the body. */ |
Jan Jongboom |
0:910f5949759f | 427 | int http_body_is_final(const http_parser *parser); |
Jan Jongboom |
0:910f5949759f | 428 | |
Jan Jongboom |
0:910f5949759f | 429 | #ifdef __cplusplus |
Jan Jongboom |
0:910f5949759f | 430 | } |
Jan Jongboom |
0:910f5949759f | 431 | #endif |
Jan Jongboom |
0:910f5949759f | 432 | #endif |