mongrel 1.0.5 → 1.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of mongrel might be problematic. Click here for more details.

data.tar.gz.sig CHANGED
Binary file
data/CHANGELOG CHANGED
@@ -1,6 +1,5 @@
1
- v1.0.5. Fix security flaw of DirHandler reported on mailing list.
2
1
 
3
- v1.0.4. Backport fixes for versioning inconsistency, mongrel_rails bug, and DirHandler bug.
2
+ v1.1. Pure Ruby URIClassifier. More modular architecture. JRuby support. Move C URIClassifier into mongrel_experimental project.
4
3
 
5
4
  v1.0.3. Fix user-switching bug; make people upgrade to the latest from the RC.
6
5
 
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  Mongrel Web Server (Mongrel) is copyrighted free software by Zed A. Shaw
2
- <zedshaw at zedshaw dot com> You can redistribute it and/or modify it under
3
- either the terms of the GPL or the conditions below:
2
+ <zedshaw at zedshaw dot com> and contributors. You can redistribute it
3
+ and/or modify it under either the terms of the GPL2 or the conditions below:
4
4
 
5
5
  1. You may make and give away verbatim copies of the source form of the
6
6
  software without restriction, provided that you duplicate all of the
data/Manifest CHANGED
@@ -22,33 +22,33 @@ ext/http11/http11_parser.h
22
22
  ext/http11/http11_parser.java.rl
23
23
  ext/http11/http11_parser.rl
24
24
  ext/http11/http11_parser_common.rl
25
- ext/http11/MANIFEST
26
- ext/http11/tst.h
27
- ext/http11/tst_cleanup.c
28
- ext/http11/tst_delete.c
29
- ext/http11/tst_grow_node_free_list.c
30
- ext/http11/tst_init.c
31
- ext/http11/tst_insert.c
32
- ext/http11/tst_search.c
25
+ ext/http11_java/Http11Service.java
26
+ ext/http11_java/org/jruby/mongrel/Http11.java
27
+ ext/http11_java/org/jruby/mongrel/Http11Parser.java
33
28
  lib/mongrel/camping.rb
34
29
  lib/mongrel/cgi.rb
35
30
  lib/mongrel/command.rb
36
31
  lib/mongrel/configurator.rb
32
+ lib/mongrel/const.rb
37
33
  lib/mongrel/debug.rb
34
+ lib/mongrel/gems.rb
38
35
  lib/mongrel/handlers.rb
36
+ lib/mongrel/header_out.rb
37
+ lib/mongrel/http_request.rb
38
+ lib/mongrel/http_response.rb
39
39
  lib/mongrel/init.rb
40
40
  lib/mongrel/mime_types.yml
41
41
  lib/mongrel/rails.rb
42
42
  lib/mongrel/stats.rb
43
43
  lib/mongrel/tcphack.rb
44
+ lib/mongrel/uri_classifier.rb
44
45
  lib/mongrel.rb
45
- lib/mutex_fix.rb
46
46
  LICENSE
47
47
  Manifest
48
48
  mongrel-public_cert.pem
49
+ mongrel.gemspec
49
50
  README
50
51
  setup.rb
51
- test/jruby_socket.rb
52
52
  test/mime.yaml
53
53
  test/mongrel.conf
54
54
  test/test_cgi_wrapper.rb
@@ -65,4 +65,5 @@ test/test_stats.rb
65
65
  test/test_uriclassifier.rb
66
66
  test/test_ws.rb
67
67
  test/testhelp.rb
68
+ TODO
68
69
  tools/trickletest.rb
data/README CHANGED
@@ -1,60 +1,53 @@
1
1
  = Mongrel: Simple Fast Mostly Ruby Web Server
2
2
 
3
- Mongrel is a small library that provides a very fast HTTP 1.1 server for Ruby
4
- web applications. It is not particular to any framework, and is intended to
5
- be just enough to get a web application running behind a more complete and robust
6
- web server.
3
+ Mongrel is a small library that provides a very fast HTTP 1.1 server for Ruby web applications. It is not particular to any framework, and is intended to be just enough to get a web application running behind a more complete and robust web server.
7
4
 
8
- What makes Mongrel so fast is the careful use of a C extension to provide fast
9
- HTTP 1.1 protocol parsing and fast URI lookup. This combination makes the server
10
- scream without too many portability issues.
5
+ What makes Mongrel so fast is the careful use of an Ragel extension to provide fast, accurate HTTP 1.1 protocol parsing. This makes the server scream without too many portability issues.
11
6
 
