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 CHANGED
@@ -11,7 +11,7 @@ scream without too many portability issues.
11
11
 
12
12
  == Status
13
13
 
14
- The 0.2.0 release of Mongrel features an HTTP core server that is the fastest possible
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.0 release probably consists of the most effort I've ever put into
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.0", "Zed A. Shaw", summary, [], test_file)
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&#8217;s how it all works. Let&#8217;s say you register
143
- &quot;/blog&quot; with a BlogHandler. Great. Now, someone goes to
144
- &quot;/blog/zedsucks/ass&quot;. You want SCRIPT_NAME to be
145
- &quot;/blog&quot; and PATH_INFO to be &quot;/zedsucks/ass&quot;. <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
- &quot;/blog&quot; part. So, that&#8217;s the SCRIPT_NAME. It then tries a
149
- second search for just &quot;/blog&quot;. If that comes back good then it
150
- sets the rest (&quot;/zedsucks/ass&quot;) 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&#8217;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 &quot;/blog/zed&quot; then the above URI will
161
- give SCRIPT_NAME=&quot;/blog/zed&quot;, PATH_INFO=&quot;sucks/ass&quot;.
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") &rarr; 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&#8217;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&#8217;s the longest prefix. So, if you registered handler 1 at
200
+ &quot;/something/lik&quot;, and 2 at &quot;/something/like/that&quot;, then
201
+ a a search for &quot;/something/like&quot; would give you 1. A search for
202
+ &quot;/something/like/that/too&quot; 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&#8217;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&#8216;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 &quot;/blog&quot; with a BlogHandler. Great.
28
- * Now, someone goes to &quot;/blog/zedsucks/ass&quot;. You want SCRIPT_NAME to be &quot;/blog&quot; and
29
- * PATH_INFO to be &quot;/zedsucks/ass&quot;. URIClassifier first does a TST search and comes
30
- * up with a failure, but knows that the failure ended at the &quot;/blog&quot; part. So, that's
31
- * the SCRIPT_NAME. It then tries a second search for just &quot;/blog&quot;. If that comes back
32
- * good then it sets the rest (&quot;/zedsucks/ass&quot;) 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 &quot;/blog/zed&quot; then the above URI will give SCRIPT_NAME=&quot;/blog/zed&quot;,
39
- * PATH_INFO=&quot;sucks/ass&quot;. 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 &quot;/something/lik&quot;, and #2 at &quot;/something/like/that&quot;, then a
27
+ * a search for &quot;/something/like&quot; would give you #1. A search for &quot;/something/like/that/too&quot;
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
- if(handler == NULL) {
46
- script_name = rb_str_substr (uri, 0, pref_len);
47
- script_name_str = (unsigned char *)StringValueCStr(script_name);
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)-&gt;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)-&gt;len));
57
+ rb_ary_push(result, (VALUE)handler);
61
58
  } else {
62
- // whole thing was found, so uri is the script name, path info empty
63
- script_name = uri;
64
- path_info = rb_str_new2(&quot;&quot;);
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>
@@ -1 +1 @@
1
- Tue Jan 31 00:48:28 EST 2006
1
+ Thu Feb 02 01:57:10 EST 2006
@@ -56,7 +56,7 @@
56
56
  </tr>
57
57
  <tr class="top-aligned-row">
58
58
  <td><strong>Last Update:</strong></td>
59
- <td>Tue Jan 31 00:44:18 EST 2006</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.0 release of <a href="../classes/Mongrel.html">Mongrel</a> features
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.0 release probably consists of the most effort I&#8217;ve ever put
157
+ The 0.2.1 release probably consists of the most effort I&#8217;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&#8217;ve tried about seven different
@@ -56,7 +56,7 @@
56
56
  </tr>
57
57
  <tr class="top-aligned-row">
58
58
  <td><strong>Last Update:</strong></td>
59
- <td>Mon Jan 30 23:59:49 EST 2006</td>
59
+ <td>Thu Feb 02 00:12:35 EST 2006</td>
60
60
  </tr>
61
61
  </table>
62
62
  </div>
@@ -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
- rb_str_buf_cat(f, field, flen);
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
- VALUE id = rb_str_new2("REQUEST_METHOD");
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
- VALUE id = rb_str_new2("PATH_INFO");
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
- VALUE id = rb_str_new2("QUERY_STRING");
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
- VALUE id = rb_str_new2("HTTP_VERSION");
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
- if(handler == NULL) {
384
- script_name = rb_str_substr (uri, 0, pref_len);
385
- script_name_str = (unsigned char *)StringValueCStr(script_name);
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
- // whole thing was found, so uri is the script name, path info empty
401
- script_name = uri;
402
- path_info = rb_str_new2("");
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);
@@ -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
- if(prefix_len) *prefix_len = key_index;
53
- return NULL;
68
+ return longest_match;
54
69
  }
@@ -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.0
7
- date: 2006-01-31 00:00:00 -05:00
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