puma 0.8.0

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

Potentially problematic release.


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

Files changed (59) hide show
  1. data/.gemtest +0 -0
  2. data/COPYING +55 -0
  3. data/History.txt +69 -0
  4. data/LICENSE +26 -0
  5. data/Manifest.txt +57 -0
  6. data/README.md +60 -0
  7. data/Rakefile +10 -0
  8. data/TODO +5 -0
  9. data/bin/puma +15 -0
  10. data/examples/builder.rb +29 -0
  11. data/examples/camping/README +3 -0
  12. data/examples/camping/blog.rb +294 -0
  13. data/examples/camping/tepee.rb +149 -0
  14. data/examples/httpd.conf +474 -0
  15. data/examples/mime.yaml +3 -0
  16. data/examples/mongrel.conf +9 -0
  17. data/examples/monitrc +57 -0
  18. data/examples/random_thrash.rb +19 -0
  19. data/examples/simpletest.rb +52 -0
  20. data/examples/webrick_compare.rb +20 -0
  21. data/ext/puma_http11/Http11Service.java +13 -0
  22. data/ext/puma_http11/ext_help.h +15 -0
  23. data/ext/puma_http11/extconf.rb +5 -0
  24. data/ext/puma_http11/http11_parser.c +1225 -0
  25. data/ext/puma_http11/http11_parser.h +63 -0
  26. data/ext/puma_http11/http11_parser.java.rl +159 -0
  27. data/ext/puma_http11/http11_parser.rl +146 -0
  28. data/ext/puma_http11/http11_parser_common.rl +54 -0
  29. data/ext/puma_http11/org/jruby/mongrel/Http11.java +241 -0
  30. data/ext/puma_http11/org/jruby/mongrel/Http11Parser.java +486 -0
  31. data/ext/puma_http11/puma_http11.c +482 -0
  32. data/lib/puma.rb +18 -0
  33. data/lib/puma/cli.rb +131 -0
  34. data/lib/puma/const.rb +132 -0
  35. data/lib/puma/events.rb +36 -0
  36. data/lib/puma/gems.rb +20 -0
  37. data/lib/puma/mime_types.yml +616 -0
  38. data/lib/puma/server.rb +419 -0
  39. data/lib/puma/thread_pool.rb +95 -0
  40. data/lib/puma/utils.rb +44 -0
  41. data/lib/rack/handler/puma.rb +33 -0
  42. data/puma.gemspec +37 -0
  43. data/tasks/gem.rake +22 -0
  44. data/tasks/java.rake +12 -0
  45. data/tasks/native.rake +25 -0
  46. data/tasks/ragel.rake +20 -0
  47. data/test/lobster.ru +4 -0
  48. data/test/mime.yaml +3 -0
  49. data/test/test_http10.rb +27 -0
  50. data/test/test_http11.rb +151 -0
  51. data/test/test_persistent.rb +159 -0
  52. data/test/test_rack_handler.rb +10 -0
  53. data/test/test_rack_server.rb +107 -0
  54. data/test/test_thread_pool.rb +102 -0
  55. data/test/test_unix_socket.rb +34 -0
  56. data/test/test_ws.rb +97 -0
  57. data/test/testhelp.rb +41 -0
  58. data/tools/trickletest.rb +45 -0
  59. metadata +165 -0
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Copyright (c) 2005 Zed A. Shaw
3
+ * You can redistribute it and/or modify it under the same terms as Ruby.
4
+ */
5
+
6
+ #ifndef http11_parser_h
7
+ #define http11_parser_h
8
+
9
+ #include "ruby.h"
10
+
11
+ #include <sys/types.h>
12
+
13
+ #if defined(_WIN32)
14
+ #include <stddef.h>
15
+ #endif
16
+
17
+ #define BUFFER_LEN 1024
18
+
19
+ struct http_parser;
20
+
21
+ typedef void (*element_cb)(struct http_parser* hp,
22
+ const char *at, size_t length);
23
+
24
+ typedef void (*field_cb)(struct http_parser* hp,
25
+ const char *field, size_t flen,
26
+ const char *value, size_t vlen);
27
+
28
+ typedef struct http_parser {
29
+ int cs;
30
+ size_t body_start;
31
+ int content_len;
32
+ size_t nread;
33
+ size_t mark;
34
+ size_t field_start;
35
+ size_t field_len;
36
+ size_t query_start;
37
+
38
+ VALUE request;
39
+ VALUE body;
40
+
41
+ field_cb http_field;
42
+ element_cb request_method;
43
+ element_cb request_uri;
44
+ element_cb fragment;
45
+ element_cb request_path;
46
+ element_cb query_string;
47
+ element_cb http_version;
48
+ element_cb header_done;
49
+
50
+ char buf[BUFFER_LEN];
51
+
52
+ } http_parser;
53
+
54
+ int http_parser_init(http_parser *parser);
55
+ int http_parser_finish(http_parser *parser);
56
+ size_t http_parser_execute(http_parser *parser, const char *data,
57
+ size_t len, size_t off);
58
+ int http_parser_has_error(http_parser *parser);
59
+ int http_parser_is_finished(http_parser *parser);
60
+
61
+ #define http_parser_nread(parser) (parser)->nread
62
+
63
+ #endif
@@ -0,0 +1,159 @@
1
+ package org.jruby.mongrel;
2
+
3
+ import org.jruby.util.ByteList;
4
+
5
+ public class Http11Parser {
6
+
7
+ /** Machine **/
8
+
9
+ %%{
10
+
11
+ machine http_parser;
12
+
13
+ action mark {parser.mark = fpc; }
14
+
15
+ action start_field { parser.field_start = fpc; }
16
+ action snake_upcase_field { /* FIXME stub */ }
17
+ action write_field {
18
+ parser.field_len = fpc-parser.field_start;
19
+ }
20
+
21
+ action start_value { parser.mark = fpc; }
22
+ action write_value {
23
+ if(parser.http_field != null) {
24
+ parser.http_field.call(parser.data, parser.field_start, parser.field_len, parser.mark, fpc-parser.mark);
25
+ }
26
+ }
27
+ action request_method {
28
+ if(parser.request_method != null)
29
+ parser.request_method.call(parser.data, parser.mark, fpc-parser.mark);
30
+ }
31
+ action request_uri {
32
+ if(parser.request_uri != null)
33
+ parser.request_uri.call(parser.data, parser.mark, fpc-parser.mark);
34
+ }
35
+ action fragment {
36
+ if(parser.fragment != null)
37
+ parser.fragment.call(parser.data, parser.mark, fpc-parser.mark);
38
+ }
39
+
40
+ action start_query {parser.query_start = fpc; }
41
+ action query_string {
42
+ if(parser.query_string != null)
43
+ parser.query_string.call(parser.data, parser.query_start, fpc-parser.query_start);
44
+ }
45
+
46
+ action http_version {
47
+ if(parser.http_version != null)
48
+ parser.http_version.call(parser.data, parser.mark, fpc-parser.mark);
49
+ }
50
+
51
+ action request_path {
52
+ if(parser.request_path != null)
53
+ parser.request_path.call(parser.data, parser.mark, fpc-parser.mark);
54
+ }
55
+
56
+ action done {
57
+ parser.body_start = fpc + 1;
58
+ if(parser.header_done != null)
59
+ parser.header_done.call(parser.data, fpc + 1, pe - fpc - 1);
60
+ fbreak;
61
+ }
62
+
63
+ include http_parser_common "http11_parser_common.rl";
64
+
65
+ }%%
66
+
67
+ /** Data **/
68
+ %% write data;
69
+
70
+ public static interface ElementCB {
71
+ public void call(Object data, int at, int length);
72
+ }
73
+
74
+ public static interface FieldCB {
75
+ public void call(Object data, int field, int flen, int value, int vlen);
76
+ }
77
+
78
+ public static class HttpParser {
79
+ int cs;
80
+ int body_start;
81
+ int content_len;
82
+ int nread;
83
+ int mark;
84
+ int field_start;
85
+ int field_len;
86
+ int query_start;
87
+
88
+ Object data;
89
+ ByteList buffer;
90
+
91
+ public FieldCB http_field;
92
+ public ElementCB request_method;
93
+ public ElementCB request_uri;
94
+ public ElementCB fragment;
95
+ public ElementCB request_path;
96
+ public ElementCB query_string;
97
+ public ElementCB http_version;
98
+ public ElementCB header_done;
99
+
100
+ public void init() {
101
+ cs = 0;
102
+
103
+ %% write init;
104
+
105
+ body_start = 0;
106
+ content_len = 0;
107
+ mark = 0;
108
+ nread = 0;
109
+ field_len = 0;
110
+ field_start = 0;
111
+ }
112
+ }
113
+
114
+ public final HttpParser parser = new HttpParser();
115
+
116
+ public int execute(ByteList buffer, int off) {
117
+ int p, pe;
118
+ int cs = parser.cs;
119
+ int len = buffer.length();
120
+ assert off<=len : "offset past end of buffer";
121
+
122
+ p = off;
123
+ pe = len;
124
+ byte[] data = buffer.unsafeBytes();
125
+ parser.buffer = buffer;
126
+
127
+ %% write exec;
128
+
129
+ parser.cs = cs;
130
+ parser.nread += (p - off);
131
+
132
+ assert p <= pe : "buffer overflow after parsing execute";
133
+ assert parser.nread <= len : "nread longer than length";
134
+ assert parser.body_start <= len : "body starts after buffer end";
135
+ assert parser.mark < len : "mark is after buffer end";
136
+ assert parser.field_len <= len : "field has length longer than whole buffer";
137
+ assert parser.field_start < len : "field starts after buffer end";
138
+
139
+ return parser.nread;
140
+ }
141
+
142
+ public int finish() {
143
+ if(has_error()) {
144
+ return -1;
145
+ } else if(is_finished()) {
146
+ return 1;
147
+ } else {
148
+ return 0;
149
+ }
150
+ }
151
+
152
+ public boolean has_error() {
153
+ return parser.cs == http_parser_error;
154
+ }
155
+
156
+ public boolean is_finished() {
157
+ return parser.cs == http_parser_first_final;
158
+ }
159
+ }
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Copyright (c) 2005 Zed A. Shaw
3
+ * You can redistribute it and/or modify it under the same terms as Ruby.
4
+ */
5
+ #include "http11_parser.h"
6
+ #include <stdio.h>
7
+ #include <assert.h>
8
+ #include <stdlib.h>
9
+ #include <ctype.h>
10
+ #include <string.h>
11
+
12
+ /*
13
+ * capitalizes all lower-case ASCII characters,
14
+ * converts dashes to underscores.
15
+ */
16
+ static void snake_upcase_char(char *c)
17
+ {
18
+ if (*c >= 'a' && *c <= 'z')
19
+ *c &= ~0x20;
20
+ else if (*c == '-')
21
+ *c = '_';
22
+ }
23
+
24
+ #define LEN(AT, FPC) (FPC - buffer - parser->AT)
25
+ #define MARK(M,FPC) (parser->M = (FPC) - buffer)
26
+ #define PTR_TO(F) (buffer + parser->F)
27
+
28
+ /** Machine **/
29
+
30
+ %%{
31
+
32
+ machine http_parser;
33
+
34
+ action mark { MARK(mark, fpc); }
35
+
36
+
37
+ action start_field { MARK(field_start, fpc); }
38
+ action snake_upcase_field { snake_upcase_char((char *)fpc); }
39
+ action write_field {
40
+ parser->field_len = LEN(field_start, fpc);
41
+ }
42
+
43
+ action start_value { MARK(mark, fpc); }
44
+ action write_value {
45
+ parser->http_field(parser, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, fpc));
46
+ }
47
+ action request_method {
48
+ parser->request_method(parser, PTR_TO(mark), LEN(mark, fpc));
49
+ }
50
+ action request_uri {
51
+ parser->request_uri(parser, PTR_TO(mark), LEN(mark, fpc));
52
+ }
53
+ action fragment {
54
+ parser->fragment(parser, PTR_TO(mark), LEN(mark, fpc));
55
+ }
56
+
57
+ action start_query { MARK(query_start, fpc); }
58
+ action query_string {
59
+ parser->query_string(parser, PTR_TO(query_start), LEN(query_start, fpc));
60
+ }
61
+
62
+ action http_version {
63
+ parser->http_version(parser, PTR_TO(mark), LEN(mark, fpc));
64
+ }
65
+
66
+ action request_path {
67
+ parser->request_path(parser, PTR_TO(mark), LEN(mark,fpc));
68
+ }
69
+
70
+ action done {
71
+ parser->body_start = fpc - buffer + 1;
72
+ parser->header_done(parser, fpc + 1, pe - fpc - 1);
73
+ fbreak;
74
+ }
75
+
76
+ include http_parser_common "http11_parser_common.rl";
77
+
78
+ }%%
79
+
80
+ /** Data **/
81
+ %% write data;
82
+
83
+ int http_parser_init(http_parser *parser) {
84
+ int cs = 0;
85
+ %% write init;
86
+ parser->cs = cs;
87
+ parser->body_start = 0;
88
+ parser->content_len = 0;
89
+ parser->mark = 0;
90
+ parser->nread = 0;
91
+ parser->field_len = 0;
92
+ parser->field_start = 0;
93
+ parser->request = Qnil;
94
+ parser->body = Qnil;
95
+
96
+ return 1;
97
+ }
98
+
99
+
100
+ /** exec **/
101
+ size_t http_parser_execute(http_parser *parser, const char *buffer, size_t len, size_t off) {
102
+ const char *p, *pe;
103
+ int cs = parser->cs;
104
+
105
+ assert(off <= len && "offset past end of buffer");
106
+
107
+ p = buffer+off;
108
+ pe = buffer+len;
109
+
110
+ /* assert(*pe == '\0' && "pointer does not end on NUL"); */
111
+ assert(pe - p == len - off && "pointers aren't same distance");
112
+
113
+ %% write exec;
114
+
115
+ if (!http_parser_has_error(parser))
116
+ parser->cs = cs;
117
+ parser->nread += p - (buffer + off);
118
+
119
+ assert(p <= pe && "buffer overflow after parsing execute");
120
+ assert(parser->nread <= len && "nread longer than length");
121
+ assert(parser->body_start <= len && "body starts after buffer end");
122
+ assert(parser->mark < len && "mark is after buffer end");
123
+ assert(parser->field_len <= len && "field has length longer than whole buffer");
124
+ assert(parser->field_start < len && "field starts after buffer end");
125
+
126
+ return(parser->nread);
127
+ }
128
+
129
+ int http_parser_finish(http_parser *parser)
130
+ {
131
+ if (http_parser_has_error(parser) ) {
132
+ return -1;
133
+ } else if (http_parser_is_finished(parser) ) {
134
+ return 1;
135
+ } else {
136
+ return 0;
137
+ }
138
+ }
139
+
140
+ int http_parser_has_error(http_parser *parser) {
141
+ return parser->cs == http_parser_error;
142
+ }
143
+
144
+ int http_parser_is_finished(http_parser *parser) {
145
+ return parser->cs >= http_parser_first_final;
146
+ }
@@ -0,0 +1,54 @@
1
+ %%{
2
+
3
+ machine http_parser_common;
4
+
5
+ #### HTTP PROTOCOL GRAMMAR
6
+ # line endings
7
+ CRLF = "\r\n";
8
+
9
+ # character types
10
+ CTL = (cntrl | 127);
11
+ safe = ("$" | "-" | "_" | ".");
12
+ extra = ("!" | "*" | "'" | "(" | ")" | ",");
13
+ reserved = (";" | "/" | "?" | ":" | "@" | "&" | "=" | "+");
14
+ unsafe = (CTL | " " | "\"" | "#" | "%" | "<" | ">");
15
+ national = any -- (alpha | digit | reserved | extra | safe | unsafe);
16
+ unreserved = (alpha | digit | safe | extra | national);
17
+ escape = ("%" xdigit xdigit);
18
+ uchar = (unreserved | escape);
19
+ pchar = (uchar | ":" | "@" | "&" | "=" | "+");
20
+ tspecials = ("(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\\" | "\"" | "/" | "[" | "]" | "?" | "=" | "{" | "}" | " " | "\t");
21
+
22
+ # elements
23
+ token = (ascii -- (CTL | tspecials));
24
+
25
+ # URI schemes and absolute paths
26
+ scheme = ( alpha | digit | "+" | "-" | "." )* ;
27
+ absolute_uri = (scheme ":" (uchar | reserved )*);
28
+
29
+ path = ( pchar+ ( "/" pchar* )* ) ;
30
+ query = ( uchar | reserved )* %query_string ;
31
+ param = ( pchar | "/" )* ;
32
+ params = ( param ( ";" param )* ) ;
33
+ rel_path = ( path? %request_path (";" params)? ) ("?" %start_query query)?;
34
+ absolute_path = ( "/"+ rel_path );
35
+
36
+ Request_URI = ( "*" | absolute_uri | absolute_path ) >mark %request_uri;
37
+ Fragment = ( uchar | reserved )* >mark %fragment;
38
+ Method = ( upper | digit | safe ){1,20} >mark %request_method;
39
+
40
+ http_number = ( digit+ "." digit+ ) ;
41
+ HTTP_Version = ( "HTTP/" http_number ) >mark %http_version ;
42
+ Request_Line = ( Method " " Request_URI ("#" Fragment){0,1} " " HTTP_Version CRLF ) ;
43
+
44
+ field_name = ( token -- ":" )+ >start_field $snake_upcase_field %write_field;
45
+
46
+ field_value = any* >start_value %write_value;
47
+
48
+ message_header = field_name ":" " "* field_value :> CRLF;
49
+
50
+ Request = Request_Line ( message_header )* ( CRLF @done );
51
+
52
+ main := Request;
53
+
54
+ }%%
@@ -0,0 +1,241 @@
1
+ package org.jruby.mongrel;
2
+
3
+ import org.jruby.Ruby;
4
+ import org.jruby.RubyClass;
5
+ import org.jruby.RubyHash;
6
+ import org.jruby.RubyModule;
7
+ import org.jruby.RubyNumeric;
8
+ import org.jruby.RubyObject;
9
+ import org.jruby.RubyString;
10
+
11
+ import org.jruby.anno.JRubyMethod;
12
+
13
+ import org.jruby.runtime.ObjectAllocator;
14
+ import org.jruby.runtime.ThreadContext;
15
+ import org.jruby.runtime.builtin.IRubyObject;
16
+
17
+ import org.jruby.exceptions.RaiseException;
18
+
19
+ import org.jruby.util.ByteList;
20
+
21
+ /**
22
+ * @author <a href="mailto:ola.bini@ki.se">Ola Bini</a>
23
+ */
24
+ public class Http11 extends RubyObject {
25
+ public final static int MAX_FIELD_NAME_LENGTH = 256;
26
+ public final static String MAX_FIELD_NAME_LENGTH_ERR = "HTTP element FIELD_NAME is longer than the 256 allowed length.";
27
+ public final static int MAX_FIELD_VALUE_LENGTH = 80 * 1024;
28
+ public final static String MAX_FIELD_VALUE_LENGTH_ERR = "HTTP element FIELD_VALUE is longer than the 81920 allowed length.";
29
+ public final static int MAX_REQUEST_URI_LENGTH = 1024 * 12;
30
+ public final static String MAX_REQUEST_URI_LENGTH_ERR = "HTTP element REQUEST_URI is longer than the 12288 allowed length.";
31
+ public final static int MAX_FRAGMENT_LENGTH = 1024;
32
+ public final static String MAX_FRAGMENT_LENGTH_ERR = "HTTP element REQUEST_PATH is longer than the 1024 allowed length.";
33
+ public final static int MAX_REQUEST_PATH_LENGTH = 1024;
34
+ public final static String MAX_REQUEST_PATH_LENGTH_ERR = "HTTP element REQUEST_PATH is longer than the 1024 allowed length.";
35
+ public final static int MAX_QUERY_STRING_LENGTH = 1024 * 10;
36
+ public final static String MAX_QUERY_STRING_LENGTH_ERR = "HTTP element QUERY_STRING is longer than the 10240 allowed length.";
37
+ public final static int MAX_HEADER_LENGTH = 1024 * (80 + 32);
38
+ public final static String MAX_HEADER_LENGTH_ERR = "HTTP element HEADER is longer than the 114688 allowed length.";
39
+
40
+
41
+ private static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
42
+ public IRubyObject allocate(Ruby runtime, RubyClass klass) {
43
+ return new Http11(runtime, klass);
44
+ }
45
+ };
46
+
47
+ public static void createHttp11(Ruby runtime) {
48
+ RubyModule mMongrel = runtime.defineModule("Mongrel");
49
+ mMongrel.defineClassUnder("HttpParserError",runtime.getClass("IOError"),runtime.getClass("IOError").getAllocator());
50
+
51
+ RubyClass cHttpParser = mMongrel.defineClassUnder("HttpParser",runtime.getObject(),ALLOCATOR);
52
+ cHttpParser.defineAnnotatedMethods(Http11.class);
53
+ }
54
+
55
+ private Ruby runtime;
56
+ private RubyClass eHttpParserError;
57
+ private Http11Parser hp;
58
+
59
+ public Http11(Ruby runtime, RubyClass clazz) {
60
+ super(runtime,clazz);
61
+ this.runtime = runtime;
62
+ this.eHttpParserError = (RubyClass)runtime.getModule("Mongrel").getConstant("HttpParserError");
63
+ this.hp = new Http11Parser();
64
+ this.hp.parser.http_field = http_field;
65
+ this.hp.parser.request_method = request_method;
66
+ this.hp.parser.request_uri = request_uri;
67
+ this.hp.parser.fragment = fragment;
68
+ this.hp.parser.request_path = request_path;
69
+ this.hp.parser.query_string = query_string;
70
+ this.hp.parser.http_version = http_version;
71
+ this.hp.parser.header_done = header_done;
72
+ this.hp.parser.init();
73
+ }
74
+
75
+ public void validateMaxLength(int len, int max, String msg) {
76
+ if(len>max) {
77
+ throw new RaiseException(runtime, eHttpParserError, msg, true);
78
+ }
79
+ }
80
+
81
+ private Http11Parser.FieldCB http_field = new Http11Parser.FieldCB() {
82
+ public void call(Object data, int field, int flen, int value, int vlen) {
83
+ RubyHash req = (RubyHash)data;
84
+ RubyString v,f;
85
+ validateMaxLength(flen, MAX_FIELD_NAME_LENGTH, MAX_FIELD_NAME_LENGTH_ERR);
86
+ validateMaxLength(vlen, MAX_FIELD_VALUE_LENGTH, MAX_FIELD_VALUE_LENGTH_ERR);
87
+
88
+ v = RubyString.newString(runtime, new ByteList(Http11.this.hp.parser.buffer,value,vlen));
89
+ f = RubyString.newString(runtime, "HTTP_");
90
+ ByteList b = new ByteList(Http11.this.hp.parser.buffer,field,flen);
91
+ for(int i = 0,j = b.length();i<j;i++) {
92
+ if((b.get(i) & 0xFF) == '-') {
93
+ b.set(i, (byte)'_');
94
+ } else {
95
+ b.set(i, (byte)Character.toUpperCase((char)b.get(i)));
96
+ }
97
+ }
98
+ f.cat(b);
99
+ req.op_aset(req.getRuntime().getCurrentContext(), f,v);
100
+ }
101
+ };
102
+
103
+ private Http11Parser.ElementCB request_method = new Http11Parser.ElementCB() {
104
+ public void call(Object data, int at, int length) {
105
+ RubyHash req = (RubyHash)data;
106
+ RubyString val = RubyString.newString(runtime,new ByteList(hp.parser.buffer,at,length));
107
+ req.op_aset(req.getRuntime().getCurrentContext(), runtime.newString("REQUEST_METHOD"),val);
108
+ }
109
+ };
110
+
111
+ private Http11Parser.ElementCB request_uri = new Http11Parser.ElementCB() {
112
+ public void call(Object data, int at, int length) {
113
+ RubyHash req = (RubyHash)data;
114
+ validateMaxLength(length, MAX_REQUEST_URI_LENGTH, MAX_REQUEST_URI_LENGTH_ERR);
115
+ RubyString val = RubyString.newString(runtime,new ByteList(hp.parser.buffer,at,length));
116
+ req.op_aset(req.getRuntime().getCurrentContext(), runtime.newString("REQUEST_URI"),val);
117
+ }
118
+ };
119
+
120
+ private Http11Parser.ElementCB fragment = new Http11Parser.ElementCB() {
121
+ public void call(Object data, int at, int length) {
122
+ RubyHash req = (RubyHash)data;
123
+ validateMaxLength(length, MAX_FRAGMENT_LENGTH, MAX_FRAGMENT_LENGTH_ERR);
124
+ RubyString val = RubyString.newString(runtime,new ByteList(hp.parser.buffer,at,length));
125
+ req.op_aset(req.getRuntime().getCurrentContext(), runtime.newString("FRAGMENT"),val);
126
+ }
127
+ };
128
+
129
+ private Http11Parser.ElementCB request_path = new Http11Parser.ElementCB() {
130
+ public void call(Object data, int at, int length) {
131
+ RubyHash req = (RubyHash)data;
132
+ validateMaxLength(length, MAX_REQUEST_PATH_LENGTH, MAX_REQUEST_PATH_LENGTH_ERR);
133
+ RubyString val = RubyString.newString(runtime,new ByteList(hp.parser.buffer,at,length));
134
+ req.op_aset(req.getRuntime().getCurrentContext(), runtime.newString("REQUEST_PATH"),val);
135
+ }
136
+ };
137
+
138
+ private Http11Parser.ElementCB query_string = new Http11Parser.ElementCB() {
139
+ public void call(Object data, int at, int length) {
140
+ RubyHash req = (RubyHash)data;
141
+ validateMaxLength(length, MAX_QUERY_STRING_LENGTH, MAX_QUERY_STRING_LENGTH_ERR);
142
+ RubyString val = RubyString.newString(runtime,new ByteList(hp.parser.buffer,at,length));
143
+ req.op_aset(req.getRuntime().getCurrentContext(), runtime.newString("QUERY_STRING"),val);
144
+ }
145
+ };
146
+
147
+ private Http11Parser.ElementCB http_version = new Http11Parser.ElementCB() {
148
+ public void call(Object data, int at, int length) {
149
+ RubyHash req = (RubyHash)data;
150
+ RubyString val = RubyString.newString(runtime,new ByteList(hp.parser.buffer,at,length));
151
+ req.op_aset(req.getRuntime().getCurrentContext(), runtime.newString("HTTP_VERSION"),val);
152
+ }
153
+ };
154
+
155
+ private Http11Parser.ElementCB header_done = new Http11Parser.ElementCB() {
156
+ public void call(Object data, int at, int length) {
157
+ RubyHash req = (RubyHash)data;
158
+ ThreadContext context = req.getRuntime().getCurrentContext();
159
+ IRubyObject temp,ctype,clen;
160
+
161
+ clen = req.op_aref(context, runtime.newString("HTTP_CONTENT_LENGTH"));
162
+ if(!clen.isNil()) {
163
+ req.op_aset(context, runtime.newString("CONTENT_LENGTH"),clen);
164
+ }
165
+
166
+ ctype = req.op_aref(context, runtime.newString("HTTP_CONTENT_TYPE"));
167
+ if(!ctype.isNil()) {
168
+ req.op_aset(context, runtime.newString("CONTENT_TYPE"),ctype);
169
+ }
170
+
171
+ req.op_aset(context, runtime.newString("GATEWAY_INTERFACE"),runtime.newString("CGI/1.2"));
172
+ if(!(temp = req.op_aref(context, runtime.newString("HTTP_HOST"))).isNil()) {
173
+ String s = temp.toString();
174
+ int colon = s.indexOf(':');
175
+ if(colon != -1) {
176
+ req.op_aset(context, runtime.newString("SERVER_NAME"),runtime.newString(s.substring(0,colon)));
177
+ req.op_aset(context, runtime.newString("SERVER_PORT"),runtime.newString(s.substring(colon+1)));
178
+ } else {
179
+ req.op_aset(context, runtime.newString("SERVER_NAME"),temp);
180
+ req.op_aset(context, runtime.newString("SERVER_PORT"),runtime.newString("80"));
181
+ }
182
+ }
183
+
184
+ req.setInstanceVariable("@http_body", RubyString.newString(runtime, new ByteList(hp.parser.buffer, at, length)));
185
+ req.op_aset(context, runtime.newString("SERVER_PROTOCOL"),runtime.newString("HTTP/1.1"));
186
+ req.op_aset(context, runtime.newString("SERVER_SOFTWARE"),runtime.newString("Mongrel 1.2.0.beta.1"));
187
+ }
188
+ };
189
+
190
+ @JRubyMethod
191
+ public IRubyObject initialize() {
192
+ this.hp.parser.init();
193
+ return this;
194
+ }
195
+
196
+ @JRubyMethod
197
+ public IRubyObject reset() {
198
+ this.hp.parser.init();
199
+ return runtime.getNil();
200
+ }
201
+
202
+ @JRubyMethod
203
+ public IRubyObject finish() {
204
+ this.hp.finish();
205
+ return this.hp.is_finished() ? runtime.getTrue() : runtime.getFalse();
206
+ }
207
+
208
+ @JRubyMethod
209
+ public IRubyObject execute(IRubyObject req_hash, IRubyObject data, IRubyObject start) {
210
+ int from = 0;
211
+ from = RubyNumeric.fix2int(start);
212
+ ByteList d = ((RubyString)data).getByteList();
213
+ if(from >= d.length()) {
214
+ throw new RaiseException(runtime, eHttpParserError, "Requested start is after data buffer end.", true);
215
+ } else {
216
+ this.hp.parser.data = req_hash;
217
+ this.hp.execute(d,from);
218
+ validateMaxLength(this.hp.parser.nread,MAX_HEADER_LENGTH, MAX_HEADER_LENGTH_ERR);
219
+ if(this.hp.has_error()) {
220
+ throw new RaiseException(runtime, eHttpParserError, "Invalid HTTP format, parsing fails.", true);
221
+ } else {
222
+ return runtime.newFixnum(this.hp.parser.nread);
223
+ }
224
+ }
225
+ }
226
+
227
+ @JRubyMethod(name = "error?")
228
+ public IRubyObject has_error() {
229
+ return this.hp.has_error() ? runtime.getTrue() : runtime.getFalse();
230
+ }
231
+
232
+ @JRubyMethod(name = "finished?")
233
+ public IRubyObject is_finished() {
234
+ return this.hp.is_finished() ? runtime.getTrue() : runtime.getFalse();
235
+ }
236
+
237
+ @JRubyMethod
238
+ public IRubyObject nread() {
239
+ return runtime.newFixnum(this.hp.parser.nread);
240
+ }
241
+ }// Http11