12
- You can view http://mongrel.rubyforge.org for more information.
7
+ See http://mongrel.rubyforge.org for more information.
8
+
9
+ == License
10
+
11
+ Mongrel is copyright 2007 Zed A. Shaw and contributors. It is licensed under the Ruby license and the GPL2. See the include LICENSE file for details.
13
12
 
14
13
  == Quick Start
15
14
 
16
- After you've installed (either with gem install mongrel or via source) you should
17
- have the mongrel_rails command available in your PATH. Then you just do the following:
15
+ The easiest way to get started with Mongrel is to install it via RubyGems and then run a Ruby on Rails application. You can do this easily:
18
16
 
19
- > cd myrailsapp
20
- > mongrel_rails start
17
+ $ gem install mongrel
21
18
 
22
- This will start it in the foreground so you can play with it. It runs your application
23
- in production mode. To get help do:
19
+ Now you should have the mongrel_rails command available in your PATH, so just do the following:
24
20
 
25
- > mongrel_rails start -h
21
+ $ cd myrailsapp
22
+ $ mongrel_rails start
26
23
 
27
- Finally, you can then start in background mode (probably won't work in win32):
24
+ This will start it in the foreground so you can play with it. It runs your application in production mode. To get help do:
28
25
 
29
- > mongrel_rails start -d
26
+ $ mongrel_rails start -h
30
27
 
31
- And you can stop it whenever you like with:
28
+ Finally, you can then start in background mode:
32
29
 
33
- > mongrel_rails stop
30
+ $ mongrel_rails start -d
31
+
32
+ And you can stop it whenever you like with:
34
33
 
35
- All of which should be done from your application's directory. It writes the
36
- PID of the process you ran into log/mongrel.pid.
34
+ $ mongrel_rails stop
37
35
 
38
- There are also many more new options for configuring the rails runner including
39
- changing to a different directory, adding more MIME types, and setting processor
40
- threads and timeouts.
36
+ All of which should be done from your application's directory. It writes the PID of the process you ran into log/mongrel.pid.
41
37
 
38
+ There are also many more new options for configuring the rails runner including changing to a different directory, adding more MIME types, and setting processor threads and timeouts.
42
39
 
43
40
  == Install
44
41
 
45
- It doesn't explicitly require Camping, but if you want to run the examples/camping/
46
- examples then you'll need to install Camping 1.2 at least (and redcloth I think).
47
- These are all available from RubyGems.
42
+ It doesn't explicitly require Camping, but if you want to run the examples/camping/ examples then you'll need to install Camping 1.2 at least (and redcloth I think). These are all available from RubyGems.
48
43
 
49
- The library consists of a C extension so you'll need a C compiler or at least a friend
50
- who can build it for you.
44
+ The library consists of a C extension so you'll need a C compiler or at least a friend who can build it for you.
51
45
 
52
46
  Finally, the source includes a setup.rb for those who hate RubyGems.
53
47
 
54
48
  == Usage
55
49
 
56
- The examples/simpletest.rb file has the following code as the simplest
57
- example:
50
+ The examples/simpletest.rb file has the following code as the simplest example:
58
51
 
59
52
  require 'mongrel'
60
53
 
@@ -72,15 +65,10 @@ example:
72
65
  h.register("/files", Mongrel::DirHandler.new("."))
73
66
  h.run.join
74
67
 
75
- If you run this and access port 3000 with a browser it will say
76
- "hello!". If you access it with any url other than "/test" it will
77
- give a simple 404. Check out the Mongrel::Error404Handler for a
78
- basic way to give a more complex 404 message.
68
+ If you run this and access port 3000 with a browser it will say "hello!". If you access it with any url other than "/test" it will give a simple 404. Check out the Mongrel::Error404Handler for a basic way to give a more complex 404 message.
79
69
 
80
- This also shows the DirHandler with directory listings. This is still
81
- rough but it should work for basic hosting. *File extension to mime
82
- type mapping is missing though.*
70
+ This also shows the DirHandler with directory listings. This is still rough but it should work for basic hosting. *File extension to mime type mapping is missing though.*
83
71
 
84
72
  == Contact
85
73
 
86
- E-mail zedshaw at zedshaw.com and I'll help. Comments about the API are welcome.
74
+ E-mail the Mongrel list at http://rubyforge.org/mailman/listinfo/mongrel-users and someone will help you. Comments about the API are welcome.
data/TODO ADDED
@@ -0,0 +1,5 @@
1
+
2
+ v1.2. Rewrite and merge mongrel cluster and mongrel_rails into something small and maintainable. Remove gem_plugin entirely.
3
+
4
+ v1.1.1. See if Java is setting the server version string in the request properly.
5
+
@@ -124,7 +124,7 @@ module Mongrel
124
124
  end
125
125
 
126
126
  config.run
127
- config.log "Mongrel available at #{@address}:#{@port}"
127
+ config.log "Mongrel #{Mongrel::Const::MONGREL_VERSION} available at #{@address}:#{@port}"
128
128
 
129
129
  if config.defaults[:daemon]
130
130
  config.write_pid_file
@@ -8,11 +8,9 @@
8
8
  #include <string.h>
9
9
  #include "http11_parser.h"
10
10
  #include <ctype.h>
11
- #include "tst.h"
12
11
 
13
12
  static VALUE mMongrel;
14
13
  static VALUE cHttpParser;
15
- static VALUE cURIClassifier;
16
14
  static VALUE eHttpParserError;
17
15
 
18
16
  #define id_handler_map rb_intern("@handler_map")
@@ -363,191 +361,6 @@ VALUE HttpParser_nread(VALUE self)
363
361
  return INT2FIX(http->nread);
364
362
  }
