ry / ebb fork watch download tarball
public
Description: web server
Homepage: http://ebb.rubyforge.org
Clone URL: git://github.com/ry/ebb.git
Search Repo:
Major update to parser.rl

I'm changing Zed's original design of having a callback for each element 
in
the parser. Rather there will be two callbacks for headers: one for 
unknown
headers and one for known headers - there is an enum which defines the 
known
headers.

The idea here is to easily add preallocated global variables for often 
seen
header values in the ruby binding. This has only been done so far with
Content-Type, but I will add many more soon.

This change simplifies ebb.c greatly.
Ryan Dahl (author)
Sat Mar 22 08:24:33 -0700 2008
commit  9d81073a9238c892c39ca51b05ebb22a05fe0675
tree    a65fa5de142a0eb81ce210a060e570ad61536d93
parent  eb87a28b1e30f2303bc5c11684ba50ec87f01427
...
37
38
39
40
 
41
42
43
44
45
...
70
71
72
73
 
74
75
76
 
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
...
133
134
135
136
 
137
138
139
...
157
158
159
160
 
161
162
163
...
167
168
169
170
 
171
172
173
174
...
197
198
199
200
 
201
202
203
 
204
205
206
207
...
362
363
364
365
366
367
368
369
370
371
 
372
373
374
375
376
377
378
379
380
...
680
681
682
683
 
684
685
686
...
37
38
39
 
40
41
42
43
44
45
...
70
71
72
 
73
74
75
 
76
77
78
79
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
81
82
...
86
87
88
 
89
90
91
92
...
110
111
112
 
113
114
115
116
...
120
121
122
 
123
124
125
126
127
...
150
151
152
 
153
154
155
 
156
157
158
159
160
...
315
316
317
 
 
 
 
 
 
 
318
319
320
321
322
323
 
324
325
326
...
626
627
628
 
629
630
631
632
0
@@ -37,7 +37,7 @@
0
     client->parser.overflow_error = TRUE;
0
     return;
0
   }
0
- client->env[client->env_size].type = EBB_FIELD_VALUE_PAIR;
0
+ client->env[client->env_size].type = -1;
0
   client->env[client->env_size].field = field;
0
   client->env[client->env_size].field_length = flen;
0
   client->env[client->env_size].value = value;
0
0
0
@@ -70,60 +70,13 @@
0
 }
0
 
0
 
0
-void request_method_cb(void *data, const char *at, size_t length)
0
+void on_element(void *data, int type, const char *at, size_t length)
0
 {
0
   ebb_client *client = (ebb_client*)(data);
0
- env_add_const(client, EBB_REQUEST_METHOD, at, length);
0
+ env_add_const(client, type, at, length);
0
 }
0
 
0
 
0
-void request_uri_cb(void *data, const char *at, size_t length)
0
-{
0
- ebb_client *client = (ebb_client*)(data);
0
- env_add_const(client, EBB_REQUEST_URI, at, length);
0
-}
0
-
0
-
0
-void fragment_cb(void *data, const char *at, size_t length)
0
-{
0
- ebb_client *client = (ebb_client*)(data);
0
- env_add_const(client, EBB_FRAGMENT, at, length);
0
-}
0
-
0
-
0
-void request_path_cb(void *data, const char *at, size_t length)
0
-{
0
- ebb_client *client = (ebb_client*)(data);
0
- env_add_const(client, EBB_REQUEST_PATH, at, length);
0
-}
0
-
0
-
0
-void query_string_cb(void *data, const char *at, size_t length)
0
-{
0
- ebb_client *client = (ebb_client*)(data);
0
- env_add_const(client, EBB_QUERY_STRING, at, length);
0
-}
0
-
0
-
0
-void http_version_cb(void *data, const char *at, size_t length)
0
-{
0
- ebb_client *client = (ebb_client*)(data);
0
- env_add_const(client, EBB_HTTP_VERSION, at, length);
0
-}
0
-
0
-
0
-void content_length_cb(void *data, const char *at, size_t length)
0
-{
0
- ebb_client *client = (ebb_client*)(data);
0
- env_add_const(client, EBB_CONTENT_LENGTH, at, length);
0
- /* atoi_length - why isn't this in the statndard library? i hate c */
0
- assert(client->content_length == 0);
0
- int i, mult;
0
- for(mult=1, i=length-1; i>=0; i--, mult*=10)
0
- client->content_length += (at[i] - '0') * mult;
0
-}
0
-
0
-
0
 static void dispatch(ebb_client *client)
