File indexing completed on 2025-01-26 04:24:51
0001 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved. 0002 * 0003 * Permission is hereby granted, free of charge, to any person obtaining a copy 0004 * of this software and associated documentation files (the "Software"), to 0005 * deal in the Software without restriction, including without limitation the 0006 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 0007 * sell copies of the Software, and to permit persons to whom the Software is 0008 * furnished to do so, subject to the following conditions: 0009 * 0010 * The above copyright notice and this permission notice shall be included in 0011 * all copies or substantial portions of the Software. 0012 * 0013 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 0014 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 0015 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 0016 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 0017 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 0018 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 0019 * IN THE SOFTWARE. 0020 */ 0021 #ifndef http_parser_h 0022 #define http_parser_h 0023 #ifdef __cplusplus 0024 extern "C" { 0025 #endif 0026 0027 #define HTTP_PARSER_VERSION_MAJOR 2 0028 #define HTTP_PARSER_VERSION_MINOR 0 0029 0030 #include <sys/types.h> 0031 #if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600) 0032 #include <BaseTsd.h> 0033 #include <stddef.h> 0034 typedef __int8 int8_t; 0035 typedef unsigned __int8 uint8_t; 0036 typedef __int16 int16_t; 0037 typedef unsigned __int16 uint16_t; 0038 typedef __int32 int32_t; 0039 typedef unsigned __int32 uint32_t; 0040 typedef __int64 int64_t; 0041 typedef unsigned __int64 uint64_t; 0042 #else 0043 #include <stdint.h> 0044 #endif 0045 0046 /* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run 0047 * faster 0048 */ 0049 #ifndef HTTP_PARSER_STRICT 0050 # define HTTP_PARSER_STRICT 1 0051 #endif 0052 0053 /* Maximium header size allowed */ 0054 #define HTTP_MAX_HEADER_SIZE (80*1024) 0055 0056 0057 typedef struct http_parser http_parser; 0058 typedef struct http_parser_settings http_parser_settings; 0059 0060 0061 /* Callbacks should return non-zero to indicate an error. The parser will 0062 * then halt execution. 0063 * 0064 * The one exception is on_headers_complete. In a HTTP_RESPONSE parser 0065 * returning '1' from on_headers_complete will tell the parser that it 0066 * should not expect a body. This is used when receiving a response to a 0067 * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding: 0068 * chunked' headers that indicate the presence of a body. 0069 * 0070 * http_data_cb does not return data chunks. It will be call arbitrarally 0071 * many times for each string. E.G. you might get 10 callbacks for "on_url" 0072 * each providing just a few characters more data. 0073 */ 0074 typedef int (*http_data_cb) (http_parser*, const char *at, size_t length); 0075 typedef int (*http_cb) (http_parser*); 0076 0077 0078 /* Request Methods */ 0079 #define HTTP_METHOD_MAP(XX) \ 0080 XX(0, DELETE, DELETE) \ 0081 XX(1, GET, GET) \ 0082 XX(2, HEAD, HEAD) \ 0083 XX(3, POST, POST) \ 0084 XX(4, PUT, PUT) \ 0085 /* pathological */ \ 0086 XX(5, CONNECT, CONNECT) \ 0087 XX(6, OPTIONS, OPTIONS) \ 0088 XX(7, TRACE, TRACE) \ 0089 /* webdav */ \ 0090 XX(8, COPY, COPY) \ 0091 XX(9, LOCK, LOCK) \ 0092 XX(10, MKCOL, MKCOL) \ 0093 XX(11, MOVE, MOVE) \ 0094 XX(12, PROPFIND, PROPFIND) \ 0095 XX(13, PROPPATCH, PROPPATCH) \ 0096 XX(14, SEARCH, SEARCH) \ 0097 XX(15, UNLOCK, UNLOCK) \ 0098 /* subversion */ \ 0099 XX(16, REPORT, REPORT) \ 0100 XX(17, MKACTIVITY, MKACTIVITY) \ 0101 XX(18, CHECKOUT, CHECKOUT) \ 0102 XX(19, MERGE, MERGE) \ 0103 /* upnp */ \ 0104 XX(20, MSEARCH, M-SEARCH) \ 0105 XX(21, NOTIFY, NOTIFY) \ 0106 XX(22, SUBSCRIBE, SUBSCRIBE) \ 0107 XX(23, UNSUBSCRIBE, UNSUBSCRIBE) \ 0108 /* RFC-5789 */ \ 0109 XX(24, PATCH, PATCH) \ 0110 XX(25, PURGE, PURGE) \ 0111 0112 enum http_method 0113 { 0114 #define XX(num, name, string) HTTP_##name = num, 0115 HTTP_METHOD_MAP(XX) 0116 #undef XX 0117 }; 0118 0119 0120 enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH }; 0121 0122 0123 /* Flag values for http_parser.flags field */ 0124 enum flags 0125 { F_CHUNKED = 1 << 0 0126 , F_CONNECTION_KEEP_ALIVE = 1 << 1 0127 , F_CONNECTION_CLOSE = 1 << 2 0128 , F_TRAILING = 1 << 3 0129 , F_UPGRADE = 1 << 4 0130 , F_SKIPBODY = 1 << 5 0131 }; 0132 0133 0134 /* Map for errno-related constants 0135 * 0136 * The provided argument should be a macro that takes 2 arguments. 0137 */ 0138 #define HTTP_ERRNO_MAP(XX) \ 0139 /* No error */ \ 0140 XX(OK, "success") \ 0141 \ 0142 /* Callback-related errors */ \ 0143 XX(CB_message_begin, "the on_message_begin callback failed") \ 0144 XX(CB_url, "the on_url callback failed") \ 0145 XX(CB_header_field, "the on_header_field callback failed") \ 0146 XX(CB_header_value, "the on_header_value callback failed") \ 0147 XX(CB_headers_complete, "the on_headers_complete callback failed") \ 0148 XX(CB_body, "the on_body callback failed") \ 0149 XX(CB_message_complete, "the on_message_complete callback failed") \ 0150 \ 0151 /* Parsing-related errors */ \ 0152 XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \ 0153 XX(HEADER_OVERFLOW, \ 0154 "too many header bytes seen; overflow detected") \ 0155 XX(CLOSED_CONNECTION, \ 0156 "data received after completed connection: close message") \ 0157 XX(INVALID_VERSION, "invalid HTTP version") \ 0158 XX(INVALID_STATUS, "invalid HTTP status code") \ 0159 XX(INVALID_METHOD, "invalid HTTP method") \ 0160 XX(INVALID_URL, "invalid URL") \ 0161 XX(INVALID_HOST, "invalid host") \ 0162 XX(INVALID_PORT, "invalid port") \ 0163 XX(INVALID_PATH, "invalid path") \ 0164 XX(INVALID_QUERY_STRING, "invalid query string") \ 0165 XX(INVALID_FRAGMENT, "invalid fragment") \ 0166 XX(LF_EXPECTED, "LF character expected") \ 0167 XX(INVALID_HEADER_TOKEN, "invalid character in header") \ 0168 XX(INVALID_CONTENT_LENGTH, \ 0169 "invalid character in content-length header") \ 0170 XX(INVALID_CHUNK_SIZE, \ 0171 "invalid character in chunk size header") \ 0172 XX(INVALID_CONSTANT, "invalid constant string") \ 0173 XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\ 0174 XX(STRICT, "strict mode assertion failed") \ 0175 XX(PAUSED, "parser is paused") \ 0176 XX(UNKNOWN, "an unknown error occurred") 0177 0178 0179 /* Define HPE_* values for each errno value above */ 0180 #define HTTP_ERRNO_GEN(n, s) HPE_##n, 0181 enum http_errno { 0182 HTTP_ERRNO_MAP(HTTP_ERRNO_GEN) 0183 }; 0184 #undef HTTP_ERRNO_GEN 0185 0186 0187 /* Get an http_errno value from an http_parser */ 0188 #define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno) 0189 0190 0191 struct http_parser { 0192 /** PRIVATE **/ 0193 unsigned char type : 2; /* enum http_parser_type */ 0194 unsigned char flags : 6; /* F_* values from 'flags' enum; semi-public */ 0195 unsigned char state; /* enum state from http_parser.c */ 0196 unsigned char header_state; /* enum header_state from http_parser.c */ 0197 unsigned char index; /* index into current matcher */ 0198 0199 uint32_t nread; /* # bytes read in various scenarios */ 0200 uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */ 0201 0202 /** READ-ONLY **/ 0203 unsigned short http_major; 0204 unsigned short http_minor; 0205 unsigned short status_code; /* responses only */ 0206 unsigned char method; /* requests only */ 0207 unsigned char http_errno : 7; 0208 0209 /* 1 = Upgrade header was present and the parser has exited because of that. 0210 * 0 = No upgrade header present. 0211 * Should be checked when http_parser_execute() returns in addition to 0212 * error checking. 0213 */ 0214 unsigned char upgrade : 1; 0215 0216 /** PUBLIC **/ 0217 void *data; /* A pointer to get hook to the "connection" or "socket" object */ 0218 }; 0219 0220 0221 struct http_parser_settings { 0222 http_cb on_message_begin; 0223 http_data_cb on_url; 0224 http_data_cb on_header_field; 0225 http_data_cb on_header_value; 0226 http_cb on_headers_complete; 0227 http_data_cb on_body; 0228 http_cb on_message_complete; 0229 }; 0230 0231 0232 enum http_parser_url_fields 0233 { UF_SCHEMA = 0 0234 , UF_HOST = 1 0235 , UF_PORT = 2 0236 , UF_PATH = 3 0237 , UF_QUERY = 4 0238 , UF_FRAGMENT = 5 0239 , UF_USERINFO = 6 0240 , UF_MAX = 7 0241 }; 0242 0243 0244 /* Result structure for http_parser_parse_url(). 0245 * 0246 * Callers should index into field_data[] with UF_* values iff field_set 0247 * has the relevant (1 << UF_*) bit set. As a courtesy to clients (and 0248 * because we probably have padding left over), we convert any port to 0249 * a uint16_t. 0250 */ 0251 struct http_parser_url { 0252 uint16_t field_set; /* Bitmask of (1 << UF_*) values */ 0253 uint16_t port; /* Converted UF_PORT string */ 0254 0255 struct { 0256 uint16_t off; /* Offset into buffer in which field starts */ 0257 uint16_t len; /* Length of run in buffer */ 0258 } field_data[UF_MAX]; 0259 }; 0260 0261 0262 void http_parser_init(http_parser *parser, enum http_parser_type type); 0263 0264 0265 size_t http_parser_execute(http_parser *parser, 0266 const http_parser_settings *settings, 0267 const char *data, 0268 size_t len); 0269 0270 0271 /* If http_should_keep_alive() in the on_headers_complete or 0272 * on_message_complete callback returns 0, then this should be 0273 * the last message on the connection. 0274 * If you are the server, respond with the "Connection: close" header. 0275 * If you are the client, close the connection. 0276 */ 0277 int http_should_keep_alive(const http_parser *parser); 0278 0279 /* Returns a string version of the HTTP method. */ 0280 const char *http_method_str(enum http_method m); 0281 0282 /* Return a string name of the given error */ 0283 const char *http_errno_name(enum http_errno err); 0284 0285 /* Return a string description of the given error */ 0286 const char *http_errno_description(enum http_errno err); 0287 0288 /* Parse a URL; return nonzero on failure */ 0289 int http_parser_parse_url(const char *buf, size_t buflen, 0290 int is_connect, 0291 struct http_parser_url *u); 0292 0293 /* Pause or un-pause the parser; a nonzero value pauses */ 0294 void http_parser_pause(http_parser *parser, int paused); 0295 0296 /* Checks if this is the final chunk of the body. */ 0297 int http_body_is_final(const http_parser *parser); 0298 0299 #ifdef __cplusplus 0300 } 0301 #endif 0302 #endif