365
363
 
366
-
367
- void URIClassifier_free(void *data)
368
- {
369
- TRACE();
370
-
371
- if(data) {
372
- tst_cleanup((struct tst *)data);
373
- }
374
- }
375
-
376
-
377
-
378
- VALUE URIClassifier_alloc(VALUE klass)
379
- {
380
- VALUE obj;
381
- struct tst *tst = tst_init(TRIE_INCREASE);
382
- TRACE();
383
- assert(tst && "failed to initialize trie structure");
384
-
385
- obj = Data_Wrap_Struct(klass, NULL, URIClassifier_free, tst);
386
-
387
- return obj;
388
- }
389
-
390
- /**
391
- * call-seq:
392
- * URIClassifier.new -> URIClassifier
393
- *
394
- * Initializes a new URIClassifier object that you can use to associate URI sequences
395
- * with objects. You can actually use it with any string sequence and any objects,
396
- * but it's mostly used with URIs.
397
- *
398
- * It uses TST from http://www.octavian.org/cs/software.html to build an ternary search
399
- * trie to hold all of the URIs. It uses this to do an initial search for the a URI
400
- * prefix, and then to break the URI into SCRIPT_NAME and PATH_INFO portions. It actually
401
- * will do two searches most of the time in order to find the right handler for the
402
- * registered prefix portion.
403
- *
404
- */
405
- VALUE URIClassifier_init(VALUE self)
406
- {
407
- VALUE hash;
408
-
409
- /* we create an internal hash to protect stuff from the GC */
410
- hash = rb_hash_new();
411
- rb_ivar_set(self, id_handler_map, hash);
412
-
413
- return self;
414
- }
415
-
416
-
417
- /**
418
- * call-seq:
419
- * uc.register("/someuri", SampleHandler.new) -> nil
420
- *
421
- * Registers the SampleHandler (one for all requests) with the "/someuri".
422
- * When URIClassifier::resolve is called with "/someuri" it'll return
423
- * SampleHandler immediately. When called with "/someuri/iwant" it'll also
424
- * return SomeHandler immediatly, with no additional searches, but it will
425
- * return path info with "/iwant".
426
- *
427
- * You actually can reuse this class to register nearly anything and
428
- * quickly resolve it. This could be used for caching, fast mapping, etc.
429
- * The downside is it uses much more memory than a Hash, but it can be
430
- * a lot faster. It's main advantage is that it works on prefixes, which
431
- * is damn hard to get right with a Hash.
432
- */
433
- VALUE URIClassifier_register(VALUE self, VALUE uri, VALUE handler)
434
- {
435
- int rc = 0;
436
- void *ptr = NULL;
437
- struct tst *tst = NULL;
438
- DATA_GET(self, struct tst, tst);
439
-
440
- rc = tst_insert((unsigned char *)StringValueCStr(uri), (void *)handler , tst, 0, &ptr);
441
-
442
- if(rc == TST_DUPLICATE_KEY) {
443
- rb_raise(rb_eStandardError, "Handler already registered with that name");
444
- } else if(rc == TST_ERROR) {
445
- rb_raise(rb_eStandardError, "Memory error registering handler");
446
- } else if(rc == TST_NULL_KEY) {
447
- rb_raise(rb_eStandardError, "URI was empty");
448
- }
449
-
450
- rb_hash_aset(rb_ivar_get(self, id_handler_map), uri, handler);
451
-
452
- return Qnil;
453
- }
454
-
455
-
456
- /**
457
- * call-seq:
458
- * uc.unregister("/someuri")
459
- *
460
- * Yep, just removes this uri and it's handler from the trie.
461
- */
462
- VALUE URIClassifier_unregister(VALUE self, VALUE uri)
463
- {
464
- void *handler = NULL;
465
- struct tst *tst = NULL;
466
- DATA_GET(self, struct tst, tst);
467
-
468
- handler = tst_delete((unsigned char *)StringValueCStr(uri), tst);
469
-
470
- if(handler) {
471
- rb_hash_delete(rb_ivar_get(self, id_handler_map), uri);
472
-
473
- return (VALUE)handler;
474
- } else {
475
- return Qnil;
476
- }
477
- }
478
-
479
-
480
- /**
481
- * call-seq:
482
- * uc.resolve("/someuri") -> "/someuri", "", handler
483
- * uc.resolve("/someuri/pathinfo") -> "/someuri", "/pathinfo", handler
484
- * uc.resolve("/notfound/orhere") -> nil, nil, nil
485
- * uc.resolve("/") -> "/", "/", handler # if uc.register("/", handler)
486
- * uc.resolve("/path/from/root") -> "/", "/path/from/root", handler # if uc.register("/", handler)
487
- *
488
- * Attempts to resolve either the whole URI or at the longest prefix, returning
489
- * the prefix (as script_info), path (as path_info), and registered handler
490
- * (usually an HttpHandler). If it doesn't find a handler registered at the longest
491
- * match then it returns nil,nil,nil.
492
- *
493
- * Because the resolver uses a trie you are able to register a handler at *any* character
494
- * in the URI and it will be handled as long as it's the longest prefix. So, if you
495
- * registered handler #1 at "/something/lik", and #2 at "/something/like/that", then a
496
- * a search for "/something/like" would give you #1. A search for "/something/like/that/too"
497
- * would give you #2.
498
- *
499
- * This is very powerful since it means you can also attach handlers to parts of the ;
500
- * (semi-colon) separated path params, any part of the path, use off chars, anything really.
501
- * It also means that it's very efficient to do this only taking as long as the URI has
502
- * characters.
503
- *
504
- * A slight modification to the CGI 1.2 standard is given for handlers registered to "/".
505
- * CGI expects all CGI scripts to be at some script path, so it doesn't really say anything
506
- * about a script that handles the root. To make this work, the resolver will detect that
507
- * the requested handler is at "/", and return that for script_name, and then simply return
508
- * the full URI back as path_info.
509
- *
510
- * It expects strings with no embedded '\0' characters. Don't try other string-like stuff yet.
511
- */
512
- VALUE URIClassifier_resolve(VALUE self, VALUE uri)
513
- {
514
- void *handler = NULL;
515
- int pref_len = 0;
516
- struct tst *tst = NULL;
517
- VALUE result;
518
- unsigned char *uri_str = NULL;
519
-
520
- DATA_GET(self, struct tst, tst);
521
- uri_str = (unsigned char *)StringValueCStr(uri);
522
-
523
- handler = tst_search(uri_str, tst, TST_LONGEST_MATCH, &pref_len);
524
-
525
- /* setup for multiple return values */
526
- result = rb_ary_new();
527
-
528
- if(handler) {
529
- rb_ary_push(result, rb_str_substr (uri, 0, pref_len));
530
- /* compensate for a script_name="/" where we need to add the "/" to path_info to keep it consistent */
531
- if(pref_len == 1 && uri_str[0] == '/') {
532
- /* matches the root URI so we have to use the whole URI as the path_info */
533
- rb_ary_push(result, uri);
534
- } else {
535
- /* matches a script so process like normal */
536
- rb_ary_push(result, rb_str_substr(uri, pref_len, RSTRING(uri)->len));
537
- }
538
-
539
- rb_ary_push(result, (VALUE)handler);
540
- } else {
541
- /* not found so push back nothing */
542
- rb_ary_push(result, Qnil);
543
- rb_ary_push(result, Qnil);
544
- rb_ary_push(result, Qnil);
545
- }
546
-
547
- return result;
548
- }
549
-
550
-
551
364
  void Init_http11()
