mongrel 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|