http_parser.rb 0.5.3 → 0.6.0.beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. data/.gitmodules +3 -3
  2. data/Gemfile +1 -1
  3. data/Gemfile.lock +9 -2
  4. data/README.md +50 -45
  5. data/bench/standalone.rb +23 -0
  6. data/bench/thin.rb +1 -0
  7. data/ext/ruby_http_parser/org/ruby_http_parser/RubyHttpParser.java +66 -58
  8. data/ext/ruby_http_parser/ruby_http_parser.c +10 -41
  9. data/ext/ruby_http_parser/vendor/http-parser-java/AUTHORS +32 -0
  10. data/ext/ruby_http_parser/vendor/http-parser-java/LICENSE-MIT +5 -1
  11. data/ext/ruby_http_parser/vendor/http-parser-java/README.md +133 -1
  12. data/ext/ruby_http_parser/vendor/http-parser-java/TODO +6 -0
  13. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.c +1029 -615
  14. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.gyp +79 -0
  15. data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.h +177 -43
  16. data/ext/ruby_http_parser/vendor/http-parser-java/src/Http-parser.java.iml +22 -0
  17. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/FieldData.java +41 -0
  18. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPHeadersCompleteCallback.java +13 -0
  19. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPMethod.java +4 -1
  20. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPParserUrl.java +76 -0
  21. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/ParserSettings.java +2 -2
  22. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/Util.java +6 -6
  23. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPHeadersCompleteCallback.java +12 -0
  24. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPParser.java +715 -637
  25. data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/ParserSettings.java +1 -1
  26. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Message.java +71 -21
  27. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/ParseUrl.java +51 -0
  28. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Requests.java +1 -1
  29. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Responses.java +1 -0
  30. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Test.java +2 -1
  31. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestHeaderOverflowError.java +1 -0
  32. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestLoaderNG.java +6 -17
  33. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestNoOverflowLongBody.java +1 -0
  34. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/UnitTest.java +1 -0
  35. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Upgrade.java +1 -0
  36. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Url.java +127 -0
  37. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Util.java +80 -9
  38. data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/WrongContentLength.java +2 -1
  39. data/ext/ruby_http_parser/vendor/http-parser-java/test.c +1141 -210
  40. data/ext/ruby_http_parser/vendor/http-parser-java/tests.dumped +230 -71
  41. data/ext/ruby_http_parser/vendor/http-parser/AUTHORS +32 -0
  42. data/ext/ruby_http_parser/vendor/http-parser/LICENSE-MIT +5 -1
  43. data/ext/ruby_http_parser/vendor/http-parser/README.md +9 -2
  44. data/ext/ruby_http_parser/vendor/http-parser/http_parser.c +1029 -615
  45. data/ext/ruby_http_parser/vendor/http-parser/http_parser.gyp +79 -0
  46. data/ext/ruby_http_parser/vendor/http-parser/http_parser.h +145 -16
  47. data/ext/ruby_http_parser/vendor/http-parser/test.c +1065 -141
  48. data/http_parser.rb.gemspec +3 -1
  49. data/spec/parser_spec.rb +41 -17
  50. data/spec/support/requests.json +236 -24
  51. data/spec/support/responses.json +182 -36
  52. data/tasks/compile.rake +2 -2
  53. data/tasks/fixtures.rake +7 -1
  54. metadata +57 -19
  55. data/ext/ruby_http_parser/vendor/http-parser-java/compile +0 -1
  56. data/ext/ruby_http_parser/vendor/http-parser-java/test_permutations +0 -1
  57. data/ext/ruby_http_parser/vendor/http-parser-java/test_unit +0 -1
  58. data/ext/ruby_http_parser/vendor/http-parser-java/test_utf8 +0 -1
@@ -1,6 +1,6 @@
1
- [submodule "ext/ruby_http_parser/vendor/http-parser"]
1
+ [submodule "http-parser"]
2
2
  path = ext/ruby_http_parser/vendor/http-parser
3
3
  url = git://github.com/joyent/http-parser.git
4
- [submodule "ext/ruby_http_parser/vendor/http-parser-java"]
4
+ [submodule "http-parser-java"]
5
5
  path = ext/ruby_http_parser/vendor/http-parser-java
