ry / ebb fork watch download tarball
public this repo is viewable by everyone
Description: web server
Homepage: http://ebb.rubyforge.org
Clone URL: git://github.com/ry/ebb.git
Tests parser errors

Run test/echo_server.rb and then run test/env_test.rb to check that ebb 
drops connections on all sorts of bad input. Some additional checks and 
improvements in the parser were made.
Ryan Dahl (author)
2 months ago
commit  6b67ca61e0da5ad0b69ee5aff0a116ca5c6db8d2
tree    1dbbdd26a43050028ae31a75a51988ecbcacb2d8
parent  00b3ac3777772e2092ecbc495dc1368ef9bdae67
...
37
38
39
40
41
42
43
 
44
45
46
...
98
99
100
101
102
 
 
 
 
 
 
 
 
 
 
 
...
37
38
39
 
 
 
 
40
41
42
43
...
95
96
97
 
98
99
100
101
102
103
104
105
106
107
108
109
0
@@ -37,10 +37,7 @@ file('MANIFEST') do
0
   end
0
 end
0
 
0
-file('src/parser.c' => 'src/parser.rl') do
0
- #sh "ragel src/parser.rl | rlgen-cd -G2 -o src/parser.c"
0
- sh 'ragel -G2 src/parser.rl'
0
-end
0
+
0
 
0
 task(:wc) { sh "wc -l ruby_lib/*.rb src/ebb*.{c,h}" }
0
 
0
@@ -98,4 +95,14 @@ end
0
 
0
 Rake::GemPackageTask.new(spec) do |pkg|
0
   pkg.need_zip = true
0
-end
0
\ No newline at end of file
0
+end
0
+
0
+## Compile
0
+file('src/parser.c' => 'src/parser.rl') do
0
+ #sh "ragel src/parser.rl | rlgen-cd -G2 -o src/parser.c" # ragel 5
0
+ sh 'ragel -G2 src/parser.rl' # ragel 6
0
+end
0
+
0
+file('test/parser_test' => ['src/parser.c', 'src/parser.h']) do
0
+ sh "gcc -g -Wall -I#{dir('src')} -DPARSER_TEST #{dir('src/parser.c')} -o #{dir('test/parser_test')}"
0
+end
...
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
...
94
95
96
97
98
99
100
...
102
103
104
105
106
107
108
...
110
111
112
113
114
115
116
...
118
119
120
121
122
123
124
...
246
247
248
 
249
250
251
...
264
265
266
267
 
268
269
270
 
 
271
272
273
 
 
274
275
276
277
278
...
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
299
300
301
...
708
709
710
711
712
 
713
...
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
...
80
81
82
 
83
84
85
...
87
88
89
 
90
91
92
...
94
95
96
 
97
98
99
...
101
102
103
 
104
105
106
...
228
229
230
231
232
233
234
...
247
248
249
 
250
251
252
 
253
254
255
256
257
258
259
260
 
261
262
263
...
266
267
268
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
...
693
694
695
 
 
696
697
0
@@ -32,54 +32,40 @@
0
 static int server_socket(const int port);
0
 static int server_socket_unix(const char *path, int access_mask);
0
 
0
-#define env_add(client, field,flen,value,vlen) \
0
- client->env_fields[client->env_size] = field; \
0
- client->env_field_lengths[client->env_size] = flen; \
0
- client->env_values[client->env_size] = value; \
0
- client->env_value_lengths[client->env_size] = vlen; \
0
- client->env_size += 1;
0
-#define env_add_const(client,field,value,vlen) \
0
- client->env_fields[client->env_size] = NULL; \
0
- client->env_field_lengths[client->env_size] = field; \
0
- client->env_values[client->env_size] = value; \
0
- client->env_value_lengths[client->env_size] = vlen; \
0
- client->env_size += 1;
0
-#define env_error(client) \
0
- client->env_fields[client->env_size] = NULL; \
0
- client->env_field_lengths[client->env_size] = -1; \
0
- client->env_values[client->env_size] = NULL; \
0
- client->env_value_lengths[client->env_size] = -1; \
0
- client->env_size += 1;
0
-
0
-int env_has_error(ebb_client *client)
0
+void env_add(ebb_client *client, const char *field, int flen, const char *value, int vlen)
0
 {
0
- int i;
0
- for(i = 0; i < client->env_size; i++)
0
- if(client->env_field_lengths[i] < 0)
0
- return TRUE;
0
- return FALSE;
0
+ if(client->env_size >= EBB_MAX_ENV) {
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].field = field;
0
+ client->env[client->env_size].field_length = flen;
0
+ client->env[client->env_size].value = value;
0
+ client->env[client->env_size].value_length = vlen;
0
+ client->env_size += 1;
0
 }