552
365
  {
553
366
 
@@ -571,7 +384,7 @@ void Init_http11()
571
384
  DEF_GLOBAL(server_protocol, "SERVER_PROTOCOL");
572
385
  DEF_GLOBAL(server_protocol_value, "HTTP/1.1");
573
386
  DEF_GLOBAL(http_host, "HTTP_HOST");
574
- DEF_GLOBAL(mongrel_version, "Mongrel 1.0.5");
387
+ DEF_GLOBAL(mongrel_version, "Mongrel 1.1");
575
388
  DEF_GLOBAL(server_software, "SERVER_SOFTWARE");
576
389
  DEF_GLOBAL(port_80, "80");
577
390
 
@@ -586,11 +399,4 @@ void Init_http11()
586
399
  rb_define_method(cHttpParser, "error?", HttpParser_has_error,0);
587
400
  rb_define_method(cHttpParser, "finished?", HttpParser_is_finished,0);
588
401
  rb_define_method(cHttpParser, "nread", HttpParser_nread,0);
589
-
590
- cURIClassifier = rb_define_class_under(mMongrel, "URIClassifier", rb_cObject);
591
- rb_define_alloc_func(cURIClassifier, URIClassifier_alloc);
592
- rb_define_method(cURIClassifier, "initialize", URIClassifier_init, 0);
593
- rb_define_method(cURIClassifier, "register", URIClassifier_register, 2);
594
- rb_define_method(cURIClassifier, "unregister", URIClassifier_unregister, 1);
595
- rb_define_method(cURIClassifier, "resolve", URIClassifier_resolve, 1);
596
402
  }