6
- url = git://github.com/a2800276/http-parser.java.git
6
+ url = git://github.com/http-parser/http-parser.java
data/Gemfile CHANGED
@@ -1,2 +1,2 @@
1
- source :rubygems
1
+ source 'https://rubygems.org'
2
2
  gemspec
@@ -1,13 +1,17 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- http_parser.rb (0.5.2)
4
+ http_parser.rb (0.5.3)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
8
8
  specs:
9
+ benchmark_suite (0.8.0)
9
10
  diff-lcs (1.1.2)
11
+ ffi (1.0.11)
12
+ ffi (1.0.11-java)
10
13
  json (1.5.1)
14
+ json (1.5.1-java)
11
15
  rake (0.9.2)
12
16
  rake-compiler (0.7.9)
13
17
  rake
@@ -19,12 +23,15 @@ GEM
19
23
  rspec-expectations (2.4.0)
20
24
  diff-lcs (~> 1.1.2)
21
25
  rspec-mocks (2.4.0)
22
- yajl-ruby (0.8.2)
26
+ yajl-ruby (1.1.0)
23
27
 
24
28
  PLATFORMS
29
+ java
25
30
  ruby
26
31
 
27
32
  DEPENDENCIES
33
+ benchmark_suite
34
+ ffi
28
35
  http_parser.rb!
29
36
  json (>= 1.4.6)
30
37
  rake-compiler (>= 0.7.9)
data/README.md CHANGED
@@ -16,70 +16,75 @@ This gem aims to work on all major Ruby platforms, including:
16
16
 
17
17
  ## Usage
18
18
 
19
- require "http/parser"
19
+ ```ruby
20
+ require "http/parser"
20
21
 
21
- parser = Http::Parser.new
22
+ parser = Http::Parser.new
22
23
 
23
- parser.on_headers_complete = proc do
24
- p parser.http_version
24
+ parser.on_headers_complete = proc do
25
+ p parser.http_version
25
26
 
26
- p parser.http_method # for requests
27
- p parser.request_url
27
+ p parser.http_method # for requests
28
+ p parser.request_url
28
29
 
29
- p parser.status_code # for responses
30
+ p parser.status_code # for responses
30
31
 
31
- p parser.headers
32
- end
32
+ p parser.headers
33
+ end
33
34
 
34
- parser.on_body = proc do |chunk|
35
- # One chunk of the body
36
- p chunk
37
- end
35
+ parser.on_body = proc do |chunk|
36
+ # One chunk of the body
37
+ p chunk
38
+ end
38
39
 
39
- parser.on_message_complete = proc do |env|
40
- # Headers and body is all parsed
41
- puts "Done!"
42
- end
40
+ parser.on_message_complete = proc do |env|
41
+ # Headers and body is all parsed
42
+ puts "Done!"
43
+ end
44
+ ```
43
45
 
44
- # Feed raw data from the socket to the parser
45
- parser << raw_data
46
+ # Feed raw data from the socket to the parser
47
+ `parser << raw_data`
46
48
 
47
49
  ## Advanced Usage
48
50
 
49
51
  ### Accept callbacks on an object
50
52
 
51
- module MyHttpConnection
52
- def connection_completed
53
- @parser = Http::Parser.new(self)
54
- end
53
+ ```ruby
54
+ module MyHttpConnection
55
+ def connection_completed
56
+ @parser = Http::Parser.new(self)
57
+ end
55
58
 
56
- def receive_data(data)
57
- @parser << data
58
- end
59
+ def receive_data(data)
60
+ @parser << data
61
+ end
59
62
 
60
- def on_message_begin
61
- @headers = nil
62
- @body = ''
63
- end
63
+ def on_message_begin
64
+ @headers = nil
65
+ @body = ''
66
+ end
64
67
 
65
- def on_headers_complete
66
- @headers = @parser.headers
67
- end
68
+ def on_headers_complete(headers)
69
+ @headers = headers
70
+ end
68
71
 
69
- def on_body(chunk)
70
- @body << chunk
71
- end
72
+ def on_body(chunk)
73
+ @body << chunk
74
+ end
72
75
 
73
- def on_message_complete
74
- p [@headers, @body]
75
- end
76
- end
76
+ def on_message_complete
77
+ p [@headers, @body]
78
+ end
79
+ end
80
+ ```
77
81
 
78
82
  ### Stop parsing after headers
79
83
 
