HTTP and HTTPS library for Mbed OS 5

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

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

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

HTTP Request API

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

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

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

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

delete request; // also clears out the response

HTTPS Request API

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

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

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

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

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

delete request;

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

Mbed TLS Entropy configuration

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

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

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

Memory usage

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

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

Dealing with large response body

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

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

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

Dealing with a large request body

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

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

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

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

Socket re-use

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

HTTP

TCPSocket* socket = new TCPSocket();

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

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

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

HTTPS

TLSSocket* socket = new TLSSocket();

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

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

Request logging

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

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

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

Integration tests

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

Mbed OS 5.10 or lower

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

Tested on

  • K64F with Ethernet.
  • NUCLEO_F411RE with ESP8266.
  • ODIN-W2 with WiFi.
  • K64F with Atmel 6LoWPAN shield.
  • DISCO-L475VG-IOT01A with WiFi.
  • Mbed Simulator.
Committer:
Jan Jongboom
Date:
Thu Feb 16 13:55:05 2017 +0100
Revision:
2:959baaa89148
Parent:
0:910f5949759f
Child:
29:383e9bfbfbed
Child:
31:b3730a2c4f39
size_t is not available in ARMCC

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