0
 
0
-/** Defines common length and error messages for input length validation. */
0
-#define DEF_MAX_LENGTH(N,length) const size_t MAX_##N##_LENGTH = length; const char *MAX_##N##_LENGTH_ERR = "HTTP Parse Error: HTTP element " # N " is longer than the " # length " allowed length."
0
 
0
-/** Validates the max length of given input and throws an exception if over. */
0
-#define VALIDATE_MAX_LENGTH(len, N) if(len > MAX_##N##_LENGTH) { env_error(client); g_message(MAX_##N##_LENGTH_ERR); }
0
-
0
-/* Defines the maximum allowed lengths for various input elements.*/
0
-DEF_MAX_LENGTH(FIELD_NAME, 256);
0
-DEF_MAX_LENGTH(FIELD_VALUE, 80 * 1024);
0
-DEF_MAX_LENGTH(REQUEST_URI, 1024 * 12);
0
-DEF_MAX_LENGTH(FRAGMENT, 1024); /* Don't know if this length is specified somewhere or not */
0
-DEF_MAX_LENGTH(REQUEST_PATH, 1024);
0
-DEF_MAX_LENGTH(QUERY_STRING, (1024 * 10));
0
-DEF_MAX_LENGTH(HEADER, (1024 * (80 + 32)));
0
+void env_add_const(ebb_client *client, int type, const char *value, int vlen)
0
+{
0
+ if(client->env_size >= EBB_MAX_ENV) {
0
+ client->parser.overflow_error = TRUE;
0
+ return;
0
+ }
0
+ client->env[client->env_size].type = type;
0
+ client->env[client->env_size].field = NULL;
0
+ client->env[client->env_size].field_length = -1;
0
+ client->env[client->env_size].value = value;
0
+ client->env[client->env_size].value_length = vlen;
0
+ client->env_size += 1;
0
+}
0
 
0
 void http_field_cb(void *data, const char *field, size_t flen, const char *value, size_t vlen)
0
 {
0
   ebb_client *client = (ebb_client*)(data);
0
- VALIDATE_MAX_LENGTH(flen, FIELD_NAME);
0
- VALIDATE_MAX_LENGTH(vlen, FIELD_VALUE);
0
+ assert(field != NULL);
0
+ assert(value != NULL);
0
   env_add(client, field, flen, value, vlen);
0
 }
0
 
0
@@ -94,7 +80,6 @@ void request_method_cb(void *data, const char *at, size_t length)
0
 void request_uri_cb(void *data, const char *at, size_t length)
0
 {
0
   ebb_client *client = (ebb_client*)(data);
0
- VALIDATE_MAX_LENGTH(length, REQUEST_URI);
0
   env_add_const(client, EBB_REQUEST_URI, at, length);
0
 }
0
 
0
@@ -102,7 +87,6 @@ void request_uri_cb(void *data, const char *at, size_t length)
0
 void fragment_cb(void *data, const char *at, size_t length)
0
 {
0
   ebb_client *client = (ebb_client*)(data);
0
- VALIDATE_MAX_LENGTH(length, FRAGMENT);
0
   env_add_const(client, EBB_FRAGMENT, at, length);
0
 }
0
 
0
@@ -110,7 +94,6 @@ void fragment_cb(void *data, const char *at, size_t length)
0
 void request_path_cb(void *data, const char *at, size_t length)
0
 {
0
   ebb_client *client = (ebb_client*)(data);
0
- VALIDATE_MAX_LENGTH(length, REQUEST_PATH);
0
   env_add_const(client, EBB_REQUEST_PATH, at, length);
0
 }
0
 
0
@@ -118,7 +101,6 @@ void request_path_cb(void *data, const char *at, size_t length)
0
 void query_string_cb(void *data, const char *at, size_t length)
0
 {
0
   ebb_client *client = (ebb_client*)(data);
0
- VALIDATE_MAX_LENGTH(length, QUERY_STRING);
0
   env_add_const(client, EBB_QUERY_STRING, at, length);
0
 }
0
 
0
@@ -246,6 +228,7 @@ void* read_body_into_file(void *_client)
0
   }
0
   rewind(tmpfile);
0
   // g_debug("%d bytes written to file %s", written, client->upload_file_filename);
0
+ dispatch(client);
0
   return NULL;