0
 {
0
   ebb_server *server = client->server;
0
@@ -133,7 +86,7 @@
0
   
0
   /* Set the env variables */
0
   if(server->port) {
0
- env_add_const(client, EBB_SERVER_PORT
0
+ env_add_const(client, MONGREL_SERVER_PORT
0
                         , server->port
0
                         , strlen(server->port)
0
                         );
0
@@ -157,7 +110,7 @@
0
 }
0
 
0
 #define client_finished_parsing http_parser_is_finished(&client->parser)
0
-#define total_request_size (client->content_length + client->parser.nread)
0
+#define total_request_size (client->parser.content_length + client->parser.nread)
0
 
0
 static void* read_body_into_file(void *_client)
0
 {
0
@@ -167,7 +120,7 @@
0
   
0
   assert(client->open);
0
   assert(client->server->open);
0
- assert(client->content_length > 0);
0
+ assert(client->parser.content_length > 0);
0
   assert(client_finished_parsing);
0
   
0
   /* set blocking socket */
0
0
@@ -197,10 +150,10 @@
0
   int bufsize = 5*1024;
0
   char buffer[bufsize];
0
   size_t received;
0
- while(written < client->content_length) {
0
+ while(written < client->parser.content_length) {
0
     received = recv(client->fd
0
                    , buffer
0
- , min(client->content_length - written, bufsize)
0
+ , min(client->parser.content_length - written, bufsize)
0
                    , 0
0
                    );
0
     if(received < 0) goto error;
0
0
@@ -362,19 +315,12 @@
0
   http_parser_init(&(client->parser));
0
   client->parser.data = client;
0
   client->parser.http_field = http_field_cb;
0
- client->parser.request_method = request_method_cb;
0
- client->parser.request_uri = request_uri_cb;
0
- client->parser.fragment = fragment_cb;
0
- client->parser.request_path = request_path_cb;
0
- client->parser.query_string = query_string_cb;
0
- client->parser.http_version = http_version_cb;
0
- client->parser.content_length = content_length_cb;
0
+ client->parser.on_element = on_element;
0
   
0
   /* OTHER */
0
   client->env_size = 0;
0
   client->read = client->nread_from_body = 0;
0
   client->response_buffer->len = 0; /* see note in ebb_client_close */
0
- client->content_length = 0;
0
   if(client->request_buffer == NULL) {
0
     client->request_buffer = (char*)malloc(EBB_BUFFERSIZE);
0
   }
0
@@ -680,7 +626,7 @@
0
   } else {
0
     char* request_body = client->request_buffer + client->parser.nread;
0
     
0
- read = ramp(min(length, client->content_length - client->nread_from_body));
0
+ read = ramp(min(length, client->parser.content_length - client->nread_from_body));
0
     memcpy( buffer
0
           , request_body + client->nread_from_body
0
           , read
...
35
36
37
38
39
40
41
42
43
44
45
46
47
 
48
49
50
...
65
66
67
68
69
70
71
72
...
35
36
37
 
 
 
 
 
 
 
 
 
 
38
39
40
41
...
56
57
58
 
 
59
60
61
0
@@ -35,16 +35,7 @@
0
 void ebb_client_begin_transmission( ebb_client *client);
0
 
0
 struct ebb_env_item {
0
- enum { EBB_FIELD_VALUE_PAIR
0
- , EBB_REQUEST_METHOD
0
- , EBB_REQUEST_URI
0
- , EBB_FRAGMENT
0
- , EBB_REQUEST_PATH
0
- , EBB_QUERY_STRING
0
- , EBB_HTTP_VERSION
0
- , EBB_SERVER_PORT
0
- , EBB_CONTENT_LENGTH
0
- } type;
0
+ int type;
0
  const char *field;
0
  int field_length;
0
  const char *value;
0
@@ -65,8 +56,6 @@
0
   
0
   char upload_file_filename[200];
0
   FILE *upload_file;
0
-
0
- int content_length;
0
   
0
   ev_io write_watcher;
0
   GString *response_buffer;
...
22
23
24
 
25
26
27
28
29
...
118
119
120
121
 
 
 
 
 
 
 
 
 
 
 
 
 
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
 
 
 
 
 
 
 
 
 
143
 
144
145
146
...
250
251
252
253
 
 
254
255
256
...
22
23
24
25
26
27
28
29
30
...
119
120
121
 
122
123
124
125
126
127
128
129
130
131
132
133
134
135
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
137
138
139
140
141
142
143
144
145
146
147
148
149
...
253
254
255
 
256
257
258
259
260
0
@@ -22,6 +22,7 @@
0
 static VALUE global_server_port;
0
 static VALUE global_path_info;
0
 static VALUE global_content_length;
0
+static VALUE global_content_type;
0
 static VALUE global_http_host;
0
 
0
 /* You don't want to run more than one server per Ruby VM. Really
0
0
0
@@ -118,29 +119,31 @@
0
 
0
 VALUE env_field(struct ebb_env_item *item)
0
 {
0
- VALUE f;
0
+ if(item->field) {
0
+ VALUE f = rb_str_new(NULL, RSTRING_LEN(global_http_prefix) + item->field_length);
0
+ memcpy( RSTRING_PTR(f)
0
+ , RSTRING_PTR(global_http_prefix)
0
+ , RSTRING_LEN(global_http_prefix)
0
+ );
0
+ int i;
0
+ for(i = 0; i < item->field_length; i++) {
0
+ char *ch = RSTRING_PTR(f) + RSTRING_LEN(global_http_prefix) + i;
0
+ *ch = item->field[i] == '-' ? '_' : ASCII_UPPER(item->field[i]);
0
+ }
0
+ return f;
0
+ }
0
   switch(item->type) {
0
- case EBB_FIELD_VALUE_PAIR:
0
- f = rb_str_new(NULL, RSTRING_LEN(global_http_prefix) + item->field_length);
0
- memcpy( RSTRING_PTR(f)
0
- , RSTRING_PTR(global_http_prefix)
0
- , RSTRING_LEN(global_http_prefix)
0
- );
0
- int i;
0
- for(i = 0; i < item->field_length; i++) {
0
- char *ch = RSTRING_PTR(f) + RSTRING_LEN(global_http_prefix) + i;
0
- *ch = item->field[i] == '-' ? '_' : ASCII_UPPER(item->field[i]);
0
- }
0
- return f;
0
- case EBB_REQUEST_METHOD: return global_request_method;
0
- case EBB_REQUEST_URI: return global_request_uri;
0
- case EBB_FRAGMENT: return global_fragment;
0
- case EBB_REQUEST_PATH: return global_request_path;
0
- case EBB_QUERY_STRING: return global_query_string;
0
- case EBB_HTTP_VERSION: return global_http_version;
0
- case EBB_SERVER_PORT: return global_server_port;
0
- case EBB_CONTENT_LENGTH: return global_content_length;
0
+ case MONGREL_REQUEST_METHOD: return global_request_method;
0
+ case MONGREL_REQUEST_URI: return global_request_uri;
0
+ case MONGREL_FRAGMENT: return global_fragment;
0
+ case MONGREL_REQUEST_PATH: return global_request_path;
0
+ case MONGREL_QUERY_STRING: return global_query_string;
0
+ case MONGREL_HTTP_VERSION: return global_http_version;
0
+ case MONGREL_SERVER_PORT: return global_server_port;
0
+ case MONGREL_CONTENT_LENGTH: return global_content_length;
0
+ case MONGREL_CONTENT_TYPE: return global_content_type;
0
   }
0
+ fprintf(stderr, "Unknown environ type: %d", item->type);
0
   assert(FALSE);
0
   return Qnil;
0
 }
0
@@ -250,7 +253,8 @@
0
   DEF_GLOBAL(request_body, "REQUEST_BODY");
0
   DEF_GLOBAL(server_port, "SERVER_PORT");
0
   DEF_GLOBAL(path_info, "PATH_INFO");
0
- DEF_GLOBAL(content_length, "CONTENT_LENGTH");
0
+ DEF_GLOBAL(content_length, "HTTP_CONTENT_LENGTH");
0
+ DEF_GLOBAL(content_type, "HTTP_CONTENT_TYPE");
0
   DEF_GLOBAL(http_host, "HTTP_HOST");
0
   
0
   rb_define_singleton_method(mFFI, "server_process_connections", server_process_connections, 0);
...
12
13
14
 
 
 
 
 
 
 
 
 
 
 
 
 
15
16
 
17
 
 
18
19
20
21
22
 
23
24
25
26
...
29
30
31
32
33
34
35
36
37
 
38
39
 
40
41
42
...
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
 
38
39
40
41
42
...
45
46
47
 
 
 
 
 
 
48
49
 
50
51
52
53
0
@@ -12,14 +12,30 @@
0
 #include <stddef.h>
0
 #endif
0
 
0
+
0
+enum { MONGREL_REQUEST_METHOD
0
+ , MONGREL_REQUEST_URI
0
+ , MONGREL_FRAGMENT
0
+ , MONGREL_REQUEST_PATH
0
+ , MONGREL_QUERY_STRING
0
+ , MONGREL_HTTP_VERSION
0
+ , MONGREL_CONTENT_LENGTH
0
+ , MONGREL_CONTENT_TYPE
0
+ /* below - not used in the parser but often used by users of parser */
0
+ , MONGREL_SERVER_PORT
0
+ };
0
+
0
 typedef void (*element_cb)(void *data, const char *at, size_t length);
0
 typedef void (*field_cb)(void *data, const char *field, size_t flen, const char *value, size_t vlen);
0
+typedef void (*new_element_cb)(void *data, int type, const char *at, size_t length);
0
 
0
+
0
+
0
 typedef struct http_parser {
0
   int cs;
0
   int overflow_error;
0
   size_t body_start;
0
- int content_len;
0
+ size_t content_length;
0
   size_t nread;
0
   size_t mark;
0
   size_t field_start;
0
0
@@ -29,14 +45,9 @@
0
   void *data;
0
 
0
   field_cb http_field;
0
- element_cb request_method;
0
- element_cb request_uri;
0
- element_cb fragment;
0
- element_cb request_path;
0
- element_cb query_string;
0
- element_cb http_version;
0
+
0
   element_cb header_done;
0
- element_cb content_length;
0
+ new_element_cb on_element;
0
 } http_parser;
0
 
0
 void http_parser_init(http_parser *parser);
...
18
19
20
21
 
22
23
 
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
...
29
30
31
32
 
33
34
35
36
37
38
 
39
40
41
42
43
44
45
46
47
 
 
 
48
49
50
51
52
 
 
 
53
54
55
56
57
58
59
60
61
 
 
 
 
62
63
64
65
66
 
 
 
 
 
 
67
68
69
70
71
 
72
73
74
75
76
 
 
77
78
79
80
 
 
81
82
83
84
85
 
86
87
88
89
90
 
 
 
91
92
93
94
95
 
96
97
 
98
99
100
101
...
148
149
150
 
 
 
 
 
 
 
151
152
153
154
155
156
157
158
159
160
161
...
161
162
163
 
 
 
 
 
 
 
 
 
164
165
166
167
168
169
170
 
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
...
18
19
20
 
21
22
 
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
...
29
30
31
 
32
33
34
 
 
 
 
35
36
37
38
39
40
41
 
 
 
42
43
44
45
46
 
 
 
47
48
49
50
51
 
 
 
 
 
 
 
52
53
54
55
56
57
 
 
 
58
59
60
61
62
63
64
65
66
 
 
67
68
69
 
 
 
70
71
72
73
 
 
74
75
76
77
78
 
 
79
80
81
 
 
 
82
83
84
85
86
87
 
 
88
89
90
91
92
93
94
95
...
142
143
144
145
146
147
148
149
150
151
152
 
 
 
 
 
153
154
155
156
157
...
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
 
175
176
177
178
179
180
181
 
 
 
 
 
 
 
182
183
184
0
@@ -18,9 +18,9 @@
0
 /** machine **/
0
 %%{
0
   machine http_parser;
0
-
0
+
0
   action mark {MARK(mark, fpc); }
0
-
0
+
0
   action start_field { MARK(field_start, fpc); }
0
   action write_field {
0
     parser->field_len = LEN(field_start, fpc);
0
0
0
0
0
0
0
0
0
0
0
0
0
@@ -29,72 +29,66 @@
0
       fbreak;
0
     }
0
   }
0
-
0
+
0
   action start_value { MARK(mark, fpc); }
0
   action write_value {
0
- if(LEN(mark, fpc) > 80 * 1024) {
0
- parser->overflow_error = TRUE;
0
- fbreak;
0
- }
0
+ if(LEN(mark, fpc) > 80 * 1024) { parser->overflow_error = TRUE; fbreak; }
0
     if(parser->http_field != NULL) {
0
       parser->http_field(parser->data, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, fpc));
0
     }
0
   }
0
   
0
   action content_length {
0
- if(parser->content_length != NULL) {
0
- parser->content_length(parser->data, PTR_TO(mark), LEN(mark, fpc));
0
- }
0
+ if(LEN(mark, fpc) > 20) { parser->overflow_error = TRUE; fbreak; }
0
+ set_content_length(parser, PTR_TO(mark), LEN(mark, fpc));
0
+ parser->on_element(parser->data, MONGREL_CONTENT_LENGTH, PTR_TO(mark), LEN(mark, fpc));
0
   }
0
   
0
- action request_method {
0
- if(parser->request_method != NULL)
0
- parser->request_method(parser->data, PTR_TO(mark), LEN(mark, fpc));
0
+ action content_type {
0
+ if(LEN(mark, fpc) > 1024) { parser->overflow_error = TRUE; fbreak; }
0
+ parser->on_element(parser->data, MONGREL_CONTENT_TYPE, PTR_TO(mark), LEN(mark, fpc));
0
   }
0
   
0
- action request_uri {
0
- if(LEN(mark, fpc) > 12 * 1024) {
0
- parser->overflow_error = TRUE;
0
- fbreak;
0
- }
0
- if(parser->request_uri != NULL)
0
- parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, fpc));
0
+ action fragment {
0
+ /* Don't know if this length is specified somewhere or not */
0
+ if(LEN(mark, fpc) > 1024) { parser->overflow_error = TRUE; fbreak; }
0
+ parser->on_element(parser->data, MONGREL_FRAGMENT, PTR_TO(mark), LEN(mark, fpc));
0
   }
0
   
0
- action start_query {MARK(query_start, fpc); }
0
- action query_string {
0
- if(LEN(query_start, fpc) > 10 * 1024) {
0
+ action http_version {
0
+ parser->on_element(parser->data, MONGREL_HTTP_VERSION, PTR_TO(mark), LEN(mark, fpc));
0
+ }
0
+
0
+ action request_path {
0
+ if(LEN(mark, fpc) > 1024) {
0
       parser->overflow_error = TRUE;
0
       fbreak;
0
     }
0
- if(parser->query_string != NULL)
0
- parser->query_string(parser->data, PTR_TO(query_start), LEN(query_start, fpc));
0
+ parser->on_element(parser->data, MONGREL_REQUEST_PATH, PTR_TO(mark), LEN(mark,fpc));
0
   }
0
   
0
- action http_version {
0
- if(parser->http_version != NULL)
0
- parser->http_version(parser->data, PTR_TO(mark), LEN(mark, fpc));
0
+ action request_method {
0
+ parser->on_element(parser->data, MONGREL_REQUEST_METHOD, PTR_TO(mark), LEN(mark, fpc));
0
   }
0
   
0
- action request_path {
0
- if(LEN(mark, fpc) > 1024) {
0
+ action request_uri {
0
+ if(LEN(mark, fpc) > 12 * 1024) {
0
       parser->overflow_error = TRUE;
0
       fbreak;
0
     }
0
- if(parser->request_path != NULL)
0
- parser->request_path(parser->data, PTR_TO(mark), LEN(mark,fpc));
0
+ parser->on_element(parser->data, MONGREL_REQUEST_URI, PTR_TO(mark), LEN(mark, fpc));
0
   }
0
   
0
- action fragment {
0
- /* Don't know if this length is specified somewhere or not */
0
- if(LEN(mark, fpc) > 1024) {
0
+ action start_query {MARK(query_start, fpc); }
0
+ action query_string {
0
+ if(LEN(query_start, fpc) > 10 * 1024) {
0
       parser->overflow_error = TRUE;
0
       fbreak;
0
     }
0
- if(parser->fragment != NULL)
0
- parser->fragment(parser->data, PTR_TO(mark), LEN(mark, fpc));
0
+ parser->on_element(parser->data, MONGREL_QUERY_STRING, PTR_TO(query_start), LEN(query_start, fpc));
0
   }
0
   
0
+
0
   action done {
0
     if(parser->nread > 1024 * (80 + 32)) {
0
       parser->overflow_error = TRUE;
0
0
@@ -148,12 +142,14 @@
0
   field_name = ( token -- ":" )+ >start_field %write_field;
0
 
0
   field_value = any* >start_value %write_value;
0
+
0
+ known_header = ("Content-Length:"i " "* (digit+ >mark %content_length) :> CRLF)
0
+ | ("Content-Type:"i " "* (any* >mark %content_type) :> CRLF)
0
+ ;
0
+ unknown_header = (field_name ":" " "* field_value :> CRLF) -- known_header;
0
+
0
+ Request = Request_Line (known_header | unknown_header )* ( CRLF @done );
0
 
0
- message_header = field_name ":" " "* field_value :> CRLF;
0
- content_length = "Content-Length:"i " "* (digit+ >mark %content_length) :> CRLF;
0
-
0
- Request = Request_Line (content_length | message_header )* ( CRLF @done );
0
-
0
 main := Request;
0
 
0
 }%%
0
0
0
@@ -161,26 +157,28 @@
0
 /** Data **/
0
 %% write data;
0
 
0
+static void set_content_length(http_parser *parser, const char *at, int length)
0
+{
0
+ /* atoi_length - why isn't this in the statndard library? i hate c */
0
+ assert(parser->content_length == 0);
0
+ int i, mult;
0
+ for(mult=1, i=length-1; i>=0; i--, mult*=10)
0
+ parser->content_length += (at[i] - '0') * mult;
0
+}
0
+
0
 void http_parser_init(http_parser *parser) {
0
   int cs = 0;
0
   %% write init;
0
   parser->cs = cs;
0
   parser->overflow_error = FALSE;
0
   parser->body_start = 0;
0
- parser->content_len = 0;
0
+ parser->content_length = 0;
0
   parser->mark = 0;
0
   parser->nread = 0;
0
   parser->field_len = 0;
0
   parser->field_start = 0;
0
   parser->data = NULL;
0
   parser->http_field = NULL;
0
- parser->request_method = NULL;
0
- parser->request_uri = NULL;
0
- parser->fragment = NULL;
0
- parser->request_path = NULL;
0
- parser->query_string = NULL;
0
- parser->http_version = NULL;
0
- parser->content_length = NULL;
0
 }
0
 
0
 

Comments

    No one has commented yet.