80
- parser = Http::Parser.new
81
- parser.on_headers_complete = proc{ :stop }
82
-
83
- offset = parser << request_data
84
- body = request_data[offset..-1]
84
+ ```ruby
85
+ parser = Http::Parser.new
86
+ parser.on_headers_complete = proc{ :stop }
85
87
 
88
+ offset = parser << request_data
89
+ body = request_data[offset..-1]
90
+ ```
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift File.dirname(__FILE__) + "/../lib"
3
+ require "rubygems"
4
+ require "http/parser"
5
+ require "benchmark/ips"
6
+
7
+ request = <<-REQUEST
8
+ GET / HTTP/1.1
9
+ Host: www.example.com
10
+ Connection: keep-alive
11
+ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.78 S
12
+ Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
13
+ Accept-Encoding: gzip,deflate,sdch
14
+ Accept-Language: en-US,en;q=0.8
15
+ Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
16
+
17
+ REQUEST
18
+ request.gsub!(/\n/m, "\r\n")
19
+
20
+ Benchmark.ips do |ips|
21
+ ips.report("instance") { Http::Parser.new }
22
+ ips.report("parsing") { Http::Parser.new << request }
23
+ end
@@ -3,6 +3,7 @@ require "rubygems"
3
3
  require "thin_parser"
4
4
  require "http_parser"
5
5
  require "benchmark"
6
+ require "stringio"
6
7
 
7
8
  data = "POST /postit HTTP/1.1\r\n" +
8
9
  "Host: localhost:3000\r\n" +
@@ -8,6 +8,7 @@ import org.jruby.RubyModule;
8
8
  import org.jruby.RubyNumeric;
9
9
  import org.jruby.RubyObject;
10
10
  import org.jruby.RubyString;
11
+ import org.jruby.RubySymbol;
11
12
 
12
13
  import org.jruby.runtime.ObjectAllocator;
13
14
  import org.jruby.runtime.ThreadContext;
@@ -16,6 +17,10 @@ import org.jruby.runtime.builtin.IRubyObject;
16
17
  import org.jruby.anno.JRubyMethod;
17
18
  import org.jruby.exceptions.RaiseException;
18
19
 
20
+ import org.jruby.util.ByteList;
21
+
22
+ import org.jcodings.specific.UTF8Encoding;
23
+
19
24
  import java.nio.ByteBuffer;
20
25
  import http_parser.*;
21
26
  import http_parser.lolevel.ParserSettings;
@@ -24,6 +29,11 @@ import http_parser.lolevel.HTTPDataCallback;
24
29
 