0
 error:
0
   ebb_client_close(client);
0
@@ -264,15 +247,17 @@ void on_readable(struct ev_loop *loop, ev_io *watcher, int revents)
0
   
0
   ssize_t read = recv( client->fd
0
                      , client->request_buffer + client->read
0
- , EBB_BUFFERSIZE - client->read //- 1 /* -1 is for making ragel happy below */
0
+ , EBB_BUFFERSIZE - client->read
0
                      , 0
0
                      );
0
- if(read <= 0) goto error; /* XXX is this the right action to take for read==0 ? */
0
+ if(read < 0) goto error; /* XXX is this the right action to take for read==0 ? */
0
+ if(read == 0) return;
0
   client->read += read;
0
   ev_timer_again(loop, &client->timeout_watcher);
0
   
0
+ if(client->read == EBB_BUFFERSIZE) goto error;
0
+
0
   if(FALSE == client_finished_parsing) {
0
- //client->request_buffer[client->read] = '\0'; /* make ragel happy */
0
     http_parser_execute( &client->parser
0
                        , client->request_buffer
0
                        , client->read
0
@@ -281,21 +266,21 @@ void on_readable(struct ev_loop *loop, ev_io *watcher, int revents)
0
     if(http_parser_has_error(&client->parser)) goto error;
0
   }
0
   
0
- if(total_request_size == client->read) {
0
- ev_io_stop(loop, watcher);
0
- client->nread_from_body = 0;
0
- dispatch(client);
0
- return;
0
- }
0
-
0
- if(client_finished_parsing && total_request_size > EBB_BUFFERSIZE ) {
0
- /* read body into file - in a thread */
0
- pthread_t thread;
0
- ev_io_stop(loop, watcher);
0
- assert(0 <= pthread_create(&thread, NULL, read_body_into_file, client));
0
- pthread_join(thread, NULL);
0
- dispatch(client);
0
- return;
0
+ if(client_finished_parsing) {
0
+ if(total_request_size == client->read) {
0
+ ev_io_stop(loop, watcher);
0
+ client->nread_from_body = 0;
0
+ dispatch(client);
0
+ return;
0
+ }
0
+ if(total_request_size > EBB_BUFFERSIZE ) {
0
+ /* read body into file - in a thread */
0
+ ev_io_stop(loop, watcher);
0
+ pthread_t thread;
0
+ assert(0 <= pthread_create(&thread, NULL, read_body_into_file, client));
0
+ pthread_detach(thread);
0
+ return;
0
+ }
0
   }
0
   return;
0
 error:
0
@@ -708,5 +693,4 @@ static int server_socket_unix(const char *path, int access_mask) {
0
         return -1;
0
     }
0
     return sfd;
0
-}
0
-
0
+}
0
\ No newline at end of file
...
18
19
20
21
 
22
23
24
...
33
34
35
36
37
38
39
40
41
42
43
44
45
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
47
48
...
67
68
69
70
71
72
73
 
74
75
76
...
18
19
20
 
21
22
23
24
...
33
34
35
 
 
 
 
 
 
 
 
 
 
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
...
75
76
77
 
 
 
 
78
79
80
81
0
@@ -18,7 +18,7 @@
0
 typedef struct ebb_server ebb_server;
0
 typedef struct ebb_client ebb_client;
0
 
0
-#define EBB_BUFFERSIZE (40*1024)
0
+#define EBB_BUFFERSIZE (1024 * (80 + 32) * 2)
0
 #define EBB_MAX_CLIENTS 950
0
 #define EBB_TIMEOUT 30.0
0
 #define EBB_MAX_ENV 100
0
@@ -33,16 +33,24 @@ int ebb_client_read(ebb_client *client, char *buffer, int length);
0
 void ebb_client_write(ebb_client*, const char *data, int length);
0
 void ebb_client_finished( ebb_client *client);
0
 
0
-enum { 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_NAME
0
- , EBB_SERVER_PORT
0
- , EBB_CONTENT_LENGTH
0
- };
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_NAME
0
+ , EBB_SERVER_PORT
0
+ , EBB_CONTENT_LENGTH
0
+ } type;
0
+ const char *field;
0
+ int field_length;
0
+ const char *value;
0
+ int value_length;
0
+};
0
 