@@ -0,0 +1,13 @@
1
+ import java.io.IOException;
2
+
3
+ import org.jruby.Ruby;
4
+ import org.jruby.runtime.load.BasicLibraryService;
5
+
6
+ import org.jruby.mongrel.Http11;
7
+
8
+ public class Http11Service implements BasicLibraryService {
9
+ public boolean basicLoad(final Ruby runtime) throws IOException {
10
+ Http11.createHttp11(runtime);
11
+ return true;
12
+ }
13
+ }
@@ -0,0 +1,266 @@
1
+ /***** BEGIN LICENSE BLOCK *****
2
+ * Version: CPL 1.0/GPL 2.0/LGPL 2.1
3
+ *
4
+ * The contents of this file are subject to the Common Public
5
+ * License Version 1.0 (the "License"); you may not use this file
6
+ * except in compliance with the License. You may obtain a copy of
7
+ * the License at http://www.eclipse.org/legal/cpl-v10.html
8
+ *
9
+ * Software distributed under the License is distributed on an "AS
10
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11
+ * implied. See the License for the specific language governing
12
+ * rights and limitations under the License.
13
+ *
14
+ * Copyright (C) 2007 Ola Bini <ola@ologix.com>
15
+ *
16
+ * Alternatively, the contents of this file may be used under the terms of
17
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
18
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
19
+ * in which case the provisions of the GPL or the LGPL are applicable instead
20
+ * of those above. If you wish to allow use of your version of this file only
21
+ * under the terms of either the GPL or the LGPL, and not to allow others to
22
+ * use your version of this file under the terms of the CPL, indicate your
23
+ * decision by deleting the provisions above and replace them with the notice
24
+ * and other provisions required by the GPL or the LGPL. If you do not delete
25
+ * the provisions above, a recipient may use your version of this file under
26
+ * the terms of any one of the CPL, the GPL or the LGPL.
27
+ ***** END LICENSE BLOCK *****/
28
+ package org.jruby.mongrel;
29
+
30
+ import org.jruby.Ruby;
31
+ import org.jruby.RubyClass;
32
+ import org.jruby.RubyHash;
33
+ import org.jruby.RubyModule;
34
+ import org.jruby.RubyNumeric;
35
+ import org.jruby.RubyObject;
36
+ import org.jruby.RubyString;
37
+
38
+ import org.jruby.runtime.CallbackFactory;
39
+ import org.jruby.runtime.ObjectAllocator;
40
+ import org.jruby.runtime.builtin.IRubyObject;
41
+
42
+ import org.jruby.exceptions.RaiseException;
43
+
44
+ import org.jruby.util.ByteList;
45
+
46
+ /**
47
+ * @author <a href="mailto:ola.bini@ki.se">Ola Bini</a>
48
+ */
49
+ public class Http11 extends RubyObject {
50
+ public final static int MAX_FIELD_NAME_LENGTH = 256;
51
+ public final static String MAX_FIELD_NAME_LENGTH_ERR = "HTTP element FIELD_NAME is longer than the 256 allowed length.";
52
+ public final static int MAX_FIELD_VALUE_LENGTH = 80 * 1024;
53
+ public final static String MAX_FIELD_VALUE_LENGTH_ERR = "HTTP element FIELD_VALUE is longer than the 81920 allowed length.";
54
+ public final static int MAX_REQUEST_URI_LENGTH = 1024 * 12;
55
+ public final static String MAX_REQUEST_URI_LENGTH_ERR = "HTTP element REQUEST_URI is longer than the 12288 allowed length.";
56
+ public final static int MAX_FRAGMENT_LENGTH = 1024;
57
+ public final static String MAX_FRAGMENT_LENGTH_ERR = "HTTP element REQUEST_PATH is longer than the 1024 allowed length.";
58
+ public final static int MAX_REQUEST_PATH_LENGTH = 1024;
59
+ public final static String MAX_REQUEST_PATH_LENGTH_ERR = "HTTP element REQUEST_PATH is longer than the 1024 allowed length.";
60
+ public final static int MAX_QUERY_STRING_LENGTH = 1024 * 10;
61
+ public final static String MAX_QUERY_STRING_LENGTH_ERR = "HTTP element QUERY_STRING is longer than the 10240 allowed length.";
62
+ public final static int MAX_HEADER_LENGTH = 1024 * (80 + 32);
63
+ public final static String MAX_HEADER_LENGTH_ERR = "HTTP element HEADER is longer than the 114688 allowed length.";
64
+
65
+
66
+ private static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
67
+ public IRubyObject allocate(Ruby runtime, RubyClass klass) {
68
+ return new Http11(runtime, klass);
69
+ }
70
+ };
71
+
72
+ public static void createHttp11(Ruby runtime) {
73
+ RubyModule mMongrel = runtime.defineModule("Mongrel");
74
+ mMongrel.defineClassUnder("HttpParserError",runtime.getClass("IOError"),runtime.getClass("IOError").getAllocator());
75
+
76
+ CallbackFactory cf = runtime.callbackFactory(Http11.class);
77
+
78
+ RubyClass cHttpParser = mMongrel.defineClassUnder("HttpParser",runtime.getObject(),ALLOCATOR);
79
+ cHttpParser.defineFastMethod("initialize",cf.getFastMethod("initialize"));
80
+ cHttpParser.defineFastMethod("reset",cf.getFastMethod("reset"));
81
+ cHttpParser.defineFastMethod("finish",cf.getFastMethod("finish"));
82
+ cHttpParser.defineFastMethod("execute",cf.getFastMethod("execute", IRubyObject.class, IRubyObject.class, IRubyObject.class));
83
+ cHttpParser.defineFastMethod("error?",cf.getFastMethod("has_error"));
84
+ cHttpParser.defineFastMethod("finished?",cf.getFastMethod("is_finished"));
85
+ cHttpParser.defineFastMethod("nread",cf.getFastMethod("nread"));
86
+ }
87
+
88
+ private Ruby runtime;
89
+ private RubyClass eHttpParserError;
90
+ private Http11Parser hp;
91
+
92
+ public Http11(Ruby runtime, RubyClass clazz) {
93
+ super(runtime,clazz);
94
+ this.runtime = runtime;
95
+ this.eHttpParserError = (RubyClass)runtime.getModule("Mongrel").getConstant("HttpParserError");
96
+ this.hp = new Http11Parser();
97
+ this.hp.parser.http_field = http_field;
98
+ this.hp.parser.request_method = request_method;
99
+ this.hp.parser.request_uri = request_uri;
100
+ this.hp.parser.fragment = fragment;
101
+ this.hp.parser.request_path = request_path;
102
+ this.hp.parser.query_string = query_string;
103
+ this.hp.parser.http_version = http_version;
104
+ this.hp.parser.header_done = header_done;
105
+ this.hp.parser.init();
106
+ }
107
+
108
+ public void validateMaxLength(int len, int max, String msg) {
109
+ if(len>max) {
110
+ throw new RaiseException(runtime, eHttpParserError, msg, true);
111
+ }
112
+ }
113
+
114
+ private Http11Parser.FieldCB http_field = new Http11Parser.FieldCB() {
115
+ public void call(Object data, int field, int flen, int value, int vlen) {
116
+ RubyHash req = (RubyHash)data;
117
+ RubyString v,f;
118
+ validateMaxLength(flen, MAX_FIELD_NAME_LENGTH, MAX_FIELD_NAME_LENGTH_ERR);
119
+ validateMaxLength(vlen, MAX_FIELD_VALUE_LENGTH, MAX_FIELD_VALUE_LENGTH_ERR);
120
+
121
+ v = RubyString.newString(runtime, new ByteList(Http11.this.hp.parser.buffer,value,vlen));
122
+ f = RubyString.newString(runtime, "HTTP_");
123
+ ByteList b = new ByteList(Http11.this.hp.parser.buffer,field,flen);
124
+ for(int i=0,j=b.realSize;i<j;i++) {
125
+ if((b.bytes[i]&0xFF) == '-') {
126
+ b.bytes[i] = (byte)'_';
127
+ } else {
128
+ b.bytes[i] = (byte)Character.toUpperCase((char)b.bytes[i]);
129
+ }
130
+ }
131
+ f.cat(b);
132
+ req.aset(f,v);
133
+ }
134
+ };
135
+
136
+ private Http11Parser.ElementCB request_method = new Http11Parser.ElementCB() {
137
+ public void call(Object data, int at, int length) {
138
+ RubyHash req = (RubyHash)data;
139
+ RubyString val = RubyString.newString(runtime,new ByteList(hp.parser.buffer,at,length));
140
+ req.aset(runtime.newString("REQUEST_METHOD"),val);
141
+ }
142
+ };
143
+
144
+ private Http11Parser.ElementCB request_uri = new Http11Parser.ElementCB() {
145
+ public void call(Object data, int at, int length) {
146
+ RubyHash req = (RubyHash)data;
147
+ validateMaxLength(length, MAX_REQUEST_URI_LENGTH, MAX_REQUEST_URI_LENGTH_ERR);
148
+ RubyString val = RubyString.newString(runtime,new ByteList(hp.parser.buffer,at,length));
149
+ req.aset(runtime.newString("REQUEST_URI"),val);
150
+ }
151
+ };
152
+
153
+ private Http11Parser.ElementCB fragment = new Http11Parser.ElementCB() {
154
+ public void call(Object data, int at, int length) {
155
+ RubyHash req = (RubyHash)data;
156
+ validateMaxLength(length, MAX_FRAGMENT_LENGTH, MAX_FRAGMENT_LENGTH_ERR);
157
+ RubyString val = RubyString.newString(runtime,new ByteList(hp.parser.buffer,at,length));
158
+ req.aset(runtime.newString("FRAGMENT"),val);
159
+ }
160
+ };
161
+
162
+ private Http11Parser.ElementCB request_path = new Http11Parser.ElementCB() {
163
+ public void call(Object data, int at, int length) {
164
+ RubyHash req = (RubyHash)data;
165
+ validateMaxLength(length, MAX_REQUEST_PATH_LENGTH, MAX_REQUEST_PATH_LENGTH_ERR);
166
+ RubyString val = RubyString.newString(runtime,new ByteList(hp.parser.buffer,at,length));
167
+ req.aset(runtime.newString("REQUEST_PATH"),val);
168
+ }
169
+ };
170
+
171
+ private Http11Parser.ElementCB query_string = new Http11Parser.ElementCB() {
172
+ public void call(Object data, int at, int length) {
173
+ RubyHash req = (RubyHash)data;
174
+ validateMaxLength(length, MAX_QUERY_STRING_LENGTH, MAX_QUERY_STRING_LENGTH_ERR);
175
+ RubyString val = RubyString.newString(runtime,new ByteList(hp.parser.buffer,at,length));
176
+ req.aset(runtime.newString("QUERY_STRING"),val);
177
+ }
178
+ };
179
+
180
+ private Http11Parser.ElementCB http_version = new Http11Parser.ElementCB() {
181
+ public void call(Object data, int at, int length) {
182
+ RubyHash req = (RubyHash)data;
183
+ RubyString val = RubyString.newString(runtime,new ByteList(hp.parser.buffer,at,length));
184
+ req.aset(runtime.newString("HTTP_VERSION"),val);
185
+ }
186
+ };
187
+
188
+ private Http11Parser.ElementCB header_done = new Http11Parser.ElementCB() {
189
+ public void call(Object data, int at, int length) {
190
+ RubyHash req = (RubyHash)data;
191
+ IRubyObject temp,ctype,clen;
192
+
193
+ clen = req.aref(runtime.newString("HTTP_CONTENT_LENGTH"));
194
+ if(!clen.isNil()) {
195
+ req.aset(runtime.newString("CONTENT_LENGTH"),clen);
196
+ }
197
+
198
+ ctype = req.aref(runtime.newString("HTTP_CONTENT_TYPE"));
199
+ if(!ctype.isNil()) {
200
+ req.aset(runtime.newString("CONTENT_TYPE"),ctype);
201
+ }
202
+
203
+ req.aset(runtime.newString("GATEWAY_INTERFACE"),runtime.newString("CGI/1.2"));
204
+ if(!(temp = req.aref(runtime.newString("HTTP_HOST"))).isNil()) {
205
+ String s = temp.toString();
206
+ int colon = s.indexOf(':');
207
+ if(colon != -1) {
208
+ req.aset(runtime.newString("SERVER_NAME"),runtime.newString(s.substring(0,colon)));
209
+ req.aset(runtime.newString("SERVER_PORT"),runtime.newString(s.substring(colon+1)));
210
+ } else {
211
+ req.aset(runtime.newString("SERVER_NAME"),temp);
212
+ req.aset(runtime.newString("SERVER_PORT"),runtime.newString("80"));
213
+ }
214
+ }
215
+
216
+ req.setInstanceVariable("@http_body", RubyString.newString(runtime, new ByteList(hp.parser.buffer, at, length)));
217
+ req.aset(runtime.newString("SERVER_PROTOCOL"),runtime.newString("HTTP/1.1"));
218
+ req.aset(runtime.newString("SERVER_SOFTWARE"),runtime.newString("Mongrel 1.0.1"));
219
+ }
220
+ };
221
+
222
+ public IRubyObject initialize() {
223
+ this.hp.parser.init();
224
+ return this;
225
+ }
226
+
227
+ public IRubyObject reset() {
228
+ this.hp.parser.init();
229
+ return runtime.getNil();
230
+ }
231
+
232
+ public IRubyObject finish() {
233
+ this.hp.finish();
234
+ return this.hp.is_finished() ? runtime.getTrue() : runtime.getFalse();
235
+ }
236
+
237
+ public IRubyObject execute(IRubyObject req_hash, IRubyObject data, IRubyObject start) {
238
+ int from = 0;
239
+ from = RubyNumeric.fix2int(start);
240
+ ByteList d = ((RubyString)data).getByteList();
241
+ if(from >= d.realSize) {
242
+ throw new RaiseException(runtime, eHttpParserError, "Requested start is after data buffer end.", true);
243
+ } else {
244
+ this.hp.parser.data = req_hash;
245
+ this.hp.execute(d,from);
246
+ validateMaxLength(this.hp.parser.nread,MAX_HEADER_LENGTH, MAX_HEADER_LENGTH_ERR);
247
+ if(this.hp.has_error()) {
248
+ throw new RaiseException(runtime, eHttpParserError, "Invalid HTTP format, parsing fails.", true);
249
+ } else {
250
+ return runtime.newFixnum(this.hp.parser.nread);
251
+ }
252
+ }
253
+ }
254
+
255
+ public IRubyObject has_error() {
256
+ return this.hp.has_error() ? runtime.getTrue() : runtime.getFalse();
257
+ }
258
+
259
+ public IRubyObject is_finished() {
260
+ return this.hp.is_finished() ? runtime.getTrue() : runtime.getFalse();
261
+ }
262
+
263
+ public IRubyObject nread() {
264
+ return runtime.newFixnum(this.hp.parser.nread);
265
+ }
266
+ }// Http11