http_parser.rb 0.5.0-x86-mingw32

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.
Files changed (57) hide show
  1. data/.gitignore +11 -0
  2. data/.gitmodules +6 -0
  3. data/README.md +45 -0
  4. data/Rakefile +6 -0
  5. data/bench/thin.rb +57 -0
  6. data/ext/ruby_http_parser/.gitignore +1 -0
  7. data/ext/ruby_http_parser/RubyHttpParserService.java +18 -0
  8. data/ext/ruby_http_parser/ext_help.h +18 -0
  9. data/ext/ruby_http_parser/extconf.rb +16 -0
  10. data/ext/ruby_http_parser/org/ruby_http_parser/RubyHttpParser.java +403 -0
  11. data/ext/ruby_http_parser/ruby_http_parser.c +474 -0
  12. data/ext/ruby_http_parser/vendor/.gitkeep +0 -0
  13. data/ext/ruby_http_parser/vendor/http-parser-java/CONTRIBUTIONS +4 -0
  14. data/ext/ruby_http_parser/vendor/http-parser-java/LICENSE-MIT +19 -0
  15. data/ext/ruby_http_parser/vendor/http-parser-java/README.md +171 -0
  16. data/ext/ruby_http_parser/vendor/http-parser-java/TODO +19 -0
  17. data/ext/ruby_http_parser/vendor/http-parser-java/compile +1 -0
  18. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.c +1590 -0
  19. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.h +167 -0
  20. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPException.java +7 -0
  21. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPMethod.java +90 -0
  22. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPParser.java +31 -0
  23. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/ParserType.java +13 -0
  24. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPCallback.java +5 -0
  25. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPDataCallback.java +25 -0
  26. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPErrorCallback.java +7 -0
  27. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPParser.java +1894 -0
  28. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/ParserSettings.java +78 -0
  29. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/Util.java +112 -0
  30. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestLoaderNG.java +487 -0
  31. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/UnitTest.java +115 -0
  32. data/ext/ruby_http_parser/vendor/http-parser-java/test.c +1865 -0
  33. data/ext/ruby_http_parser/vendor/http-parser-java/test_permutations +1 -0
  34. data/ext/ruby_http_parser/vendor/http-parser-java/test_unit +1 -0
  35. data/ext/ruby_http_parser/vendor/http-parser-java/tests.dumped +539 -0
  36. data/ext/ruby_http_parser/vendor/http-parser-java/tools/byte_constants.rb +6 -0
  37. data/ext/ruby_http_parser/vendor/http-parser-java/tools/const_char.rb +13 -0
  38. data/ext/ruby_http_parser/vendor/http-parser-java/tools/lowcase.rb +15 -0
  39. data/ext/ruby_http_parser/vendor/http-parser-java/tools/parse_tests.rb +33 -0
  40. data/ext/ruby_http_parser/vendor/http-parser/CONTRIBUTIONS +4 -0
  41. data/ext/ruby_http_parser/vendor/http-parser/LICENSE-MIT +19 -0
  42. data/ext/ruby_http_parser/vendor/http-parser/README.md +171 -0
  43. data/ext/ruby_http_parser/vendor/http-parser/http_parser.c +1590 -0
  44. data/ext/ruby_http_parser/vendor/http-parser/http_parser.h +167 -0
  45. data/ext/ruby_http_parser/vendor/http-parser/test.c +1755 -0
  46. data/http_parser.rb.gemspec +15 -0
  47. data/lib/http/parser.rb +1 -0
  48. data/lib/http_parser.rb +4 -0
  49. data/lib/ruby_http_parser.rb +2 -0
  50. data/spec/parser_spec.rb +187 -0
  51. data/spec/spec_helper.rb +2 -0
  52. data/spec/support/requests.json +381 -0
  53. data/spec/support/responses.json +186 -0
  54. data/tasks/compile.rake +39 -0
  55. data/tasks/spec.rake +5 -0
  56. data/tasks/submodules.rake +7 -0
  57. metadata +124 -0
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ tmp
2
+ *.bundle
3
+ *.gem
4
+ *.o
5
+ *.so
6
+ *.bundle
7
+ *.jar
8
+ *.swp
9
+ Makefile
10
+ tags
11
+ *.rbc
data/.gitmodules ADDED
@@ -0,0 +1,6 @@
1
+ [submodule "ext/ruby_http_parser/vendor/http-parser"]
2
+ path = ext/ruby_http_parser/vendor/http-parser
3
+ url = git://github.com/ry/http-parser.git
4
+ [submodule "ext/ruby_http_parser/vendor/http-parser-java"]
5
+ path = ext/ruby_http_parser/vendor/http-parser-java
6
+ url = git://github.com/a2800276/http-parser.java.git
data/README.md ADDED
@@ -0,0 +1,45 @@
1
+ # http_parser.rb
2
+
3
+ A simple callback-based HTTP request/response parser for writing http
4
+ servers, clients and proxies.
5
+
6
+ This gem is built on top of [ry/http-parser](http://github.com/ry/http-parser) and its java port [a2800276/http-parser.java](http://github.com/a2800276/http-parser.java).
7
+
8
+ ## Supported Platforms
9
+
10
+ This gem aims to work on all major Ruby platforms, including:
11
+
12
+ - MRI 1.8 and 1.9
13
+ - Rubinius
14
+ - JRuby
15
+ - win32
16
+
17
+ ## Usage
18
+
19
+ require "http/parser"
20
+
21
+ parser = Http::Parser.new
22
+
23
+ parser.on_headers_complete = proc do |headers|
24
+ p parser.http_method
25
+ p parser.http_version
26
+
27
+ p parser.request_url # for requests
28
+ p parser.status_code # for responses
29
+
30
+ p headers
31
+ end
32
+
33
+ parser.on_body = proc do |chunk|
34
+ # One chunk of the body
35
+ p chunk
36
+ end
37
+
38
+ parser.on_message_complete = proc do |env|
39
+ # Headers and body is all parsed
40
+ puts "Done!"
41
+ end
42
+
43
+ # Feed raw data from the socket to the parser
44
+ parser << raw_data
45
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ # load tasks
2
+ Dir['tasks/*.rake'].sort.each { |f| load f }
3
+
4
+ # default task
5
+ task :compile => :submodules
6
+ task :default => [:compile, :spec]
data/bench/thin.rb ADDED
@@ -0,0 +1,57 @@
1
+ $:.unshift File.dirname(__FILE__) + "/../lib"
2
+ require "rubygems"
3
+ require "thin_parser"
4
+ require "http_parser"
5
+ require "benchmark"
6
+
7
+ data = "POST /postit HTTP/1.1\r\n" +
8
+ "Host: localhost:3000\r\n" +
9
+ "User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.9) Gecko/20071025 Firefox/2.0.0.9\r\n" +
10
+ "Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5\r\n" +
11
+ "Accept-Language: en-us,en;q=0.5\r\n" +
12
+ "Accept-Encoding: gzip,deflate\r\n" +
13
+ "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" +
14
+ "Keep-Alive: 300\r\n" +
15
+ "Connection: keep-alive\r\n" +
16
+ "Content-Type: text/html\r\n" +
17
+ "Content-Length: 37\r\n" +
18
+ "\r\n" +
19
+ "name=marc&email=macournoyer@gmail.com"
20
+
21
+ def thin(data)
22
+ env = {"rack.input" => StringIO.new}
23
+ Thin::HttpParser.new.execute(env, data, 0)
24
+ env
25
+ end
26
+
27
+ def http_parser(data)
28
+ body = StringIO.new
29
+ env = nil
30
+
31
+ parser = HTTP::RequestParser.new
32
+ parser.on_headers_complete = proc { |e| env = e }
33
+ parser.on_body = proc { |c| body << c }
34
+ parser << data
35
+
36
+ env["rack-input"] = body
37
+ env
38
+ end
39
+
40
+ # p thin(data)
41
+ # p http_parser(data)
42
+
43
+ TESTS = 30_000
44
+ Benchmark.bmbm do |results|
45
+ results.report("thin:") { TESTS.times { thin data } }
46
+ results.report("http-parser:") { TESTS.times { http_parser data } }
47
+ end
48
+
49
+ # On my MBP core duo 2.2Ghz
50
+ # Rehearsal ------------------------------------------------
51
+ # thin: 1.470000 0.000000 1.470000 ( 1.474737)
52
+ # http-parser: 1.270000 0.020000 1.290000 ( 1.292758)
53
+ # --------------------------------------- total: 2.760000sec
54
+ #
55
+ # user system total real
56
+ # thin: 1.150000 0.030000 1.180000 ( 1.173767)
57
+ # http-parser: 1.250000 0.010000 1.260000 ( 1.263796)
@@ -0,0 +1 @@
1
+ ryah_http_parser.*
@@ -0,0 +1,18 @@
1
+ import java.io.IOException;
2
+
3
+ import org.jruby.Ruby;
4
+ import org.jruby.RubyClass;
5
+ import org.jruby.RubyModule;
6
+ import org.jruby.runtime.load.BasicLibraryService;
7
+
8
+ import org.ruby_http_parser.*;
9
+
10
+ public class RubyHttpParserService implements BasicLibraryService {
11
+ public boolean basicLoad(final Ruby runtime) throws IOException {
12
+ RubyModule mHTTP = runtime.defineModule("HTTP");
13
+ RubyClass cParser = mHTTP.defineClassUnder("Parser", runtime.getObject(), RubyHttpParser.ALLOCATOR);
14
+ cParser.defineAnnotatedMethods(RubyHttpParser.class);
15
+ cParser.defineClassUnder("Error", runtime.getClass("IOError"),runtime.getClass("IOError").getAllocator());
16
+ return true;
17
+ }
18
+ }
@@ -0,0 +1,18 @@
1
+ #ifndef ext_help_h
2
+ #define ext_help_h
3
+
4
+ #define RAISE_NOT_NULL(T) if(T == NULL) rb_raise(rb_eArgError, "NULL found for " # T " when shouldn't be.");
5
+ #define DATA_GET(from,type,name) Data_Get_Struct(from,type,name); RAISE_NOT_NULL(name);
6
+ #define REQUIRE_TYPE(V, T) if(TYPE(V) != T) rb_raise(rb_eTypeError, "Wrong argument type for " # V " required " # T);
7
+
8
+ /* for compatibility with Ruby 1.8.5, which doesn't declare RSTRING_PTR */
9
+ #ifndef RSTRING_PTR
10
+ #define RSTRING_PTR(s) (RSTRING(s)->ptr)
11
+ #endif
12
+
13
+ /* for compatibility with Ruby 1.8.5, which doesn't declare RSTRING_LEN */
14
+ #ifndef RSTRING_LEN
15
+ #define RSTRING_LEN(s) (RSTRING(s)->len)
16
+ #endif
17
+
18
+ #endif
@@ -0,0 +1,16 @@
1
+ require 'mkmf'
2
+
3
+ # mongrel and http-parser both define http_parser_(init|execute), so we
4
+ # rename functions in http-parser before using them.
5
+ vendor_dir = File.expand_path('../vendor/http-parser/', __FILE__)
6
+ src_dir = File.expand_path('../', __FILE__)
7
+ %w[ http_parser.c http_parser.h ].each do |file|
8
+ File.open(File.join(src_dir, "ryah_#{file}"), 'w'){ |f|
9
+ f.write File.read(File.join(vendor_dir, file)).gsub('http_parser', 'ryah_http_parser')
10
+ }
11
+ end
12
+
13
+ $CFLAGS << " -I#{src_dir}"
14
+
15
+ dir_config("ruby_http_parser")
16
+ create_makefile("ruby_http_parser")
@@ -0,0 +1,403 @@
1
+ package org.ruby_http_parser;
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.runtime.ObjectAllocator;
12
+ import org.jruby.runtime.ThreadContext;
13
+ import org.jruby.runtime.builtin.IRubyObject;
14
+
15
+ import org.jruby.anno.JRubyMethod;
16
+ import org.jruby.exceptions.RaiseException;
17
+
18
+ import java.nio.ByteBuffer;
19
+ import http_parser.*;
20
+ import http_parser.lolevel.ParserSettings;
21
+ import http_parser.lolevel.HTTPCallback;
22
+ import http_parser.lolevel.HTTPDataCallback;
23
+
24
+ public class RubyHttpParser extends RubyObject {
25
+
26
+ public static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
27
+ public IRubyObject allocate(Ruby runtime, RubyClass klass) {
28
+ return new RubyHttpParser(runtime, klass);
29
+ }
30
+ };
31
+
32
+ byte[] fetchBytes (ByteBuffer b, int pos, int len) {
33
+ byte[] by = new byte[len];
34
+ int saved = b.position();
35
+ b.position(pos);
36
+ b.get(by);
37
+ b.position(saved);
38
+ return by;
39
+ }
40
+
41
+ public class StopException extends RuntimeException {
42
+ }
43
+
44
+ private Ruby runtime;
45
+ private HTTPParser parser;
46
+ private ParserSettings settings;
47
+
48
+ private RubyClass eParserError;
49
+
50
+ private RubyHash headers;
51
+
52
+ private IRubyObject on_message_begin;
53
+ private IRubyObject on_headers_complete;
54
+ private IRubyObject on_body;
55
+ private IRubyObject on_message_complete;
56
+
57
+ private IRubyObject requestUrl;
58
+ private IRubyObject requestPath;
59
+ private IRubyObject queryString;
60
+ private IRubyObject fragment;
61
+
62
+ private IRubyObject callback_object;
63
+
64
+ private String _current_header;
65
+ private String _last_header;
66
+
67
+ public RubyHttpParser(final Ruby runtime, RubyClass clazz) {
68
+ super(runtime,clazz);
69
+
70
+ this.runtime = runtime;
71
+ this.eParserError = (RubyClass)runtime.getModule("HTTP").getClass("Parser").getConstant("Error");
72
+
73
+ this.on_message_begin = null;
74
+ this.on_headers_complete = null;
75
+ this.on_body = null;
76
+ this.on_message_complete = null;
77
+
78
+ this.callback_object = null;
79
+
80
+ initSettings();
81
+ init();
82
+ }
83
+
84
+ private void initSettings() {
85
+ this.settings = new ParserSettings();
86
+
87
+ this.settings.on_url = new HTTPDataCallback() {
88
+ public int cb (http_parser.lolevel.HTTPParser p, ByteBuffer buf, int pos, int len) {
89
+ byte[] data = fetchBytes(buf, pos, len);
90
+ ((RubyString)requestUrl).concat(runtime.newString(new String(data)));
91
+ return 0;
92
+ }
93
+ };
94
+ this.settings.on_path = new HTTPDataCallback() {
95
+ public int cb (http_parser.lolevel.HTTPParser p, ByteBuffer buf, int pos, int len) {
96
+ byte[] data = fetchBytes(buf, pos, len);
97
+ ((RubyString)requestPath).concat(runtime.newString(new String(data)));
98
+ return 0;
99
+ }
100
+ };
101
+ this.settings.on_query_string = new HTTPDataCallback() {
102
+ public int cb (http_parser.lolevel.HTTPParser p, ByteBuffer buf, int pos, int len) {
103
+ byte[] data = fetchBytes(buf, pos, len);
104
+ ((RubyString)queryString).concat(runtime.newString(new String(data)));
105
+ return 0;
106
+ }
107
+ };
108
+ this.settings.on_fragment = new HTTPDataCallback() {
109
+ public int cb (http_parser.lolevel.HTTPParser p, ByteBuffer buf, int pos, int len) {
110
+ byte[] data = fetchBytes(buf, pos, len);
111
+ ((RubyString)fragment).concat(runtime.newString(new String(data)));
112
+ return 0;
113
+ }
114
+ };
115
+
116
+ this.settings.on_header_field = new HTTPDataCallback() {
117
+ public int cb (http_parser.lolevel.HTTPParser p, ByteBuffer buf, int pos, int len) {
118
+ byte[] data = fetchBytes(buf, pos, len);
119
+
120
+ if (_current_header == null)
121
+ _current_header = new String(data);
122
+ else
123
+ _current_header.concat(new String(data));
124
+
125
+ return 0;
126
+ }
127
+ };
128
+ this.settings.on_header_value = new HTTPDataCallback() {
129
+ public int cb (http_parser.lolevel.HTTPParser p, ByteBuffer buf, int pos, int len) {
130
+ byte[] data = fetchBytes(buf, pos, len);
131
+ ThreadContext context = headers.getRuntime().getCurrentContext();
132
+ IRubyObject key, val;
133
+
134
+ if (_current_header != null) {
135
+ _last_header = _current_header;
136
+ _current_header = null;
137
+
138
+ key = (IRubyObject)runtime.newString(_last_header);
139
+ val = headers.op_aref(context, key);
140
+
141
+ if (!val.isNil())
142
+ ((RubyString)val).cat(", ".getBytes());
143
+ } else {
144
+ key = (IRubyObject)runtime.newString(_last_header);
145
+ val = headers.op_aref(context, key);
146
+ }
147
+
148
+ if (val.isNil())
149
+ headers.op_aset(context, key, runtime.newString(new String(data)));
150
+ else
151
+ ((RubyString)val).cat(data);
152
+
153
+ return 0;
154
+ }
155
+ };
156
+
157
+ this.settings.on_message_begin = new HTTPCallback() {
158
+ public int cb (http_parser.lolevel.HTTPParser p) {
159
+ headers = new RubyHash(runtime);
160
+
161
+ requestUrl = runtime.newString("");
162
+ requestPath = runtime.newString("");
163
+ queryString = runtime.newString("");
164
+ fragment = runtime.newString("");
165
+
166
+ IRubyObject ret = runtime.getNil();
167
+
168
+ if (callback_object != null) {
169
+ if (((RubyObject)callback_object).respond_to_p(runtime.newSymbol("on_message_begin")).toJava(Boolean.class) == Boolean.TRUE) {
170
+ ThreadContext context = callback_object.getRuntime().getCurrentContext();
171
+ ret = callback_object.callMethod(context, "on_message_begin");
172
+ }
173
+ } else if (on_message_begin != null) {
174
+ ThreadContext context = on_message_begin.getRuntime().getCurrentContext();
175
+ ret = on_message_begin.callMethod(context, "call");
176
+ }
177
+
178
+ if (ret == runtime.newSymbol("stop")) {
179
+ throw new StopException();
180
+ } else {
181
+ return 0;
182
+ }
183
+ }
184
+ };
185
+ this.settings.on_message_complete = new HTTPCallback() {
186
+ public int cb (http_parser.lolevel.HTTPParser p) {
187
+ IRubyObject ret = runtime.getNil();
188
+
189
+ if (callback_object != null) {
190
+ if (((RubyObject)callback_object).respond_to_p(runtime.newSymbol("on_message_complete")).toJava(Boolean.class) == Boolean.TRUE) {
191
+ ThreadContext context = callback_object.getRuntime().getCurrentContext();
192
+ ret = callback_object.callMethod(context, "on_message_complete");
193
+ }
194
+ } else if (on_message_complete != null) {
195
+ ThreadContext context = on_message_complete.getRuntime().getCurrentContext();
196
+ ret = on_message_complete.callMethod(context, "call");
197
+ }
198
+
199
+ if (ret == runtime.newSymbol("stop")) {
200
+ throw new StopException();
201
+ } else {
202
+ return 0;
203
+ }
204
+ }
205
+ };
206
+ this.settings.on_headers_complete = new HTTPCallback() {
207
+ public int cb (http_parser.lolevel.HTTPParser p) {
208
+ IRubyObject ret = runtime.getNil();
209
+
210
+ if (callback_object != null) {
211
+ if (((RubyObject)callback_object).respond_to_p(runtime.newSymbol("on_headers_complete")).toJava(Boolean.class) == Boolean.TRUE) {
212
+ ThreadContext context = callback_object.getRuntime().getCurrentContext();
213
+ ret = callback_object.callMethod(context, "on_headers_complete", headers);
214
+ }
215
+ } else if (on_headers_complete != null) {
216
+ ThreadContext context = on_headers_complete.getRuntime().getCurrentContext();
217
+ ret = on_headers_complete.callMethod(context, "call", headers);
218
+ }
219
+
220
+ if (ret == runtime.newSymbol("stop")) {
221
+ throw new StopException();
222
+ } else {
223
+ return 0;
224
+ }
225
+ }
226
+ };
227
+ this.settings.on_body = new HTTPDataCallback() {
228
+ public int cb (http_parser.lolevel.HTTPParser p, ByteBuffer buf, int pos, int len) {
229
+ IRubyObject ret = runtime.getNil();
230
+ byte[] data = fetchBytes(buf, pos, len);
231
+
232
+ if (callback_object != null) {
233
+ if (((RubyObject)callback_object).respond_to_p(runtime.newSymbol("on_body")).toJava(Boolean.class) == Boolean.TRUE) {
234
+ ThreadContext context = callback_object.getRuntime().getCurrentContext();
235
+ ret = callback_object.callMethod(context, "on_body", callback_object.getRuntime().newString(new String(data)));
236
+ }
237
+ } else if (on_body != null) {
238
+ ThreadContext context = on_body.getRuntime().getCurrentContext();
239
+ ret = on_body.callMethod(context, "call", on_body.getRuntime().newString(new String(data)));
240
+ }
241
+
242
+ if (ret == runtime.newSymbol("stop")) {
243
+ throw new StopException();
244
+ } else {
245
+ return 0;
246
+ }
247
+ }
248
+ };
249
+ }
250
+
251
+ private void init() {
252
+ this.parser = new HTTPParser();
253
+ this.headers = null;
254
+
255
+ this.requestUrl = runtime.getNil();
256
+ this.requestPath = runtime.getNil();
257
+ this.queryString = runtime.getNil();
258
+ this.fragment = runtime.getNil();
259
+ }
260
+
261
+ @JRubyMethod(name = "initialize")
262
+ public IRubyObject initialize() {
263
+ return this;
264
+ }
265
+
266
+ @JRubyMethod(name = "initialize")
267
+ public IRubyObject initialize(IRubyObject arg) {
268
+ callback_object = arg;
269
+ return initialize();
270
+ }
271
+
272
+ @JRubyMethod(name = "on_message_begin=")
273
+ public IRubyObject set_on_message_begin(IRubyObject cb) {
274
+ on_message_begin = cb;
275
+ return cb;
276
+ }
277
+
278
+ @JRubyMethod(name = "on_headers_complete=")
279
+ public IRubyObject set_on_headers_complete(IRubyObject cb) {
280
+ on_headers_complete = cb;
281
+ return cb;
282
+ }
283
+
284
+ @JRubyMethod(name = "on_body=")
285
+ public IRubyObject set_on_body(IRubyObject cb) {
286
+ on_body = cb;
287
+ return cb;
288
+ }
289
+
290
+ @JRubyMethod(name = "on_message_complete=")
291
+ public IRubyObject set_on_message_complete(IRubyObject cb) {
292
+ on_message_complete = cb;
293
+ return cb;
294
+ }
295
+
296
+ @JRubyMethod(name = "<<")
297
+ public IRubyObject execute(IRubyObject data) {
298
+ RubyString str = (RubyString)data;
299
+ ByteBuffer buf = ByteBuffer.wrap(str.getBytes());
300
+ boolean stopped = false;
301
+
302
+ try {
303
+ this.parser.execute(this.settings, buf);
304
+ } catch (HTTPException e) {
305
+ throw new RaiseException(runtime, eParserError, e.getMessage(), true);
306
+ } catch (StopException e) {
307
+ stopped = true;
308
+ }
309
+
310
+ if (parser.getUpgrade()) {
311
+ // upgrade request
312
+ } else if (buf.hasRemaining()) {
313
+ if (!stopped)
314
+ throw new RaiseException(runtime, eParserError, "Could not parse data entirely", true);
315
+ }
316
+
317
+ return RubyNumeric.int2fix(runtime, buf.position());
318
+ }
319
+
320
+ @JRubyMethod(name = "keep_alive?")
321
+ public IRubyObject shouldKeepAlive() {
322
+ return parser.shouldKeepAlive() ? runtime.getTrue() : runtime.getFalse();
323
+ }
324
+
325
+ @JRubyMethod(name = "upgrade?")
326
+ public IRubyObject shouldUpgrade() {
327
+ return parser.getUpgrade() ? runtime.getTrue() : runtime.getFalse();
328
+ }
329
+
330
+ @JRubyMethod(name = "http_major")
331
+ public IRubyObject httpMajor() {
332
+ if (parser.getMajor() == 0 && parser.getMinor() == 0)
333
+ return runtime.getNil();
334
+ else
335
+ return RubyNumeric.int2fix(runtime, parser.getMajor());
336
+ }
337
+
338
+ @JRubyMethod(name = "http_minor")
339
+ public IRubyObject httpMinor() {
340
+ if (parser.getMajor() == 0 && parser.getMinor() == 0)
341
+ return runtime.getNil();
342
+ else
343
+ return RubyNumeric.int2fix(runtime, parser.getMinor());
344
+ }
345
+
346
+ @JRubyMethod(name = "http_version")
347
+ public IRubyObject httpVersion() {
348
+ if (parser.getMajor() == 0 && parser.getMinor() == 0)
349
+ return runtime.getNil();
350
+ else
351
+ return runtime.newArray(httpMajor(), httpMinor());
352
+ }
353
+
354
+ @JRubyMethod(name = "http_method")
355
+ public IRubyObject httpMethod() {
356
+ HTTPMethod method = parser.getHTTPMethod();
357
+ if (method != null)
358
+ return runtime.newString(new String(method.bytes));
359
+ else
360
+ return runtime.getNil();
361
+ }
362
+
363
+ @JRubyMethod(name = "status_code")
364
+ public IRubyObject statusCode() {
365
+ int code = parser.getStatusCode();
366
+ if (code != 0)
367
+ return RubyNumeric.int2fix(runtime, code);
368
+ else
369
+ return runtime.getNil();
370
+ }
371
+
372
+ @JRubyMethod(name = "headers")
373
+ public IRubyObject getHeaders() {
374
+ return headers == null ? runtime.getNil() : headers;
375
+ }
376
+
377
+ @JRubyMethod(name = "request_url")
378
+ public IRubyObject getRequestUrl() {
379
+ return requestUrl == null ? runtime.getNil() : requestUrl;
380
+ }
381
+
382
+ @JRubyMethod(name = "request_path")
383
+ public IRubyObject getRequestPath() {
384
+ return requestPath == null ? runtime.getNil() : requestPath;
385
+ }
386
+
387
+ @JRubyMethod(name = "query_string")
388
+ public IRubyObject getQueryString() {
389
+ return queryString == null ? runtime.getNil() : queryString;
390
+ }
391
+
392
+ @JRubyMethod(name = "fragment")
393
+ public IRubyObject getFragment() {
394
+ return fragment == null ? runtime.getNil() : fragment;
395
+ }
396
+
397
+ @JRubyMethod(name = "reset!")
398
+ public IRubyObject reset() {
399
+ init();
400
+ return runtime.getTrue();
401
+ }
402
+
403
+ }