mongrel 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +2 -2
- data/Rakefile +1 -1
- data/doc/rdoc/classes/Mongrel/URIClassifier.html +17 -28
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/M000015.html +2 -17
- data/doc/rdoc/classes/Mongrel/URIClassifier.src/M000018.html +21 -26
- data/doc/rdoc/created.rid +1 -1
- data/doc/rdoc/files/README.html +3 -3
- data/doc/rdoc/files/ext/http11/http11_c.html +1 -1
- data/ext/http11/http11.c +47 -54
- data/ext/http11/tst_search.c +18 -3
- data/test/test_uriclassifier.rb +52 -1
- metadata +2 -2
data/README
CHANGED
@@ -11,7 +11,7 @@ scream without too many portability issues.
|
|
11
11
|
|
12
12
|
== Status
|
13
13
|
|
14
|
-
The 0.2.
|
14
|
+
The 0.2.1 release of Mongrel features an HTTP core server that is the fastest possible
|
15
15
|
thing I could get without using something other than Ruby. It features a few bug fixes,
|
16
16
|
but mostly just a change to the Mongrel::HttpResponse class to make it more feature
|
17
17
|
complete. The remaining development will be spent getting Mongrel to work with
|
@@ -68,7 +68,7 @@ basic way to give a more complex 404 message.
|
|
68
68
|
|
69
69
|
== Speed
|
70
70
|
|
71
|
-
The 0.2.
|
71
|
+
The 0.2.1 release probably consists of the most effort I've ever put into
|
72
72
|
tuning a Ruby library for speed. It consists of nearly everything I could think
|
73
73
|
of to make Mongrel the fastest Ruby HTTP library possible. I've tried about
|
74
74
|
seven different architectures and IO processing methods and none of them
|
data/Rakefile
CHANGED
@@ -27,4 +27,4 @@ setup_extension("http11", "http11")
|
|
27
27
|
|
28
28
|
summary = "An experimental fast simple web server for Ruby."
|
29
29
|
test_file = "test/test_ws.rb"
|
30
|
-
setup_gem("mongrel", "0.2.
|
30
|
+
setup_gem("mongrel", "0.2.1", "Zed A. Shaw", summary, [], test_file)
|
@@ -137,33 +137,6 @@ an initial search for the a URI prefix, and then to break the URI into
|
|
137
137
|
SCRIPT_NAME and PATH_INFO portions. It actually will do two searches most
|
138
138
|
of the time in order to find the right handler for the registered prefix
|
139
139
|
portion.
|
140
|
-
</p>
|
141
|
-
<p>
|
142
|
-
Here’s how it all works. Let’s say you register
|
143
|
-
"/blog" with a BlogHandler. Great. Now, someone goes to
|
144
|
-
"/blog/zedsucks/ass". You want SCRIPT_NAME to be
|
145
|
-
"/blog" and PATH_INFO to be "/zedsucks/ass". <a
|
146
|
-
href="URIClassifier.html">URIClassifier</a> first does a TST search and
|
147
|
-
comes up with a failure, but knows that the failure ended at the
|
148
|
-
"/blog" part. So, that’s the SCRIPT_NAME. It then tries a
|
149
|
-
second search for just "/blog". If that comes back good then it
|
150
|
-
sets the rest ("/zedsucks/ass") to the PATH_INFO and returns the
|
151
|
-
BlogHandler.
|
152
|
-
</p>
|
153
|
-
<p>
|
154
|
-
The optimal approach would be to not do the search twice, but the TST lib
|
155
|
-
doesn’t really support returning prefixes. Might not be hard to add
|
156
|
-
later.
|
157
|
-
</p>
|
158
|
-
<p>
|
159
|
-
The key though is that it will try to match the <b>longest</b> match it
|
160
|
-
can. If you also register "/blog/zed" then the above URI will
|
161
|
-
give SCRIPT_NAME="/blog/zed", PATH_INFO="sucks/ass".
|
162
|
-
Probably not what you want, so your handler will need to do the 404 thing.
|
163
|
-
</p>
|
164
|
-
<p>
|
165
|
-
Take a look at the postamble of example/tepee.rb to see how this is handled
|
166
|
-
for Camping.
|
167
140
|
</p>
|
168
141
|
</div>
|
169
142
|
</div>
|
@@ -216,7 +189,23 @@ uc.resolve("/notfound/orhere") → nil, nil, nil<br />
|
|
216
189
|
<p>
|
217
190
|
Attempts to resolve either the whole URI or at the longest prefix,
|
218
191
|
returning the prefix (as script_info), path (as path_info), and registered
|
219
|
-
handler (usually an <a href="HttpHandler.html">HttpHandler</a>).
|
192
|
+
handler (usually an <a href="HttpHandler.html">HttpHandler</a>). If it
|
193
|
+
doesn’t find a handler registered at the longest match then it
|
194
|
+
returns nil,nil,nil.
|
195
|
+
</p>
|
196
|
+
<p>
|
197
|
+
Because the resolver uses a trie you are able to register a handler at
|
198
|
+
<b>any</b> character in the URI and it will be handled as long as
|
199
|
+
it’s the longest prefix. So, if you registered handler 1 at
|
200
|
+
"/something/lik", and 2 at "/something/like/that", then
|
201
|
+
a a search for "/something/like" would give you 1. A search for
|
202
|
+
"/something/like/that/too" would give you 2.
|
203
|
+
</p>
|
204
|
+
<p>
|
205
|
+
This is very powerful since it means you can also attach handlers to parts
|
206
|
+
of the ; (semi-colon) separated path params, any part of the path, use off
|
207
|
+
chars, anything really. It also means that it’s very efficient to do
|
208
|
+
this only taking as long as the URI has characters.
|
220
209
|
</p>
|
221
210
|
<p>
|
222
211
|
It expects strings. Don‘t try other string-line stuff yet.
|
@@ -24,23 +24,6 @@
|
|
24
24
|
* will do two searches most of the time in order to find the right handler for the
|
25
25
|
* registered prefix portion.
|
26
26
|
*
|
27
|
-
* Here's how it all works. Let's say you register "/blog" with a BlogHandler. Great.
|
28
|
-
* Now, someone goes to "/blog/zedsucks/ass". You want SCRIPT_NAME to be "/blog" and
|
29
|
-
* PATH_INFO to be "/zedsucks/ass". URIClassifier first does a TST search and comes
|
30
|
-
* up with a failure, but knows that the failure ended at the "/blog" part. So, that's
|
31
|
-
* the SCRIPT_NAME. It then tries a second search for just "/blog". If that comes back
|
32
|
-
* good then it sets the rest ("/zedsucks/ass") to the PATH_INFO and returns the BlogHandler.
|
33
|
-
*
|
34
|
-
* The optimal approach would be to not do the search twice, but the TST lib doesn't
|
35
|
-
* really support returning prefixes. Might not be hard to add later.
|
36
|
-
*
|
37
|
-
* The key though is that it will try to match the *longest* match it can. If you
|
38
|
-
* also register "/blog/zed" then the above URI will give SCRIPT_NAME="/blog/zed",
|
39
|
-
* PATH_INFO="sucks/ass". Probably not what you want, so your handler will need to
|
40
|
-
* do the 404 thing.
|
41
|
-
*
|
42
|
-
* Take a look at the postamble of example/tepee.rb to see how this is handled for
|
43
|
-
* Camping.
|
44
27
|
*/
|
45
28
|
VALUE URIClassifier_init(VALUE self)
|
46
29
|
{
|
@@ -49,6 +32,8 @@ VALUE URIClassifier_init(VALUE self)
|
|
49
32
|
// we create an internal hash to protect stuff from the GC
|
50
33
|
hash = rb_hash_new();
|
51
34
|
rb_ivar_set(self, id_handler_map, hash);
|
35
|
+
|
36
|
+
return self;
|
52
37
|
}</pre>
|
53
38
|
</body>
|
54
39
|
</html>
|
@@ -18,7 +18,19 @@
|
|
18
18
|
*
|
19
19
|
* Attempts to resolve either the whole URI or at the longest prefix, returning
|
20
20
|
* the prefix (as script_info), path (as path_info), and registered handler
|
21
|
-
* (usually an HttpHandler).
|
21
|
+
* (usually an HttpHandler). If it doesn't find a handler registered at the longest
|
22
|
+
* match then it returns nil,nil,nil.
|
23
|
+
*
|
24
|
+
* Because the resolver uses a trie you are able to register a handler at *any* character
|
25
|
+
* in the URI and it will be handled as long as it's the longest prefix. So, if you
|
26
|
+
* registered handler #1 at "/something/lik", and #2 at "/something/like/that", then a
|
27
|
+
* a search for "/something/like" would give you #1. A search for "/something/like/that/too"
|
28
|
+
* would give you #2.
|
29
|
+
*
|
30
|
+
* This is very powerful since it means you can also attach handlers to parts of the ;
|
31
|
+
* (semi-colon) separated path params, any part of the path, use off chars, anything really.
|
32
|
+
* It also means that it's very efficient to do this only taking as long as the URI has
|
33
|
+
* characters.
|
22
34
|
*
|
23
35
|
* It expects strings. Don't try other string-line stuff yet.
|
24
36
|
*/
|
@@ -28,8 +40,6 @@ VALUE URIClassifier_resolve(VALUE self, VALUE uri)
|
|
28
40
|
int pref_len = 0;
|
29
41
|
struct tst *tst = NULL;
|
30
42
|
VALUE result;
|
31
|
-
VALUE script_name;
|
32
|
-
VALUE path_info;
|
33
43
|
unsigned char *uri_str = NULL;
|
34
44
|
unsigned char *script_name_str = NULL;
|
35
45
|
|
@@ -41,32 +51,17 @@ VALUE URIClassifier_resolve(VALUE self, VALUE uri)
|
|
41
51
|
// setup for multiple return values
|
42
52
|
result = rb_ary_new();
|
43
53
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
handler = tst_search(script_name_str, tst, NULL);
|
50
|
-
|
51
|
-
if(handler == NULL) {
|
52
|
-
// didn't find the script name at all
|
53
|
-
rb_ary_push(result, Qnil);
|
54
|
-
rb_ary_push(result, Qnil);
|
55
|
-
rb_ary_push(result, Qnil);
|
56
|
-
return result;
|
57
|
-
} else {
|
58
|
-
// found a handler, setup the path info and we're good
|
59
|
-
path_info = rb_str_substr(uri, pref_len, RSTRING(uri)->len);
|
60
|
-
}
|
54
|
+
if(handler) {
|
55
|
+
rb_ary_push(result, rb_str_substr (uri, 0, pref_len));
|
56
|
+
rb_ary_push(result, rb_str_substr(uri, pref_len, RSTRING(uri)->len));
|
57
|
+
rb_ary_push(result, (VALUE)handler);
|
61
58
|
} else {
|
62
|
-
//
|
63
|
-
|
64
|
-
|
59
|
+
// not found so push back nothing
|
60
|
+
rb_ary_push(result, Qnil);
|
61
|
+
rb_ary_push(result, Qnil);
|
62
|
+
rb_ary_push(result, Qnil);
|
65
63
|
}
|
66
64
|
|
67
|
-
rb_ary_push(result, script_name);
|
68
|
-
rb_ary_push(result, path_info);
|
69
|
-
rb_ary_push(result, (VALUE)handler);
|
70
65
|
return result;
|
71
66
|
}</pre>
|
72
67
|
</body>
|
data/doc/rdoc/created.rid
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
Thu Feb 02 01:57:10 EST 2006
|
data/doc/rdoc/files/README.html
CHANGED
@@ -56,7 +56,7 @@
|
|
56
56
|
</tr>
|
57
57
|
<tr class="top-aligned-row">
|
58
58
|
<td><strong>Last Update:</strong></td>
|
59
|
-
<td>
|
59
|
+
<td>Thu Feb 02 01:53:46 EST 2006</td>
|
60
60
|
</tr>
|
61
61
|
</table>
|
62
62
|
</div>
|
@@ -84,7 +84,7 @@ portability issues.
|
|
84
84
|
</p>
|
85
85
|
<h2>Status</h2>
|
86
86
|
<p>
|
87
|
-
The 0.2.
|
87
|
+
The 0.2.1 release of <a href="../classes/Mongrel.html">Mongrel</a> features
|
88
88
|
an HTTP core server that is the fastest possible thing I could get without
|
89
89
|
using something other than Ruby. It features a few bug fixes, but mostly
|
90
90
|
just a change to the <a
|
@@ -154,7 +154,7 @@ for a basic way to give a more complex 404 message.
|
|
154
154
|
</p>
|
155
155
|
<h2>Speed</h2>
|
156
156
|
<p>
|
157
|
-
The 0.2.
|
157
|
+
The 0.2.1 release probably consists of the most effort I’ve ever put
|
158
158
|
into tuning a Ruby library for speed. It consists of nearly everything I
|
159
159
|
could think of to make <a href="../classes/Mongrel.html">Mongrel</a> the
|
160
160
|
fastest Ruby HTTP library possible. I’ve tried about seven different
|
data/ext/http11/http11.c
CHANGED
@@ -11,15 +11,21 @@ static VALUE cHttpParser;
|
|
11
11
|
static VALUE cURIClassifier;
|
12
12
|
static int id_handler_map;
|
13
13
|
|
14
|
+
static VALUE global_http_prefix;
|
15
|
+
static VALUE global_request_method;
|
16
|
+
static VALUE global_path_info;
|
17
|
+
static VALUE global_query_string;
|
18
|
+
static VALUE global_http_version;
|
19
|
+
|
14
20
|
|
15
21
|
void http_field(void *data, const char *field, size_t flen, const char *value, size_t vlen)
|
16
22
|
{
|
17
23
|
char *ch, *end;
|
18
24
|
VALUE req = (VALUE)data;
|
19
|
-
VALUE f = rb_str_new2("HTTP_");
|
20
25
|
VALUE v = rb_str_new(value, vlen);
|
21
|
-
|
22
|
-
|
26
|
+
VALUE f = rb_str_dup(global_http_prefix);
|
27
|
+
|
28
|
+
f = rb_str_buf_cat(f, field, flen);
|
23
29
|
|
24
30
|
for(ch = RSTRING(f)->ptr, end = ch + RSTRING(f)->len; ch < end; ch++) {
|
25
31
|
if(*ch == '-') {
|
@@ -36,16 +42,14 @@ void request_method(void *data, const char *at, size_t length)
|
|
36
42
|
{
|
37
43
|
VALUE req = (VALUE)data;
|
38
44
|
VALUE val = rb_str_new(at, length);
|
39
|
-
|
40
|
-
rb_hash_aset(req, id, val);
|
45
|
+
rb_hash_aset(req, global_request_method, val);
|
41
46
|
}
|
42
47
|
|
43
48
|
void path_info(void *data, const char *at, size_t length)
|
44
49
|
{
|
45
50
|
VALUE req = (VALUE)data;
|
46
51
|
VALUE val = rb_str_new(at, length);
|
47
|
-
|
48
|
-
rb_hash_aset(req, id, val);
|
52
|
+
rb_hash_aset(req, global_path_info, val);
|
49
53
|
}
|
50
54
|
|
51
55
|
|
@@ -53,16 +57,14 @@ void query_string(void *data, const char *at, size_t length)
|
|
53
57
|
{
|
54
58
|
VALUE req = (VALUE)data;
|
55
59
|
VALUE val = rb_str_new(at, length);
|
56
|
-
|
57
|
-
rb_hash_aset(req, id, val);
|
60
|
+
rb_hash_aset(req, global_query_string, val);
|
58
61
|
}
|
59
62
|
|
60
63
|
void http_version(void *data, const char *at, size_t length)
|
61
64
|
{
|
62
65
|
VALUE req = (VALUE)data;
|
63
66
|
VALUE val = rb_str_new(at, length);
|
64
|
-
|
65
|
-
rb_hash_aset(req, id, val);
|
67
|
+
rb_hash_aset(req, global_http_version, val);
|
66
68
|
}
|
67
69
|
|
68
70
|
|
@@ -258,23 +260,6 @@ VALUE URIClassifier_alloc(VALUE klass)
|
|
258
260
|
* will do two searches most of the time in order to find the right handler for the
|
259
261
|
* registered prefix portion.
|
260
262
|
*
|
261
|
-
* Here's how it all works. Let's say you register "/blog" with a BlogHandler. Great.
|
262
|
-
* Now, someone goes to "/blog/zedsucks/ass". You want SCRIPT_NAME to be "/blog" and
|
263
|
-
* PATH_INFO to be "/zedsucks/ass". URIClassifier first does a TST search and comes
|
264
|
-
* up with a failure, but knows that the failure ended at the "/blog" part. So, that's
|
265
|
-
* the SCRIPT_NAME. It then tries a second search for just "/blog". If that comes back
|
266
|
-
* good then it sets the rest ("/zedsucks/ass") to the PATH_INFO and returns the BlogHandler.
|
267
|
-
*
|
268
|
-
* The optimal approach would be to not do the search twice, but the TST lib doesn't
|
269
|
-
* really support returning prefixes. Might not be hard to add later.
|
270
|
-
*
|
271
|
-
* The key though is that it will try to match the *longest* match it can. If you
|
272
|
-
* also register "/blog/zed" then the above URI will give SCRIPT_NAME="/blog/zed",
|
273
|
-
* PATH_INFO="sucks/ass". Probably not what you want, so your handler will need to
|
274
|
-
* do the 404 thing.
|
275
|
-
*
|
276
|
-
* Take a look at the postamble of example/tepee.rb to see how this is handled for
|
277
|
-
* Camping.
|
278
263
|
*/
|
279
264
|
VALUE URIClassifier_init(VALUE self)
|
280
265
|
{
|
@@ -283,6 +268,8 @@ VALUE URIClassifier_init(VALUE self)
|
|
283
268
|
// we create an internal hash to protect stuff from the GC
|
284
269
|
hash = rb_hash_new();
|
285
270
|
rb_ivar_set(self, id_handler_map, hash);
|
271
|
+
|
272
|
+
return self;
|
286
273
|
}
|
287
274
|
|
288
275
|
|
@@ -356,7 +343,19 @@ VALUE URIClassifier_unregister(VALUE self, VALUE uri)
|
|
356
343
|
*
|
357
344
|
* Attempts to resolve either the whole URI or at the longest prefix, returning
|
358
345
|
* the prefix (as script_info), path (as path_info), and registered handler
|
359
|
-
* (usually an HttpHandler).
|
346
|
+
* (usually an HttpHandler). If it doesn't find a handler registered at the longest
|
347
|
+
* match then it returns nil,nil,nil.
|
348
|
+
*
|
349
|
+
* Because the resolver uses a trie you are able to register a handler at *any* character
|
350
|
+
* in the URI and it will be handled as long as it's the longest prefix. So, if you
|
351
|
+
* registered handler #1 at "/something/lik", and #2 at "/something/like/that", then a
|
352
|
+
* a search for "/something/like" would give you #1. A search for "/something/like/that/too"
|
353
|
+
* would give you #2.
|
354
|
+
*
|
355
|
+
* This is very powerful since it means you can also attach handlers to parts of the ;
|
356
|
+
* (semi-colon) separated path params, any part of the path, use off chars, anything really.
|
357
|
+
* It also means that it's very efficient to do this only taking as long as the URI has
|
358
|
+
* characters.
|
360
359
|
*
|
361
360
|
* It expects strings. Don't try other string-line stuff yet.
|
362
361
|
*/
|
@@ -366,8 +365,6 @@ VALUE URIClassifier_resolve(VALUE self, VALUE uri)
|
|
366
365
|
int pref_len = 0;
|
367
366
|
struct tst *tst = NULL;
|
368
367
|
VALUE result;
|
369
|
-
VALUE script_name;
|
370
|
-
VALUE path_info;
|
371
368
|
unsigned char *uri_str = NULL;
|
372
369
|
unsigned char *script_name_str = NULL;
|
373
370
|
|
@@ -379,32 +376,17 @@ VALUE URIClassifier_resolve(VALUE self, VALUE uri)
|
|
379
376
|
// setup for multiple return values
|
380
377
|
result = rb_ary_new();
|
381
378
|
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
handler = tst_search(script_name_str, tst, NULL);
|
388
|
-
|
389
|
-
if(handler == NULL) {
|
390
|
-
// didn't find the script name at all
|
391
|
-
rb_ary_push(result, Qnil);
|
392
|
-
rb_ary_push(result, Qnil);
|
393
|
-
rb_ary_push(result, Qnil);
|
394
|
-
return result;
|
395
|
-
} else {
|
396
|
-
// found a handler, setup the path info and we're good
|
397
|
-
path_info = rb_str_substr(uri, pref_len, RSTRING(uri)->len);
|
398
|
-
}
|
379
|
+
if(handler) {
|
380
|
+
rb_ary_push(result, rb_str_substr (uri, 0, pref_len));
|
381
|
+
rb_ary_push(result, rb_str_substr(uri, pref_len, RSTRING(uri)->len));
|
382
|
+
rb_ary_push(result, (VALUE)handler);
|
399
383
|
} else {
|
400
|
-
//
|
401
|
-
|
402
|
-
|
384
|
+
// not found so push back nothing
|
385
|
+
rb_ary_push(result, Qnil);
|
386
|
+
rb_ary_push(result, Qnil);
|
387
|
+
rb_ary_push(result, Qnil);
|
403
388
|
}
|
404
389
|
|
405
|
-
rb_ary_push(result, script_name);
|
406
|
-
rb_ary_push(result, path_info);
|
407
|
-
rb_ary_push(result, (VALUE)handler);
|
408
390
|
return result;
|
409
391
|
}
|
410
392
|
|
@@ -414,6 +396,17 @@ void Init_http11()
|
|
414
396
|
|
415
397
|
mMongrel = rb_define_module("Mongrel");
|
416
398
|
id_handler_map = rb_intern("@handler_map");
|
399
|
+
|
400
|
+
global_http_prefix = rb_str_new2("HTTP_");
|
401
|
+
rb_global_variable(&global_http_prefix);
|
402
|
+
global_request_method = rb_str_new2("REQUEST_METHOD");
|
403
|
+
rb_global_variable(&global_request_method);
|
404
|
+
global_path_info = rb_str_new2("PATH_INFO");
|
405
|
+
rb_global_variable(&global_path_info);
|
406
|
+
global_query_string = rb_str_new2("QUERY_STRING");
|
407
|
+
rb_global_variable(&global_query_string);
|
408
|
+
global_http_version = rb_str_new2("HTTP_VERSION");
|
409
|
+
rb_global_variable(&global_http_version);
|
417
410
|
|
418
411
|
cHttpParser = rb_define_class_under(mMongrel, "HttpParser", rb_cObject);
|
419
412
|
rb_define_alloc_func(cHttpParser, HttpParser_alloc);
|
data/ext/http11/tst_search.c
CHANGED
@@ -7,18 +7,20 @@
|
|
7
7
|
void *tst_search(unsigned char *key, struct tst *tst, int *prefix_len)
|
8
8
|
{
|
9
9
|
struct node *current_node;
|
10
|
+
void *longest_match = NULL;
|
10
11
|
int key_index;
|
11
12
|
|
12
13
|
assert(key != NULL && "key can't be NULL");
|
13
14
|
assert(tst != NULL && "tst can't be NULL");
|
14
15
|
|
15
|
-
|
16
16
|
if(key[0] == 0)
|
17
17
|
return NULL;
|
18
18
|
|
19
19
|
if(tst->head[(int)key[0]] == NULL)
|
20
20
|
return NULL;
|
21
|
+
|
21
22
|
|
23
|
+
if(prefix_len) *prefix_len = 0;
|
22
24
|
current_node = tst->head[(int)key[0]];
|
23
25
|
key_index = 1;
|
24
26
|
|
@@ -30,7 +32,13 @@ void *tst_search(unsigned char *key, struct tst *tst, int *prefix_len)
|
|
30
32
|
if(prefix_len) *prefix_len = key_index;
|
31
33
|
return current_node->middle;
|
32
34
|
} else {
|
35
|
+
|
33
36
|
current_node = current_node->middle;
|
37
|
+
if(current_node && current_node->value == 0) {
|
38
|
+
if(prefix_len) *prefix_len = key_index+1;
|
39
|
+
longest_match = current_node->middle;
|
40
|
+
}
|
41
|
+
|
34
42
|
key_index++;
|
35
43
|
continue;
|
36
44
|
}
|
@@ -39,16 +47,23 @@ void *tst_search(unsigned char *key, struct tst *tst, int *prefix_len)
|
|
39
47
|
((current_node->value != 0) && (key[key_index] <
|
40
48
|
current_node->value)) )
|
41
49
|
{
|
50
|
+
if(current_node->left && current_node->value == 0) {
|
51
|
+
if(prefix_len) *prefix_len = key_index;
|
52
|
+
longest_match = current_node->middle;
|
53
|
+
}
|
42
54
|
current_node = current_node->left;
|
43
55
|
continue;
|
44
56
|
}
|
45
57
|
else
|
46
58
|
{
|
59
|
+
if(current_node->right && current_node->value == 0) {
|
60
|
+
if(prefix_len) *prefix_len = key_index;
|
61
|
+
longest_match = current_node->middle;
|
62
|
+
}
|
47
63
|
current_node = current_node->right;
|
48
64
|
continue;
|
49
65
|
}
|
50
66
|
}
|
51
67
|
|
52
|
-
|
53
|
-
return NULL;
|
68
|
+
return longest_match;
|
54
69
|
}
|
data/test/test_uriclassifier.rb
CHANGED
@@ -25,10 +25,12 @@ class URIClassifierTest < Test::Unit::TestCase
|
|
25
25
|
u = URIClassifier.new
|
26
26
|
u.register(prefix,1)
|
27
27
|
|
28
|
+
sn,pi,val = u.resolve(prefix)
|
28
29
|
sn,pi,val = u.resolve(test)
|
29
30
|
assert val != nil, "didn't resolve"
|
30
31
|
assert_equal prefix,sn, "wrong script name"
|
31
32
|
assert_equal test[sn.length .. -1],pi, "wrong path info"
|
33
|
+
|
32
34
|
end
|
33
35
|
|
34
36
|
def test_not_finding
|
@@ -99,6 +101,55 @@ class URIClassifierTest < Test::Unit::TestCase
|
|
99
101
|
puts "\nRESOLVE(#{count}): #{res}"
|
100
102
|
puts "REG_UNREG(#{count}): #{reg_unreg}"
|
101
103
|
end
|
102
|
-
|
104
|
+
|
105
|
+
|
106
|
+
def test_uri_branching
|
107
|
+
u = URIClassifier.new
|
108
|
+
u.register("/test", 1)
|
109
|
+
u.register("/test/this",2)
|
110
|
+
|
111
|
+
sn,pi,h = u.resolve("/test")
|
112
|
+
sn,pi,h = u.resolve("/test/that")
|
113
|
+
assert_equal "/test", sn, "failed to properly find script off branch portion of uri"
|
114
|
+
assert_equal "/that", pi, "didn't get the right patch info"
|
115
|
+
assert_equal 1, h, "wrong result for branching uri"
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
def test_all_prefixing
|
120
|
+
tests = ["/test","/test/that","/test/this"]
|
121
|
+
uri = "/test/this/that"
|
122
|
+
u = URIClassifier.new
|
123
|
+
|
124
|
+
cur = ""
|
125
|
+
uri.each_byte do |c|
|
126
|
+
cur << c.chr
|
127
|
+
u.register(cur, c)
|
128
|
+
end
|
129
|
+
|
130
|
+
# try to resolve everything with no asserts as a fuzzing
|
131
|
+
tests.each do |prefix|
|
132
|
+
cur = ""
|
133
|
+
prefix.each_byte do |c|
|
134
|
+
cur << c.chr
|
135
|
+
sn, pi, h = u.resolve(cur)
|
136
|
+
assert sn != nil, "didn't get a script name"
|
137
|
+
assert pi != nil, "didn't get path info"
|
138
|
+
assert h != nil, "didn't find the handler"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# assert that we find stuff
|
143
|
+
tests.each do |t|
|
144
|
+
sn, pi, h = u.resolve(t)
|
145
|
+
assert h != nil, "didn't find handler"
|
146
|
+
end
|
147
|
+
|
148
|
+
# assert we don't find stuff
|
149
|
+
sn, pi, h = u.resolve("chicken")
|
150
|
+
assert_nil h, "shoulnd't find anything"
|
151
|
+
assert_nil sn, "shoulnd't find anything"
|
152
|
+
assert_nil pi, "shoulnd't find anything"
|
153
|
+
end
|
103
154
|
end
|
104
155
|
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
|
|
3
3
|
specification_version: 1
|
4
4
|
name: mongrel
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.2.
|
7
|
-
date: 2006-
|
6
|
+
version: 0.2.1
|
7
|
+
date: 2006-02-02 00:00:00 -05:00
|
8
8
|
summary: An experimental fast simple web server for Ruby.
|
9
9
|
require_paths:
|
10
10
|
- lib
|