0
 struct ebb_client {
0
   EBB_TCP_COMMON
0
@@ -67,10 +75,7 @@ struct ebb_client {
0
   
0
   /* the ENV structure */
0
   int env_size;
0
- const char *env_fields[EBB_MAX_ENV];
0
- int env_field_lengths[EBB_MAX_ENV];
0
- const char *env_values[EBB_MAX_ENV];
0
- int env_value_lengths[EBB_MAX_ENV];
0
+ struct ebb_env_item env[EBB_MAX_ENV];
0
 };
0
 
0
 /*** Ebb Server ***/
...
10
11
12
 
13
14
15
...
27
28
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
...
155
156
157
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
159
160
...
162
163
164
165
166
167
168
169
 
170
171
172
 
 
173
174
175
...
224
225
226
 
 
 
 
227
228
229
...
10
11
12
13
14
15
16
...
28
29
30
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
32
33
...
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
150
151
152
153
154
155
156
157
158
159
160
161
162
...
164
165
166
 
 
 
 
 
167
168
 
 
169
170
171
172
173
...
222
223
224
225
226
227
228
229
230
231
0
@@ -10,6 +10,7 @@
0
 
0
 static VALUE cServer;
0
 static VALUE cClient;
0
+static VALUE eParserError;
0
 
0
 static VALUE global_http_prefix;
0
 static VALUE global_request_method;
0
@@ -27,43 +28,6 @@ static VALUE global_http_host;
0
 
0
 #define ASCII_UPPER(ch) ('a' <= ch && ch <= 'z' ? ch - 'a' + 'A' : ch)
0
 
0
-/* Variables with an underscore are C-level variables */
0
-VALUE env_field(const char *field, int length)
0
-{
0
- if(field == NULL) {
0
- switch(length) {
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_NAME: return global_server_name;
0
- case EBB_SERVER_PORT: return global_server_port;
0
- case EBB_CONTENT_LENGTH: return global_content_length;
0
- default: assert(FALSE); /* unknown const */
0
- }
0
- } else {
0
- VALUE f = rb_str_new(NULL, RSTRING_LEN(global_http_prefix) + 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 < length; i++) {
0
- char *ch = RSTRING_PTR(f) + RSTRING_LEN(global_http_prefix) + i;
0
- if(field[i] == '-') {
0
- *ch = '_';
0
- } else {
0
- *ch = ASCII_UPPER(field[i]);
0
- }
0
- }
0
- return f;
0
- }
0
- assert(FALSE);
0
- return Qnil;
0
-}
0
-
0
 VALUE client_new(ebb_client *_client)
0
 {
0
   VALUE client = Data_Wrap_Struct(cClient, 0, 0, _client);
0
@@ -155,6 +119,44 @@ VALUE server_unlisten(VALUE x, VALUE server)
0
   return Qnil;
0
 }
0
 
0
+/* Variables with an underscore are C-level variables */
0
+VALUE env_field(struct ebb_env_item *item)
0
+{
0
+ VALUE f;
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_NAME: return global_server_name;
0
+ case EBB_SERVER_PORT: return global_server_port;
0
+ case EBB_CONTENT_LENGTH: return global_content_length;
0
+ }
0
+ assert(FALSE);
0
+ return Qnil;
0
+}
0
+
0
+VALUE env_value(struct ebb_env_item *item)
0
+{
0
+ if(item->value_length > 0)
0
+ return rb_str_new(item->value, item->value_length);
0
+ else
0
+ return Qnil;
0
+}
0
 
0
 VALUE client_env(VALUE x, VALUE client)