25
30
  public class RubyHttpParser extends RubyObject {
26
31
 
32
+ @JRubyMethod(name = "strict?", module = true)
33
+ public static IRubyObject strict(IRubyObject recv) {
34
+ return recv.getRuntime().newBoolean(true);
35
+ }
36
+
27
37
  public static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
28
38
  public IRubyObject allocate(Ruby runtime, RubyClass klass) {
29
39
  return new RubyHttpParser(runtime, klass);
@@ -65,8 +75,10 @@ public class RubyHttpParser extends RubyObject {
65
75
 
66
76
  private IRubyObject callback_object;
67
77
 
68
- private String _current_header;
69
- private String _last_header;
78
+ private boolean completed;
79
+
80
+ private byte[] _current_header;
81
+ private byte[] _last_header;
70
82
 
71
83
  public RubyHttpParser(final Ruby runtime, RubyClass clazz) {
72
84
  super(runtime,clazz);
@@ -81,6 +93,8 @@ public class RubyHttpParser extends RubyObject {
81
93
 
82
94
  this.callback_object = null;
83
95
 
96
+ this.completed = false;
97
+
84
98
  this.header_value_type = runtime.getModule("HTTP").getClass("Parser").getInstanceVariable("@default_header_value_type");
85
99
 
86
100
  initSettings();
@@ -93,28 +107,7 @@ public class RubyHttpParser extends RubyObject {
93
107
  this.settings.on_url = new HTTPDataCallback() {
94
108
  public int cb (http_parser.lolevel.HTTPParser p, ByteBuffer buf, int pos, int len) {
95
109
  byte[] data = fetchBytes(buf, pos, len);
96
- ((RubyString)requestUrl).concat(runtime.newString(new String(data)));
97
- return 0;
98
- }
99
- };
100
- this.settings.on_path = new HTTPDataCallback() {
101
- public int cb (http_parser.lolevel.HTTPParser p, ByteBuffer buf, int pos, int len) {
102
- byte[] data = fetchBytes(buf, pos, len);
103
- ((RubyString)requestPath).concat(runtime.newString(new String(data)));
104
- return 0;
105
- }
106
- };
107
- this.settings.on_query_string = new HTTPDataCallback() {
108
- public int cb (http_parser.lolevel.HTTPParser p, ByteBuffer buf, int pos, int len) {
109
- byte[] data = fetchBytes(buf, pos, len);
110
- ((RubyString)queryString).concat(runtime.newString(new String(data)));
111
- return 0;
112
- }
113
- };
114
- this.settings.on_fragment = new HTTPDataCallback() {
115
- public int cb (http_parser.lolevel.HTTPParser p, ByteBuffer buf, int pos, int len) {
116
- byte[] data = fetchBytes(buf, pos, len);
117
- ((RubyString)fragment).concat(runtime.newString(new String(data)));
110
+ ((RubyString)requestUrl).cat(data);
118
111
  return 0;
119
112
  }
120
113
  };
@@ -124,13 +117,21 @@ public class RubyHttpParser extends RubyObject {
124
117
  byte[] data = fetchBytes(buf, pos, len);
125
118
 
126
119
  if (_current_header == null)
127
- _current_header = new String(data);
128
- else
129
- _current_header = _current_header.concat(new String(data));
120
+ _current_header = data;
121
+ else {
122
+ byte[] tmp = new byte[_current_header.length + data.length];
123
+ System.arraycopy(_current_header, 0, tmp, 0, _current_header.length);
124
+ System.arraycopy(data, 0, tmp, _current_header.length, data.length);
125
+ _current_header = tmp;
126
+ }
130
127
 
131
128
  return 0;
132
129
  }
133
130
  };
131
+ final RubySymbol arraysSym = runtime.newSymbol("arrays");
132
+ final RubySymbol mixedSym = runtime.newSymbol("mixed");
133
+ final RubySymbol stopSym = runtime.newSymbol("stop");
134
+ final RubySymbol resetSym = runtime.newSymbol("reset");
134
135
  this.settings.on_header_value = new HTTPDataCallback() {
135
136
  public int cb (http_parser.lolevel.HTTPParser p, ByteBuffer buf, int pos, int len) {
136
137
  byte[] data = fetchBytes(buf, pos, len);
@@ -144,27 +145,27 @@ public class RubyHttpParser extends RubyObject {
144
145
  _current_header = null;
145
146
  }
146
147
 
147
- key = (IRubyObject)runtime.newString(_last_header);
148
+ key = RubyString.newString(runtime, new ByteList(_last_header, UTF8Encoding.INSTANCE, false));
148
149
  val = headers.op_aref(context, key);
149
150
 
150
151
  if (new_field == 1) {
151
152
  if (val.isNil()) {
152
- if (header_value_type == runtime.newSymbol("arrays")) {
153
- headers.op_aset(context, key, RubyArray.newArrayLight(runtime, runtime.newString("")));
153
+ if (header_value_type == arraysSym) {
154
+ headers.op_aset(context, key, RubyArray.newArrayLight(runtime, RubyString.newStringLight(runtime, 10)));
154
155
  } else {
155
- headers.op_aset(context, key, runtime.newString(""));
156
+ headers.op_aset(context, key, RubyString.newStringLight(runtime, 10));
156
157
  }
157
158
  } else {
158
- if (header_value_type == runtime.newSymbol("mixed")) {
159
+ if (header_value_type == mixedSym) {
159
160
  if (val instanceof RubyString) {
160
- headers.op_aset(context, key, RubyArray.newArrayLight(runtime, val, runtime.newString("")));
161
+ headers.op_aset(context, key, RubyArray.newArrayLight(runtime, val, RubyString.newStringLight(runtime, 10)));
161
162
  } else {
162
- ((RubyArray)val).add(runtime.newString(""));
163
+ ((RubyArray)val).add(RubyString.newStringLight(runtime, 10));
163
164
  }
164
- } else if (header_value_type == runtime.newSymbol("arrays")) {
165
- ((RubyArray)val).add(runtime.newString(""));
165
+ } else if (header_value_type == arraysSym) {
166
+ ((RubyArray)val).add(RubyString.newStringLight(runtime, 10));
166
167
  } else {
167
- ((RubyString)val).cat(", ".getBytes());
168
+ ((RubyString)val).cat(',').cat(' ');
168
169
  }
169
170
  }
170
171
  val = headers.op_aref(context, key);
@@ -184,17 +185,17 @@ public class RubyHttpParser extends RubyObject {
184
185
  public int cb (http_parser.lolevel.HTTPParser p) {
185
186
  headers = new RubyHash(runtime);
186
187
 
187
- requestUrl = runtime.newString("");
188
- requestPath = runtime.newString("");
189
- queryString = runtime.newString("");
190
- fragment = runtime.newString("");
188
+ requestUrl = RubyString.newEmptyString(runtime);
189
+ requestPath = RubyString.newEmptyString(runtime);
190
+ queryString = RubyString.newEmptyString(runtime);
191
+ fragment = RubyString.newEmptyString(runtime);
191
192
 
192
- upgradeData = runtime.newString("");
193
+ upgradeData = RubyString.newEmptyString(runtime);
193
194
 
194
195
  IRubyObject ret = runtime.getNil();
195
196
 
196
197
  if (callback_object != null) {
197
- if (((RubyObject)callback_object).respond_to_p(runtime.newSymbol("on_message_begin")).toJava(Boolean.class) == Boolean.TRUE) {
198
+ if (((RubyObject)callback_object).respondsTo("on_message_begin")) {
198
199
  ThreadContext context = callback_object.getRuntime().getCurrentContext();
199
200
  ret = callback_object.callMethod(context, "on_message_begin");
200
201
  }
@@ -203,7 +204,7 @@ public class RubyHttpParser extends RubyObject {
203
204
  ret = on_message_begin.callMethod(context, "call");
204
205
  }
205
206
 
206
- if (ret == runtime.newSymbol("stop")) {
207
+ if (ret == stopSym) {
207
208
  throw new StopException();
208
209
  } else {
209
210
  return 0;
@@ -214,8 +215,10 @@ public class RubyHttpParser extends RubyObject {
214
215
  public int cb (http_parser.lolevel.HTTPParser p) {
215
216
  IRubyObject ret = runtime.getNil();
216
217
 
218
+ completed = true;
219
+
217
220
  if (callback_object != null) {
218
- if (((RubyObject)callback_object).respond_to_p(runtime.newSymbol("on_message_complete")).toJava(Boolean.class) == Boolean.TRUE) {
221
+ if (((RubyObject)callback_object).respondsTo("on_message_complete")) {
219
222
  ThreadContext context = callback_object.getRuntime().getCurrentContext();
220
223
  ret = callback_object.callMethod(context, "on_message_complete");
221
224
  }
@@ -224,7 +227,7 @@ public class RubyHttpParser extends RubyObject {
224
227
  ret = on_message_complete.callMethod(context, "call");
225
228
  }
226
229
 
227
- if (ret == runtime.newSymbol("stop")) {
230
+ if (ret == stopSym) {
228
231
  throw new StopException();
229
232
  } else {
230
233
  return 0;
@@ -236,7 +239,7 @@ public class RubyHttpParser extends RubyObject {
236
239
  IRubyObject ret = runtime.getNil();
237
240
 
238
241
  if (callback_object != null) {
239
- if (((RubyObject)callback_object).respond_to_p(runtime.newSymbol("on_headers_complete")).toJava(Boolean.class) == Boolean.TRUE) {
242
+ if (((RubyObject)callback_object).respondsTo("on_headers_complete")) {
240
243
  ThreadContext context = callback_object.getRuntime().getCurrentContext();
241
244
  ret = callback_object.callMethod(context, "on_headers_complete", headers);
242
245
  }
@@ -245,8 +248,10 @@ public class RubyHttpParser extends RubyObject {
245
248
  ret = on_headers_complete.callMethod(context, "call", headers);
246
249
  }
247
250
 
248
- if (ret == runtime.newSymbol("stop")) {
251
+ if (ret == stopSym) {
249
252
  throw new StopException();
253
+ } else if (ret == resetSym) {
254
+ return 1;
250
255
  } else {
251
256
  return 0;
252
257
  }
@@ -258,16 +263,16 @@ public class RubyHttpParser extends RubyObject {
258
263
  byte[] data = fetchBytes(buf, pos, len);
259
264
 
260
265
  if (callback_object != null) {
261
- if (((RubyObject)callback_object).respond_to_p(runtime.newSymbol("on_body")).toJava(Boolean.class) == Boolean.TRUE) {
266
+ if (((RubyObject)callback_object).respondsTo("on_body")) {
262
267
  ThreadContext context = callback_object.getRuntime().getCurrentContext();
263
- ret = callback_object.callMethod(context, "on_body", callback_object.getRuntime().newString(new String(data)));
268
+ ret = callback_object.callMethod(context, "on_body", RubyString.newString(runtime, new ByteList(data, UTF8Encoding.INSTANCE, false)));
264
269
  }
265
270
  } else if (on_body != null) {
266
271
  ThreadContext context = on_body.getRuntime().getCurrentContext();
267
- ret = on_body.callMethod(context, "call", on_body.getRuntime().newString(new String(data)));
272
+ ret = on_body.callMethod(context, "call", RubyString.newString(runtime, new ByteList(data, UTF8Encoding.INSTANCE, false)));
268
273
  }
269
274
 
270
- if (ret == runtime.newSymbol("stop")) {
275
+ if (ret == stopSym) {
271
276
  throw new StopException();
272
277
  } else {
273
278
  return 0;
@@ -278,6 +283,7 @@ public class RubyHttpParser extends RubyObject {
278
283
 
279
284
  private void init() {
280
285
  this.parser = new HTTPParser();
286
+ this.parser.HTTP_PARSER_STRICT = true;
281
287
  this.headers = null;
282
288
 
283
289
  this.requestUrl = runtime.getNil();
@@ -332,7 +338,8 @@ public class RubyHttpParser extends RubyObject {
332
338
  @JRubyMethod(name = "<<")
333
339
  public IRubyObject execute(IRubyObject data) {
334
340
  RubyString str = (RubyString)data;
335
- ByteBuffer buf = ByteBuffer.wrap(str.getBytes());
341
+ ByteList byteList = str.getByteList();
342
+ ByteBuffer buf = ByteBuffer.wrap(byteList.getUnsafeBytes(), byteList.getBegin(), byteList.getRealSize());
336
343
  boolean stopped = false;
337
344
 
338
345
  try {
@@ -345,9 +352,9 @@ public class RubyHttpParser extends RubyObject {
345
352
 
346
353
  if (parser.getUpgrade()) {
347
354
  byte[] upData = fetchBytes(buf, buf.position(), buf.limit() - buf.position());
348
- ((RubyString)upgradeData).concat(runtime.newString(new String(upData)));
355
+ ((RubyString)upgradeData).cat(upData);
349
356
 
350
- } else if (buf.hasRemaining()) {
357
+ } else if (buf.hasRemaining() && !completed) {
351
358
  if (!stopped)
352
359
  throw new RaiseException(runtime, eParserError, "Could not parse data entirely", true);
353
360
  }
@@ -357,12 +364,12 @@ public class RubyHttpParser extends RubyObject {
357
364
 
358
365
  @JRubyMethod(name = "keep_alive?")
359
366
  public IRubyObject shouldKeepAlive() {
360
- return parser.shouldKeepAlive() ? runtime.getTrue() : runtime.getFalse();
367
+ return runtime.newBoolean(parser.shouldKeepAlive());
361
368
  }
362
369
 
363
370
  @JRubyMethod(name = "upgrade?")
364
371
  public IRubyObject shouldUpgrade() {
365
- return parser.getUpgrade() ? runtime.getTrue() : runtime.getFalse();
372
+ return runtime.newBoolean(parser.getUpgrade());
366
373
  }
367
374
 
368
375
  @JRubyMethod(name = "http_major")
@@ -439,7 +446,8 @@ public class RubyHttpParser extends RubyObject {
439
446
 
440
447
  @JRubyMethod(name = "header_value_type=")
441
448
  public IRubyObject set_header_value_type(IRubyObject val) {
442
- if (val != runtime.newSymbol("mixed") && val != runtime.newSymbol("arrays") && val != runtime.newSymbol("strings")) {
449
+ String valString = val.toString();
450
+ if (valString != "mixed" && valString != "arrays" && valString != "strings") {
443
451
  throw runtime.newArgumentError("Invalid header value type");
444
452
  }
445
453
  header_value_type = val;