1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved. 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining a copy 4 * of this software and associated documentation files (the "Software"), to 5 * deal in the Software without restriction, including without limitation the 6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 * sell copies of the Software, and to permit persons to whom the Software is 8 * furnished to do so, subject to the following conditions: 9 * 10 * The above copyright notice and this permission notice shall be included in 11 * all copies or substantial portions of the Software. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 * IN THE SOFTWARE. 20 */ 21 #ifndef http_parser_h 22 #define http_parser_h 23 #ifdef __cplusplus 24 extern "C" { 25 #endif 26 27 /* Also update SONAME in the Makefile whenever you change these. */ 28 #define HTTP_PARSER_VERSION_MAJOR 2 29 #define HTTP_PARSER_VERSION_MINOR 1 30 #define HTTP_PARSER_VERSION_PATCH 0 31 32 #include <sys/types.h> 33 #if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600) 34 #include <BaseTsd.h> 35 #include <stddef.h> 36 typedef __int8 int8_t; 37 typedef unsigned __int8 uint8_t; 38 typedef __int16 int16_t; 39 typedef unsigned __int16 uint16_t; 40 typedef __int32 int32_t; 41 typedef unsigned __int32 uint32_t; 42 typedef __int64 int64_t; 43 typedef unsigned __int64 uint64_t; 44 #else 45 #include <stdint.h> 46 #endif 47 48 /* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run 49 * faster 50 */ 51 #ifndef HTTP_PARSER_STRICT 52 # define HTTP_PARSER_STRICT 1 53 #endif 54 55 /* Maximium header size allowed */ 56 #define HTTP_MAX_HEADER_SIZE (80*1024) 57 58 59 typedef struct http_parser http_parser; 60 typedef struct http_parser_settings http_parser_settings; 61 62 63 /* Callbacks should return non-zero to indicate an error. The parser will 64 * then halt execution. 65 * 66 * The one exception is on_headers_complete. In a HTTP_RESPONSE parser 67 * returning '1' from on_headers_complete will tell the parser that it 68 * should not expect a body. This is used when receiving a response to a 69 * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding: 70 * chunked' headers that indicate the presence of a body. 71 * 72 * http_data_cb does not return data chunks. It will be call arbitrarally 73 * many times for each string. E.G. you might get 10 callbacks for "on_url" 74 * each providing just a few characters more data. 75 */ 76 typedef int (*http_data_cb) (http_parser*, const char *at, size_t length); 77 typedef int (*http_cb) (http_parser*); 78 79 80 /* Request Methods */ 81 #define HTTP_METHOD_MAP(XX) \ 82 XX(0, DELETE, DELETE) \ 83 XX(1, GET, GET) \ 84 XX(2, HEAD, HEAD) \ 85 XX(3, POST, POST) \ 86 XX(4, PUT, PUT) \ 87 /* pathological */ \ 88 XX(5, CONNECT, CONNECT) \ 89 XX(6, OPTIONS, OPTIONS) \ 90 XX(7, TRACE, TRACE) \ 91 /* webdav */ \ 92 XX(8, COPY, COPY) \ 93 XX(9, LOCK, LOCK) \ 94 XX(10, MKCOL, MKCOL) \ 95 XX(11, MOVE, MOVE) \ 96 XX(12, PROPFIND, PROPFIND) \ 97 XX(13, PROPPATCH, PROPPATCH) \ 98 XX(14, SEARCH, SEARCH) \ 99 XX(15, UNLOCK, UNLOCK) \ 100 /* subversion */ \ 101 XX(16, REPORT, REPORT) \ 102 XX(17, MKACTIVITY, MKACTIVITY) \ 103 XX(18, CHECKOUT, CHECKOUT) \ 104 XX(19, MERGE, MERGE) \ 105 /* upnp */ \ 106 XX(20, MSEARCH, M-SEARCH) \ 107 XX(21, NOTIFY, NOTIFY) \ 108 XX(22, SUBSCRIBE, SUBSCRIBE) \ 109 XX(23, UNSUBSCRIBE, UNSUBSCRIBE) \ 110 /* RFC-5789 */ \ 111 XX(24, PATCH, PATCH) \ 112 XX(25, PURGE, PURGE) \ 113 114 enum http_method 115 { 116 #define XX(num, name, string) HTTP_##name = num, 117 HTTP_METHOD_MAP(XX) 118 #undef XX 119 }; 120 121 122 enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH }; 123 124 125 /* Flag values for http_parser.flags field */ 126 enum flags 127 { F_CHUNKED = 1 << 0 128 , F_CONNECTION_KEEP_ALIVE = 1 << 1 129 , F_CONNECTION_CLOSE = 1 << 2 130 , F_TRAILING = 1 << 3 131 , F_UPGRADE = 1 << 4 132 , F_SKIPBODY = 1 << 5 133 }; 134 135 136 /* Map for errno-related constants 137 * 138 * The provided argument should be a macro that takes 2 arguments. 139 */ 140 #define HTTP_ERRNO_MAP(XX) \ 141 /* No error */ \ 142 XX(OK, "success") \ 143 \ 144 /* Callback-related errors */ \ 145 XX(CB_message_begin, "the on_message_begin callback failed") \ 146 XX(CB_status_complete, "the on_status_complete callback failed") \ 147 XX(CB_url, "the on_url callback failed") \ 148 XX(CB_header_field, "the on_header_field callback failed") \ 149 XX(CB_header_value, "the on_header_value callback failed") \ 150 XX(CB_headers_complete, "the on_headers_complete callback failed") \ 151 XX(CB_body, "the on_body callback failed") \ 152 XX(CB_message_complete, "the on_message_complete callback failed") \ 153 \ 154 /* Parsing-related errors */ \ 155 XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \ 156 XX(HEADER_OVERFLOW, \ 157 "too many header bytes seen; overflow detected") \ 158 XX(CLOSED_CONNECTION, \ 159 "data received after completed connection: close message") \ 160 XX(INVALID_VERSION, "invalid HTTP version") \ 161 XX(INVALID_STATUS, "invalid HTTP status code") \ 162 XX(INVALID_METHOD, "invalid HTTP method") \ 163 XX(INVALID_URL, "invalid URL") \ 164 XX(INVALID_HOST, "invalid host") \ 165 XX(INVALID_PORT, "invalid port") \ 166 XX(INVALID_PATH, "invalid path") \ 167 XX(INVALID_QUERY_STRING, "invalid query string") \ 168 XX(INVALID_FRAGMENT, "invalid fragment") \ 169 XX(LF_EXPECTED, "LF character expected") \ 170 XX(INVALID_HEADER_TOKEN, "invalid character in header") \ 171 XX(INVALID_CONTENT_LENGTH, \ 172 "invalid character in content-length header") \ 173 XX(INVALID_CHUNK_SIZE, \ 174 "invalid character in chunk size header") \ 175 XX(INVALID_CONSTANT, "invalid constant string") \ 176 XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\ 177 XX(STRICT, "strict mode assertion failed") \ 178 XX(PAUSED, "parser is paused") \ 179 XX(UNKNOWN, "an unknown error occurred") 180 181 182 /* Define HPE_* values for each errno value above */ 183 #define HTTP_ERRNO_GEN(n, s) HPE_##n, 184 enum http_errno { 185 HTTP_ERRNO_MAP(HTTP_ERRNO_GEN) 186 }; 187 #undef HTTP_ERRNO_GEN 188 189 190 /* Get an http_errno value from an http_parser */ 191 #define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno) 192 193 194 struct http_parser { 195 /** PRIVATE **/ 196 unsigned char type : 2; /* enum http_parser_type */ 197 unsigned char flags : 6; /* F_* values from 'flags' enum; semi-public */ 198 unsigned char state; /* enum state from http_parser.c */ 199 unsigned char header_state; /* enum header_state from http_parser.c */ 200 unsigned char index; /* index into current matcher */ 201 202 uint32_t nread; /* # bytes read in various scenarios */ 203 uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */ 204 205 /** READ-ONLY **/ 206 unsigned short http_major; 207 unsigned short http_minor; 208 unsigned short status_code; /* responses only */ 209 unsigned char method; /* requests only */ 210 unsigned char http_errno : 7; 211 212 /* 1 = Upgrade header was present and the parser has exited because of that. 213 * 0 = No upgrade header present. 214 * Should be checked when http_parser_execute() returns in addition to 215 * error checking. 216 */ 217 unsigned char upgrade : 1; 218 219 /** PUBLIC **/ 220 void *data; /* A pointer to get hook to the "connection" or "socket" object */ 221 }; 222 223 224 struct http_parser_settings { 225 http_cb on_message_begin; 226 http_data_cb on_url; 227 http_cb on_status_complete; 228 http_data_cb on_header_field; 229 http_data_cb on_header_value; 230 http_cb on_headers_complete; 231 http_data_cb on_body; 232 http_cb on_message_complete; 233 }; 234 235 236 enum http_parser_url_fields 237 { UF_SCHEMA = 0 238 , UF_HOST = 1 239 , UF_PORT = 2 240 , UF_PATH = 3 241 , UF_QUERY = 4 242 , UF_FRAGMENT = 5 243 , UF_USERINFO = 6 244 , UF_MAX = 7 245 }; 246 247 248 /* Result structure for http_parser_parse_url(). 249 * 250 * Callers should index into field_data[] with UF_* values iff field_set 251 * has the relevant (1 << UF_*) bit set. As a courtesy to clients (and 252 * because we probably have padding left over), we convert any port to 253 * a uint16_t. 254 */ 255 struct http_parser_url { 256 uint16_t field_set; /* Bitmask of (1 << UF_*) values */ 257 uint16_t port; /* Converted UF_PORT string */ 258 259 struct { 260 uint16_t off; /* Offset into buffer in which field starts */ 261 uint16_t len; /* Length of run in buffer */ 262 } field_data[UF_MAX]; 263 }; 264 265 266 /* Returns the library version. Bits 16-23 contain the major version number, 267 * bits 8-15 the minor version number and bits 0-7 the patch level. 268 * Usage example: 269 * 270 * unsigned long version = http_parser_version(); 271 * unsigned major = (version >> 16) & 255; 272 * unsigned minor = (version >> 8) & 255; 273 * unsigned patch = version & 255; 274 * printf("http_parser v%u.%u.%u\n", major, minor, version); 275 */ 276 unsigned long http_parser_version(void); 277 278 void http_parser_init(http_parser *parser, enum http_parser_type type); 279 280 281 size_t http_parser_execute(http_parser *parser, 282 const http_parser_settings *settings, 283 const char *data, 284 size_t len); 285 286 287 /* If http_should_keep_alive() in the on_headers_complete or 288 * on_message_complete callback returns 0, then this should be 289 * the last message on the connection. 290 * If you are the server, respond with the "Connection: close" header. 291 * If you are the client, close the connection. 292 */ 293 int http_should_keep_alive(const http_parser *parser); 294 295 /* Returns a string version of the HTTP method. */ 296 const char *http_method_str(enum http_method m); 297 298 /* Return a string name of the given error */ 299 const char *http_errno_name(enum http_errno err); 300 301 /* Return a string description of the given error */ 302 const char *http_errno_description(enum http_errno err); 303 304 /* Parse a URL; return nonzero on failure */ 305 int http_parser_parse_url(const char *buf, size_t buflen, 306 int is_connect, 307 struct http_parser_url *u); 308 309 /* Pause or un-pause the parser; a nonzero value pauses */ 310 void http_parser_pause(http_parser *parser, int paused); 311 312 /* Checks if this is the final chunk of the body. */ 313 int http_body_is_final(const http_parser *parser); 314 315 #ifdef __cplusplus 316 } 317 #endif 318 #endif 319