0
 {
0
@@ -162,14 +164,10 @@ VALUE client_env(VALUE x, VALUE client)
0
   VALUE hash = rb_hash_new();
0
   int i;
0
   Data_Get_Struct(client, ebb_client, _client);
0
- /* This client->env_fields, client->env_value structure is pretty hacky
0
- * and a bit hard to follow. Look at the #defines at the top of ebb.c to
0
- * see what they are doing. Basically it's a list of (ptr,length) pairs
0
- * for both a field and value
0
- */
0
+
0
   for(i=0; i < _client->env_size; i++) {
0
- rb_hash_aset(hash, env_field(_client->env_fields[i], _client->env_field_lengths[i])
0
- , rb_str_new(_client->env_values[i], _client->env_value_lengths[i])
0
+ rb_hash_aset(hash, env_field(&_client->env[i])
0
+ , env_value(&_client->env[i])
0
                      );
0
   }
0
   rb_hash_aset(hash, global_path_info, rb_hash_aref(hash, global_request_path));
0
@@ -224,6 +222,10 @@ void Init_ebb_ext()
0
   VALUE mEbb = rb_define_module("Ebb");
0
   VALUE mFFI = rb_define_module_under(mEbb, "FFI");
0
   
0
+
0
+ eParserError = rb_define_class_under(mEbb, "ParserError", rb_eIOError);
0
+
0
+
0
   /** Defines global strings in the init method. */
0
 #define DEF_GLOBAL(N, val) global_##N = rb_obj_freeze(rb_str_new2(val)); rb_global_variable(&global_##N)
0
   DEF_GLOBAL(http_prefix, "HTTP_");
...
43
44
45
46
...
43
44
45
 
0
@@ -43,4 +43,3 @@ $objs = ['ebb.o', 'ebb_ruby.o', 'parser.o']
0
 
0
 dir_config('ebb_ext')
0
 create_makefile('ebb_ext')
0
-
...
17
18
19
 
20
21
22
...
36
37
38
39
40
41
42
 
43
44
45
...
17
18
19
20
21
22
23
...
37
38
39
 
40
41
 
42
43
44
45
0
@@ -17,6 +17,7 @@ typedef void (*field_cb)(void *data, const char *field, size_t flen, const char
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 nread;
0
@@ -36,10 +37,9 @@ typedef struct http_parser {
0
   element_cb http_version;
0
   element_cb header_done;
0
   element_cb content_length;
0
-
0
 } http_parser;
0
 
0
-int http_parser_init(http_parser *parser);
0
+void http_parser_init(http_parser *parser);
0
 int http_parser_finish(http_parser *parser);
0
 size_t http_parser_execute(http_parser *parser, const char *data, size_t len, size_t off);
0
 int http_parser_has_error(http_parser *parser);
...
9
10
11
 
 
12
13
14
...
19
20
21
22
23
24
25
 
 
 
 
26
27
28
29
 
 
 
 
 
30
31
32
...
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
...
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
130
 
131
132
133
134
135
136
137
138
 
 
 
 
 
 
 
 
 
 
139
140
141
...
149
150
151
152
 
 
153
154
155
...
177
178
179
180
 
181
182
 
183
184
 
185
186
187
188
189
190
 
191
192
193
194
195
 
196
...
9
10
11
12
13
14
15
16
...
21
22
23
 
24
25
26
27
28
29
30
31
32
33
 
34
35
36
37
38
39
40
41
...
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
102
103
104
105
106
107
108
 
109
110
111
...
130
131
132
 
133
134
135
 
 
 
136
137
138
139
 
 
140
141
142
143
 
 
 
144
145
146
147
 
148
149
150
151
152
 
 
 
153
154
155
156
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
185
186
...
194
195
196
 
197
198
199
200
201
...
223
224
225
 
226
227
 
228
229
 
230
231
 
232
233
234
 
235
236
237
238
239
 
240
241
0
@@ -9,6 +9,8 @@
0
 #include <ctype.h>
0
 #include <string.h>
0
 
0
+#define TRUE 1
0
+#define FALSE 0
0
 #define LEN(AT, FPC) (FPC - buffer - parser->AT)
0
 #define MARK(M,FPC) (parser->M = (FPC) - buffer)
0
 #define PTR_TO(F) (buffer + parser->F)
0
@@ -19,14 +21,21 @@
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
+ if(parser->field_len > 256) {
0
+ parser->overflow_error = TRUE;
0
+ fbreak;
0
+ }
0
   }
0
 
0
   action start_value { MARK(mark, fpc); }
0
- action write_value {
0
+ action write_value {
0
+ if(LEN(mark, fpc) > 80 * 1024) {
0
+ parser->overflow_error = TRUE;
0
+ fbreak;
0
+ }
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
@@ -42,35 +51,61 @@
0
     if(parser->request_method != NULL)
0
       parser->request_method(parser->data, PTR_TO(mark), LEN(mark, fpc));
0
   }
0
- action request_uri {
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
   }
0
-
0
+
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->query_string != NULL)
0
       parser->query_string(parser->data, PTR_TO(query_start), LEN(query_start, fpc));
0
   }
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
   }
