bossan 0.3.0 → 0.4.0

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