HTTP and HTTPS library for Mbed OS 5

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

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

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

HTTP Request API

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

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

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

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

delete request; // also clears out the response

HTTPS Request API

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

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

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

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

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

delete request;

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

Mbed TLS Entropy configuration

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

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

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

Memory usage

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

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

Dealing with large response body

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

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

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

Dealing with a large request body

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

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

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

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

Socket re-use

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

HTTP

TCPSocket* socket = new TCPSocket();

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

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

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

HTTPS

TLSSocket* socket = new TLSSocket();

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

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

Request logging

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

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

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

Integration tests

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

Mbed OS 5.10 or lower

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

Tested on

  • K64F with Ethernet.
  • NUCLEO_F411RE with ESP8266.
  • ODIN-W2 with WiFi.
  • K64F with Atmel 6LoWPAN shield.
  • DISCO-L475VG-IOT01A with WiFi.
  • Mbed Simulator.
Committer:
Jan Jongboom
Date:
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?

UserRevisionLine numberNew 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