0
-
0
+
0
   action request_path {
0
+ if(LEN(mark, fpc) > 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
   }
0
-
0
- action done {
0
+
0
+ action fragment {
0
+ /* Don't know if this length is specified somewhere or not */
0
+ if(LEN(mark, fpc) > 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
+ }
0
+
0
+ action done {
0
+ if(parser->nread > 1024 * (80 + 32)) {
0
+ parser->overflow_error = TRUE;
0
+ fbreak;
0
+ }
0
     parser->body_start = fpc - buffer + 1;
0
     if(parser->header_done != NULL)
0
       parser->header_done(parser->data, fpc + 1, pe - fpc - 1);
0
     fbreak;
0
   }
0
 
0
-
0
 #### HTTP PROTOCOL GRAMMAR
0
 # line endings
0
   CRLF = "\r\n";
0
@@ -95,47 +130,57 @@
0
   scheme = ( alpha | digit | "+" | "-" | "." )* ;
0
   absolute_uri = (scheme ":" (uchar | reserved )*);
0
 
0
- path = (pchar+ ( "/" pchar* )*) ;
0
+ path = ( pchar+ ( "/" pchar* )* ) ;
0
   query = ( uchar | reserved )* %query_string ;
0
   param = ( pchar | "/" )* ;
0
- params = (param ( ";" param )*) ;
0
- rel_path = (path? %request_path (";" params)?) ("?" %start_query query)?;
0
- absolute_path = ("/"+ rel_path);
0
+ params = ( param ( ";" param )* ) ;
0
+ rel_path = ( path? %request_path (";" params)? ) ("?" %start_query query)?;
0
+ absolute_path = ( "/"+ rel_path );
0
 
0
- Request_URI = ("*" | absolute_uri | absolute_path) >mark %request_uri;
0
- Method = (upper | digit | safe){1,20} >mark %request_method;
0
+ Request_URI = ( "*" | absolute_uri | absolute_path ) >mark %request_uri;
0
+ Fragment = ( uchar | reserved )* >mark %fragment;
0
+ Method = ( upper | digit | safe ){1,20} >mark %request_method;
0
 
0
- http_number = (digit+ "." digit+) ;
0
- HTTP_Version = ("HTTP/" http_number) >mark %http_version ;
0
- Request_Line = (Method " " Request_URI " " HTTP_Version CRLF) ;
0
+ http_number = ( digit+ "." digit+ ) ;
0
+ HTTP_Version = ( "HTTP/" http_number ) >mark %http_version ;
0
+ Request_Line = ( Method " " Request_URI ("#" Fragment){0,1} " " HTTP_Version CRLF ) ;
0
 
0
- field_name = (token -- ":")+ >start_field %write_field;
0
+ field_name = ( token -- ":" )+ >start_field %write_field;
0
 
0
   field_value = any* >start_value %write_value;
0
 
0
   message_header = field_name ":" " "* field_value :> CRLF;
0
- content_length = "Content-Length:"i " "* (field_value >mark %content_length) :> CRLF;
0
-
0
- Request = Request_Line (content_length | message_header)* ( CRLF @done);
0
+ content_length = "Content-Length:"i " "* (digit{1,10} >mark %content_length) :> CRLF;
0
+
0
+ Request = Request_Line (content_length | message_header )* ( CRLF @done );
0
 
0
 main := Request;
0
+
0
 }%%
0
 
0
 /** Data **/
0
 %% write data;
0
 
0
-int http_parser_init(http_parser *parser) {
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->mark = 0;
0
   parser->nread = 0;
0
   parser->field_len = 0;
0
- parser->field_start = 0;
0
-
0
- return(1);
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
 
0
@@ -149,7 +194,8 @@ size_t http_parser_execute(http_parser *parser, const char *buffer, size_t len,
0
   p = buffer+off;
0
   pe = buffer+len;
0
   
0
- //assert(*pe == '\0' && "pointer does not end on NUL");
0
+ /* Ragel 6 does not require this */
0
+ // assert(*pe == '\0' && "pointer does not end on NUL");
0
   assert(pe - p == len - off && "pointers aren't same distance");
0
   
0
   %% write exec;
0
@@ -177,19 +223,18 @@ size_t http_parser_execute(http_parser *parser, const char *buffer, size_t len,
0
 
0
 int http_parser_finish(http_parser *parser)
0
 {
0
- if (http_parser_has_error(parser) ) {
0
+ if (http_parser_has_error(parser))
0
     return -1;
0
- } else if (http_parser_is_finished(parser) ) {
0
+ else if (http_parser_is_finished(parser))
0
     return 1;
0
- } else {
0
+ else
0
     return 0;
0
- }
0
 }
0
 
0
 int http_parser_has_error(http_parser *parser) {
0
- return parser->cs == http_parser_error;
0
+ return parser->cs == http_parser_error || parser->overflow_error;
0
 }
0
 
0
 int http_parser_is_finished(http_parser *parser) {
0
   return parser->cs >= http_parser_first_final;
0
-}
0
+}
0
\ No newline at end of file
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
9
10
11
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