1
- /* Copyright 2009,2010 Ryan Dahl <ry@tinyclouds.org>
1
+ /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2
2
*
3
3
* Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
* of this software and associated documentation files (the "Software"), to
24
24
extern "C" {
25
25
#endif
26
26
27
+ #define HTTP_PARSER_VERSION_MAJOR 2
28
+ #define HTTP_PARSER_VERSION_MINOR 0
27
29
28
30
#include <sys/types.h>
29
- #if defined(_WIN32 ) && !defined(__MINGW32__ )
31
+ #if defined(_WIN32 ) && !defined(__MINGW32__ ) && (!defined(_MSC_VER ) || _MSC_VER < 1600 )
32
+ #include <BaseTsd.h>
33
+ #include <stddef.h>
30
34
typedef __int8 int8_t ;
31
35
typedef unsigned __int8 uint8_t ;
32
36
typedef __int16 int16_t ;
@@ -35,9 +39,6 @@ typedef __int32 int32_t;
35
39
typedef unsigned __int32 uint32_t ;
36
40
typedef __int64 int64_t ;
37
41
typedef unsigned __int64 uint64_t ;
38
-
39
- typedef unsigned int size_t ;
40
- typedef int ssize_t ;
41
42
#else
42
43
#include <stdint.h>
43
44
#endif
@@ -47,11 +48,8 @@ typedef int ssize_t;
47
48
*/
48
49
#ifndef HTTP_PARSER_STRICT
49
50
# define HTTP_PARSER_STRICT 1
50
- #else
51
- # define HTTP_PARSER_STRICT 0
52
51
#endif
53
52
54
-
55
53
/* Maximium header size allowed */
56
54
#define HTTP_MAX_HEADER_SIZE (80*1024)
57
55
@@ -70,71 +68,150 @@ typedef struct http_parser_settings http_parser_settings;
70
68
* chunked' headers that indicate the presence of a body.
71
69
*
72
70
* 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_path "
71
+ * many times for each string. E.G. you might get 10 callbacks for "on_url "
74
72
* each providing just a few characters more data.
75
73
*/
76
74
typedef int (* http_data_cb ) (http_parser * , const char * at , size_t length );
77
75
typedef int (* http_cb ) (http_parser * );
78
76
79
77
80
78
/* Request Methods */
79
+ #define HTTP_METHOD_MAP (XX ) \
80
+ XX(0, DELETE, DELETE) \
81
+ XX(1, GET, GET) \
82
+ XX(2, HEAD, HEAD) \
83
+ XX(3, POST, POST) \
84
+ XX(4, PUT, PUT) \
85
+ /* pathological */ \
86
+ XX (5 , CONNECT , CONNECT ) \
87
+ XX (6 , OPTIONS , OPTIONS ) \
88
+ XX (7 , TRACE , TRACE ) \
89
+ /* webdav */ \
90
+ XX (8 , COPY , COPY ) \
91
+ XX (9 , LOCK , LOCK ) \
92
+ XX (10 , MKCOL , MKCOL ) \
93
+ XX (11 , MOVE , MOVE ) \
94
+ XX (12 , PROPFIND , PROPFIND ) \
95
+ XX (13 , PROPPATCH , PROPPATCH ) \
96
+ XX (14 , SEARCH , SEARCH ) \
97
+ XX (15 , UNLOCK , UNLOCK ) \
98
+ /* subversion */ \
99
+ XX (16 , REPORT , REPORT ) \
100
+ XX (17 , MKACTIVITY , MKACTIVITY ) \
101
+ XX (18 , CHECKOUT , CHECKOUT ) \
102
+ XX (19 , MERGE , MERGE ) \
103
+ /* upnp */ \
104
+ XX (20 , MSEARCH , M - SEARCH ) \
105
+ XX (21 , NOTIFY , NOTIFY ) \
106
+ XX (22 , SUBSCRIBE , SUBSCRIBE ) \
107
+ XX (23 , UNSUBSCRIBE , UNSUBSCRIBE ) \
108
+ /* RFC-5789 */ \
109
+ XX (24 , PATCH , PATCH ) \
110
+ XX (25 , PURGE , PURGE ) \
111
+
81
112
enum http_method
82
- { HTTP_DELETE = 0
83
- , HTTP_GET
84
- , HTTP_HEAD
85
- , HTTP_POST
86
- , HTTP_PUT
87
- /* pathological */
88
- , HTTP_CONNECT
89
- , HTTP_OPTIONS
90
- , HTTP_TRACE
91
- /* webdav */
92
- , HTTP_COPY
93
- , HTTP_LOCK
94
- , HTTP_MKCOL
95
- , HTTP_MOVE
96
- , HTTP_PROPFIND
97
- , HTTP_PROPPATCH
98
- , HTTP_UNLOCK
99
- /* subversion */
100
- , HTTP_REPORT
101
- , HTTP_MKACTIVITY
102
- , HTTP_CHECKOUT
103
- , HTTP_MERGE
104
- /* upnp */
105
- , HTTP_MSEARCH
106
- , HTTP_NOTIFY
107
- , HTTP_SUBSCRIBE
108
- , HTTP_UNSUBSCRIBE
113
+ {
114
+ #define XX(num, name, string) HTTP_##name = num,
115
+ HTTP_METHOD_MAP (XX )
116
+ #undef XX
109
117
};
110
118
111
119
112
120
enum http_parser_type { HTTP_REQUEST , HTTP_RESPONSE , HTTP_BOTH };
113
121
114
122
123
+ /* Flag values for http_parser.flags field */
124
+ enum flags
125
+ { F_CHUNKED = 1 << 0
126
+ , F_CONNECTION_KEEP_ALIVE = 1 << 1
127
+ , F_CONNECTION_CLOSE = 1 << 2
128
+ , F_TRAILING = 1 << 3
129
+ , F_UPGRADE = 1 << 4
130
+ , F_SKIPBODY = 1 << 5
131
+ };
132
+
133
+
134
+ /* Map for errno-related constants
135
+ *
136
+ * The provided argument should be a macro that takes 2 arguments.
137
+ */
138
+ #define HTTP_ERRNO_MAP (XX ) \
139
+ /* No error */ \
140
+ XX(OK, "success") \
141
+ \
142
+ /* Callback-related errors */ \
143
+ XX (CB_message_begin , "the on_message_begin callback failed" ) \
144
+ XX (CB_url , "the on_url callback failed" ) \
145
+ XX (CB_header_field , "the on_header_field callback failed" ) \
146
+ XX (CB_header_value , "the on_header_value callback failed" ) \
147
+ XX (CB_headers_complete , "the on_headers_complete callback failed" ) \
148
+ XX (CB_body , "the on_body callback failed" ) \
149
+ XX (CB_message_complete , "the on_message_complete callback failed" ) \
150
+ \
151
+ /* Parsing-related errors */ \
152
+ XX (INVALID_EOF_STATE , "stream ended at an unexpected time" ) \
153
+ XX (HEADER_OVERFLOW , \
154
+ "too many header bytes seen; overflow detected" ) \
155
+ XX (CLOSED_CONNECTION , \
156
+ "data received after completed connection: close message" ) \
157
+ XX (INVALID_VERSION , "invalid HTTP version" ) \
158
+ XX (INVALID_STATUS , "invalid HTTP status code" ) \
159
+ XX (INVALID_METHOD , "invalid HTTP method" ) \
160
+ XX (INVALID_URL , "invalid URL" ) \
161
+ XX (INVALID_HOST , "invalid host" ) \
162
+ XX (INVALID_PORT , "invalid port" ) \
163
+ XX (INVALID_PATH , "invalid path" ) \
164
+ XX (INVALID_QUERY_STRING , "invalid query string" ) \
165
+ XX (INVALID_FRAGMENT , "invalid fragment" ) \
166
+ XX (LF_EXPECTED , "LF character expected" ) \
167
+ XX (INVALID_HEADER_TOKEN , "invalid character in header" ) \
168
+ XX (INVALID_CONTENT_LENGTH , \
169
+ "invalid character in content-length header" ) \
170
+ XX (INVALID_CHUNK_SIZE , \
171
+ "invalid character in chunk size header" ) \
172
+ XX (INVALID_CONSTANT , "invalid constant string" ) \
173
+ XX (INVALID_INTERNAL_STATE , "encountered unexpected internal state" )\
174
+ XX (STRICT , "strict mode assertion failed" ) \
175
+ XX (PAUSED , "parser is paused" ) \
176
+ XX (UNKNOWN , "an unknown error occurred" )
177
+
178
+
179
+ /* Define HPE_* values for each errno value above */
180
+ #define HTTP_ERRNO_GEN (n , s ) HPE_##n,
181
+ enum http_errno {
182
+ HTTP_ERRNO_MAP (HTTP_ERRNO_GEN )
183
+ };
184
+ #undef HTTP_ERRNO_GEN
185
+
186
+
187
+ /* Get an http_errno value from an http_parser */
188
+ #define HTTP_PARSER_ERRNO (p ) ((enum http_errno) (p)->http_errno)
189
+
190
+
115
191
struct http_parser {
116
192
/** PRIVATE **/
117
- unsigned char type : 2 ;
118
- unsigned char flags : 6 ;
119
- unsigned char state ;
120
- unsigned char header_state ;
121
- unsigned char index ;
193
+ unsigned char type : 2 ; /* enum http_parser_type */
194
+ unsigned char flags : 6 ; /* F_* values from 'flags' enum; semi-public */
195
+ unsigned char state ; /* enum state from http_parser.c */
196
+ unsigned char header_state ; /* enum header_state from http_parser.c */
197
+ unsigned char index ; /* index into current matcher */
122
198
123
- uint32_t nread ;
124
- int64_t content_length ;
199
+ uint32_t nread ; /* # bytes read in various scenarios */
200
+ uint64_t content_length ; /* # bytes in body (0 if no Content-Length header) */
125
201
126
202
/** READ-ONLY **/
127
203
unsigned short http_major ;
128
204
unsigned short http_minor ;
129
205
unsigned short status_code ; /* responses only */
130
- unsigned char method ; /* requests only */
206
+ unsigned char method ; /* requests only */
207
+ unsigned char http_errno : 7 ;
131
208
132
209
/* 1 = Upgrade header was present and the parser has exited because of that.
133
210
* 0 = No upgrade header present.
134
211
* Should be checked when http_parser_execute() returns in addition to
135
212
* error checking.
136
213
*/
137
- char upgrade ;
214
+ unsigned char upgrade : 1 ;
138
215
139
216
/** PUBLIC **/
140
217
void * data ; /* A pointer to get hook to the "connection" or "socket" object */
@@ -143,10 +220,7 @@ struct http_parser {
143
220
144
221
struct http_parser_settings {
145
222
http_cb on_message_begin ;
146
- http_data_cb on_path ;
147
- http_data_cb on_query_string ;
148
223
http_data_cb on_url ;
149
- http_data_cb on_fragment ;
150
224
http_data_cb on_header_field ;
151
225
http_data_cb on_header_value ;
152
226
http_cb on_headers_complete ;
@@ -155,6 +229,36 @@ struct http_parser_settings {
155
229
};
156
230
157
231
232
+ enum http_parser_url_fields
233
+ { UF_SCHEMA = 0
234
+ , UF_HOST = 1
235
+ , UF_PORT = 2
236
+ , UF_PATH = 3
237
+ , UF_QUERY = 4
238
+ , UF_FRAGMENT = 5
239
+ , UF_USERINFO = 6
240
+ , UF_MAX = 7
241
+ };
242
+
243
+
244
+ /* Result structure for http_parser_parse_url().
245
+ *
246
+ * Callers should index into field_data[] with UF_* values iff field_set
247
+ * has the relevant (1 << UF_*) bit set. As a courtesy to clients (and
248
+ * because we probably have padding left over), we convert any port to
249
+ * a uint16_t.
250
+ */
251
+ struct http_parser_url {
252
+ uint16_t field_set ; /* Bitmask of (1 << UF_*) values */
253
+ uint16_t port ; /* Converted UF_PORT string */
254
+
255
+ struct {
256
+ uint16_t off ; /* Offset into buffer in which field starts */
257
+ uint16_t len ; /* Length of run in buffer */
258
+ } field_data [UF_MAX ];
259
+ };
260
+
261
+
158
262
void http_parser_init (http_parser * parser , enum http_parser_type type );
159
263
160
264
@@ -165,15 +269,32 @@ size_t http_parser_execute(http_parser *parser,
165
269
166
270
167
271
/* If http_should_keep_alive() in the on_headers_complete or
168
- * on_message_complete callback returns true , then this will be should be
272
+ * on_message_complete callback returns 0 , then this should be
169
273
* the last message on the connection.
170
274
* If you are the server, respond with the "Connection: close" header.
171
275
* If you are the client, close the connection.
172
276
*/
173
- int http_should_keep_alive (http_parser * parser );
277
+ int http_should_keep_alive (const http_parser * parser );
174
278
175
279
/* Returns a string version of the HTTP method. */
176
- const char * http_method_str (enum http_method );
280
+ const char * http_method_str (enum http_method m );
281
+
282
+ /* Return a string name of the given error */
283
+ const char * http_errno_name (enum http_errno err );
284
+
285
+ /* Return a string description of the given error */
286
+ const char * http_errno_description (enum http_errno err );
287
+
288
+ /* Parse a URL; return nonzero on failure */
289
+ int http_parser_parse_url (const char * buf , size_t buflen ,
290
+ int is_connect ,
291
+ struct http_parser_url * u );
292
+
293
+ /* Pause or un-pause the parser; a nonzero value pauses */
294
+ void http_parser_pause (http_parser * parser , int paused );
295
+
296
+ /* Checks if this is the final chunk of the body. */
297
+ int http_body_is_final (const http_parser * parser );
177
298
178
299
#ifdef __cplusplus
179
300
}
0 commit comments