http_parser.rb 0.5.3-java → 0.6.0.beta.2-java
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.
- data/.gitmodules +3 -3
- data/Gemfile +1 -1
- data/Gemfile.lock +14 -5
- data/README.md +50 -45
- data/bench/standalone.rb +23 -0
- data/bench/thin.rb +1 -0
- data/ext/ruby_http_parser/org/ruby_http_parser/RubyHttpParser.java +120 -85
- data/ext/ruby_http_parser/ruby_http_parser.c +10 -41
- data/ext/ruby_http_parser/vendor/http-parser-java/AUTHORS +32 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/LICENSE-MIT +5 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/README.md +133 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/TODO +6 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.c +1202 -671
- data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.gyp +79 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/http_parser.h +172 -51
- data/ext/ruby_http_parser/vendor/http-parser-java/src/Http-parser.java.iml +22 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/FieldData.java +41 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPMethod.java +8 -3
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/HTTPParserUrl.java +76 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/ParserSettings.java +35 -102
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/Util.java +6 -6
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/HTTPParser.java +775 -682
- data/ext/ruby_http_parser/vendor/http-parser-java/src/impl/http_parser/lolevel/ParserSettings.java +8 -4
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Message.java +70 -20
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/ParseUrl.java +51 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Requests.java +1 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Responses.java +1 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Test.java +2 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestHeaderOverflowError.java +1 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestLoaderNG.java +6 -17
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/TestNoOverflowLongBody.java +1 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/UnitTest.java +1 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Upgrade.java +1 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Url.java +127 -0
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/Util.java +80 -9
- data/ext/ruby_http_parser/vendor/http-parser-java/src/test/http_parser/lolevel/WrongContentLength.java +2 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/test.c +1637 -280
- data/ext/ruby_http_parser/vendor/http-parser-java/tests.dumped +230 -71
- data/ext/ruby_http_parser/vendor/http-parser/AUTHORS +32 -0
- data/ext/ruby_http_parser/vendor/http-parser/LICENSE-MIT +5 -1
- data/ext/ruby_http_parser/vendor/http-parser/README.md +9 -2
- data/ext/ruby_http_parser/vendor/http-parser/http_parser.c +1029 -615
- data/ext/ruby_http_parser/vendor/http-parser/http_parser.gyp +79 -0
- data/ext/ruby_http_parser/vendor/http-parser/http_parser.h +145 -16
- data/ext/ruby_http_parser/vendor/http-parser/test.c +1065 -141
- data/http_parser.rb.gemspec +3 -1
- data/spec/parser_spec.rb +41 -17
- data/spec/support/requests.json +236 -24
- data/spec/support/responses.json +182 -36
- data/tasks/compile.rake +2 -2
- data/tasks/fixtures.rake +7 -1
- metadata +213 -162
- data/ext/ruby_http_parser/vendor/http-parser-java/compile +0 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/test_permutations +0 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/test_unit +0 -1
- data/ext/ruby_http_parser/vendor/http-parser-java/test_utf8 +0 -1
data/.gitmodules
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
[submodule "
|
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 "
|
4
|
+
[submodule "http-parser-java"]
|
5
5
|
path = ext/ruby_http_parser/vendor/http-parser-java
|
6
|
-
url = git://github.com/
|
6
|
+
url = git://github.com/tmm1/http-parser.java
|
data/Gemfile
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
source
|
1
|
+
source 'https://rubygems.org'
|
2
2
|
gemspec
|
data/Gemfile.lock
CHANGED
@@ -1,13 +1,20 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
http_parser.rb (0.
|
4
|
+
http_parser.rb (0.6.0.beta.2)
|
5
5
|
|
6
6
|
GEM
|
7
|
-
remote:
|
7
|
+
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
+
benchmark_suite (0.8.0)
|
10
|
+
bouncy-castle-java (1.5.0147)
|
9
11
|
diff-lcs (1.1.2)
|
10
|
-
|
12
|
+
ffi (1.0.11)
|
13
|
+
ffi (1.0.11-java)
|
14
|
+
jruby-openssl (0.8.8)
|
15
|
+
bouncy-castle-java (>= 1.5.0147)
|
16
|
+
json (1.8.0)
|
17
|
+
json (1.8.0-java)
|
11
18
|
rake (0.9.2)
|
12
19
|
rake-compiler (0.7.9)
|
13
20
|
rake
|
@@ -19,14 +26,16 @@ GEM
|
|
19
26
|
rspec-expectations (2.4.0)
|
20
27
|
diff-lcs (~> 1.1.2)
|
21
28
|
rspec-mocks (2.4.0)
|
22
|
-
yajl-ruby (0.8.2)
|
23
29
|
|
24
30
|
PLATFORMS
|
31
|
+
java
|
25
32
|
ruby
|
26
33
|
|
27
34
|
DEPENDENCIES
|
35
|
+
benchmark_suite
|
36
|
+
ffi
|
28
37
|
http_parser.rb!
|
38
|
+
jruby-openssl
|
29
39
|
json (>= 1.4.6)
|
30
40
|
rake-compiler (>= 0.7.9)
|
31
41
|
rspec (>= 2.0.1)
|
32
|
-
yajl-ruby (>= 0.8.1)
|
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
|
-
|
19
|
+
```ruby
|
20
|
+
require "http/parser"
|
20
21
|
|
21
|
-
|
22
|
+
parser = Http::Parser.new
|
22
23
|
|
23
|
-
|
24
|
-
|
24
|
+
parser.on_headers_complete = proc do
|
25
|
+
p parser.http_version
|
25
26
|
|
26
|
-
|
27
|
-
|
27
|
+
p parser.http_method # for requests
|
28
|
+
p parser.request_url
|
28
29
|
|
29
|
-
|
30
|
+
p parser.status_code # for responses
|
30
31
|
|
31
|
-
|
32
|
-
|
32
|
+
p parser.headers
|
33
|
+
end
|
33
34
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
35
|
+
parser.on_body = proc do |chunk|
|
36
|
+
# One chunk of the body
|
37
|
+
p chunk
|
38
|
+
end
|
38
39
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
40
|
+
parser.on_message_complete = proc do |env|
|
41
|
+
# Headers and body is all parsed
|
42
|
+
puts "Done!"
|
43
|
+
end
|
44
|
+
```
|
43
45
|
|
44
|
-
|
45
|
-
|
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
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
53
|
+
```ruby
|
54
|
+
module MyHttpConnection
|
55
|
+
def connection_completed
|
56
|
+
@parser = Http::Parser.new(self)
|
57
|
+
end
|
55
58
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
+
def receive_data(data)
|
60
|
+
@parser << data
|
61
|
+
end
|
59
62
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
63
|
+
def on_message_begin
|
64
|
+
@headers = nil
|
65
|
+
@body = ''
|
66
|
+
end
|
64
67
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
+
def on_headers_complete(headers)
|
69
|
+
@headers = headers
|
70
|
+
end
|
68
71
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
+
def on_body(chunk)
|
73
|
+
@body << chunk
|
74
|
+
end
|
72
75
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
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
|
-
|
81
|
-
|
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
|
+
```
|
data/bench/standalone.rb
ADDED
@@ -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
|
data/bench/thin.rb
CHANGED
@@ -1,36 +1,45 @@
|
|
1
1
|
package org.ruby_http_parser;
|
2
2
|
|
3
|
+
import http_parser.HTTPException;
|
4
|
+
import http_parser.HTTPMethod;
|
5
|
+
import http_parser.HTTPParser;
|
6
|
+
import http_parser.lolevel.HTTPCallback;
|
7
|
+
import http_parser.lolevel.HTTPDataCallback;
|
8
|
+
import http_parser.lolevel.ParserSettings;
|
9
|
+
|
10
|
+
import java.nio.ByteBuffer;
|
11
|
+
|
12
|
+
import org.jcodings.Encoding;
|
13
|
+
import org.jcodings.specific.UTF8Encoding;
|
3
14
|
import org.jruby.Ruby;
|
4
15
|
import org.jruby.RubyArray;
|
5
16
|
import org.jruby.RubyClass;
|
6
17
|
import org.jruby.RubyHash;
|
7
|
-
import org.jruby.RubyModule;
|
8
18
|
import org.jruby.RubyNumeric;
|
9
19
|
import org.jruby.RubyObject;
|
10
20
|
import org.jruby.RubyString;
|
11
|
-
|
21
|
+
import org.jruby.RubySymbol;
|
22
|
+
import org.jruby.anno.JRubyMethod;
|
23
|
+
import org.jruby.exceptions.RaiseException;
|
12
24
|
import org.jruby.runtime.ObjectAllocator;
|
13
25
|
import org.jruby.runtime.ThreadContext;
|
14
26
|
import org.jruby.runtime.builtin.IRubyObject;
|
15
|
-
|
16
|
-
import org.jruby.anno.JRubyMethod;
|
17
|
-
import org.jruby.exceptions.RaiseException;
|
18
|
-
|
19
|
-
import java.nio.ByteBuffer;
|
20
|
-
import http_parser.*;
|
21
|
-
import http_parser.lolevel.ParserSettings;
|
22
|
-
import http_parser.lolevel.HTTPCallback;
|
23
|
-
import http_parser.lolevel.HTTPDataCallback;
|
27
|
+
import org.jruby.util.ByteList;
|
24
28
|
|
25
29
|
public class RubyHttpParser extends RubyObject {
|
26
30
|
|
31
|
+
@JRubyMethod(name = "strict?", module = true)
|
32
|
+
public static IRubyObject strict(IRubyObject recv) {
|
33
|
+
return recv.getRuntime().newBoolean(true);
|
34
|
+
}
|
35
|
+
|
27
36
|
public static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
|
28
37
|
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
|
29
38
|
return new RubyHttpParser(runtime, klass);
|
30
39
|
}
|
31
40
|
};
|
32
41
|
|
33
|
-
byte[] fetchBytes
|
42
|
+
byte[] fetchBytes(ByteBuffer b, int pos, int len) {
|
34
43
|
byte[] by = new byte[len];
|
35
44
|
int saved = b.position();
|
36
45
|
b.position(pos);
|
@@ -65,14 +74,18 @@ public class RubyHttpParser extends RubyObject {
|
|
65
74
|
|
66
75
|
private IRubyObject callback_object;
|
67
76
|
|
68
|
-
private
|
69
|
-
|
77
|
+
private boolean completed;
|
78
|
+
|
79
|
+
private byte[] _current_header;
|
80
|
+
private byte[] _last_header;
|
81
|
+
|
82
|
+
private static final Encoding UTF8 = UTF8Encoding.INSTANCE;
|
70
83
|
|
71
84
|
public RubyHttpParser(final Ruby runtime, RubyClass clazz) {
|
72
|
-
super(runtime,clazz);
|
85
|
+
super(runtime, clazz);
|
73
86
|
|
74
87
|
this.runtime = runtime;
|
75
|
-
this.eParserError = (RubyClass)runtime.getModule("HTTP").getClass("Parser").getConstant("Error");
|
88
|
+
this.eParserError = (RubyClass) runtime.getModule("HTTP").getClass("Parser").getConstant("Error");
|
76
89
|
|
77
90
|
this.on_message_begin = null;
|
78
91
|
this.on_headers_complete = null;
|
@@ -81,7 +94,10 @@ public class RubyHttpParser extends RubyObject {
|
|
81
94
|
|
82
95
|
this.callback_object = null;
|
83
96
|
|
84
|
-
this.
|
97
|
+
this.completed = false;
|
98
|
+
|
99
|
+
this.header_value_type = runtime.getModule("HTTP").getClass("Parser")
|
100
|
+
.getInstanceVariable("@default_header_value_type");
|
85
101
|
|
86
102
|
initSettings();
|
87
103
|
init();
|
@@ -91,48 +107,39 @@ public class RubyHttpParser extends RubyObject {
|
|
91
107
|
this.settings = new ParserSettings();
|
92
108
|
|
93
109
|
this.settings.on_url = new HTTPDataCallback() {
|
94
|
-
public int cb
|
110
|
+
public int cb(http_parser.lolevel.HTTPParser p, ByteBuffer buf, int pos, int len) {
|
95
111
|
byte[] data = fetchBytes(buf, pos, len);
|
96
|
-
((
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
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)));
|
112
|
+
if (runtime.is1_9() || runtime.is2_0()) {
|
113
|
+
((RubyString) requestUrl).cat(data, 0, data.length, UTF8);
|
114
|
+
} else {
|
115
|
+
((RubyString) requestUrl).cat(data);
|
116
|
+
}
|
118
117
|
return 0;
|
119
118
|
}
|
120
119
|
};
|
121
120
|
|
122
121
|
this.settings.on_header_field = new HTTPDataCallback() {
|
123
|
-
public int cb
|
122
|
+
public int cb(http_parser.lolevel.HTTPParser p, ByteBuffer buf, int pos, int len) {
|
124
123
|
byte[] data = fetchBytes(buf, pos, len);
|
125
124
|
|
126
125
|
if (_current_header == null)
|
127
|
-
_current_header =
|
128
|
-
else
|
129
|
-
|
126
|
+
_current_header = data;
|
127
|
+
else {
|
128
|
+
byte[] tmp = new byte[_current_header.length + data.length];
|
129
|
+
System.arraycopy(_current_header, 0, tmp, 0, _current_header.length);
|
130
|
+
System.arraycopy(data, 0, tmp, _current_header.length, data.length);
|
131
|
+
_current_header = tmp;
|
132
|
+
}
|
130
133
|
|
131
134
|
return 0;
|
132
135
|
}
|
133
136
|
};
|
137
|
+
final RubySymbol arraysSym = runtime.newSymbol("arrays");
|
138
|
+
final RubySymbol mixedSym = runtime.newSymbol("mixed");
|
139
|
+
final RubySymbol stopSym = runtime.newSymbol("stop");
|
140
|
+
final RubySymbol resetSym = runtime.newSymbol("reset");
|
134
141
|
this.settings.on_header_value = new HTTPDataCallback() {
|
135
|
-
public int cb
|
142
|
+
public int cb(http_parser.lolevel.HTTPParser p, ByteBuffer buf, int pos, int len) {
|
136
143
|
byte[] data = fetchBytes(buf, pos, len);
|
137
144
|
ThreadContext context = headers.getRuntime().getCurrentContext();
|
138
145
|
IRubyObject key, val;
|
@@ -144,57 +151,74 @@ public class RubyHttpParser extends RubyObject {
|
|
144
151
|
_current_header = null;
|
145
152
|
}
|
146
153
|
|
147
|
-
key =
|
154
|
+
key = RubyString.newString(runtime, new ByteList(_last_header, UTF8, false));
|
148
155
|
val = headers.op_aref(context, key);
|
149
156
|
|
150
157
|
if (new_field == 1) {
|
151
158
|
if (val.isNil()) {
|
152
|
-
if (header_value_type ==
|
153
|
-
headers.op_aset(context, key,
|
159
|
+
if (header_value_type == arraysSym) {
|
160
|
+
headers.op_aset(context, key,
|
161
|
+
RubyArray.newArrayLight(runtime, RubyString.newStringLight(runtime, 10, UTF8)));
|
154
162
|
} else {
|
155
|
-
headers.op_aset(context, key,
|
163
|
+
headers.op_aset(context, key, RubyString.newStringLight(runtime, 10, UTF8));
|
156
164
|
}
|
157
165
|
} else {
|
158
|
-
if (header_value_type ==
|
166
|
+
if (header_value_type == mixedSym) {
|
159
167
|
if (val instanceof RubyString) {
|
160
|
-
headers.op_aset(context, key,
|
168
|
+
headers.op_aset(context, key,
|
169
|
+
RubyArray.newArrayLight(runtime, val, RubyString.newStringLight(runtime, 10, UTF8)));
|
161
170
|
} else {
|
162
|
-
((RubyArray)val).add(
|
171
|
+
((RubyArray) val).add(RubyString.newStringLight(runtime, 10, UTF8));
|
163
172
|
}
|
164
|
-
} else if (header_value_type ==
|
165
|
-
((RubyArray)val).add(
|
173
|
+
} else if (header_value_type == arraysSym) {
|
174
|
+
((RubyArray) val).add(RubyString.newStringLight(runtime, 10, UTF8));
|
166
175
|
} else {
|
167
|
-
((
|
176
|
+
if (runtime.is1_9() || runtime.is2_0()) {
|
177
|
+
((RubyString) val).cat(',', UTF8).cat(' ', UTF8);
|
178
|
+
} else {
|
179
|
+
((RubyString) val).cat(',').cat(' ');
|
180
|
+
}
|
168
181
|
}
|
169
182
|
}
|
170
183
|
val = headers.op_aref(context, key);
|
171
184
|
}
|
172
185
|
|
173
186
|
if (val instanceof RubyArray) {
|
174
|
-
val = ((RubyArray)val).entry(-1);
|
187
|
+
val = ((RubyArray) val).entry(-1);
|
175
188
|
}
|
176
189
|
|
177
|
-
((
|
190
|
+
if (runtime.is1_9() || runtime.is2_0()) {
|
191
|
+
((RubyString) val).cat(data, 0, data.length, UTF8);
|
192
|
+
} else {
|
193
|
+
((RubyString) val).cat(data);
|
194
|
+
}
|
178
195
|
|
179
196
|
return 0;
|
180
197
|
}
|
181
198
|
};
|
182
199
|
|
183
200
|
this.settings.on_message_begin = new HTTPCallback() {
|
184
|
-
public int cb
|
201
|
+
public int cb(http_parser.lolevel.HTTPParser p) {
|
185
202
|
headers = new RubyHash(runtime);
|
186
203
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
204
|
+
if (runtime.is1_9() || runtime.is2_0()) {
|
205
|
+
requestUrl = RubyString.newEmptyString(runtime, UTF8);
|
206
|
+
requestPath = RubyString.newEmptyString(runtime, UTF8);
|
207
|
+
queryString = RubyString.newEmptyString(runtime, UTF8);
|
208
|
+
fragment = RubyString.newEmptyString(runtime, UTF8);
|
209
|
+
upgradeData = RubyString.newEmptyString(runtime, UTF8);
|
210
|
+
} else {
|
211
|
+
requestUrl = RubyString.newEmptyString(runtime);
|
212
|
+
requestPath = RubyString.newEmptyString(runtime);
|
213
|
+
queryString = RubyString.newEmptyString(runtime);
|
214
|
+
fragment = RubyString.newEmptyString(runtime);
|
215
|
+
upgradeData = RubyString.newEmptyString(runtime);
|
216
|
+
}
|
193
217
|
|
194
218
|
IRubyObject ret = runtime.getNil();
|
195
219
|
|
196
220
|
if (callback_object != null) {
|
197
|
-
if (((RubyObject)callback_object).
|
221
|
+
if (((RubyObject) callback_object).respondsTo("on_message_begin")) {
|
198
222
|
ThreadContext context = callback_object.getRuntime().getCurrentContext();
|
199
223
|
ret = callback_object.callMethod(context, "on_message_begin");
|
200
224
|
}
|
@@ -203,7 +227,7 @@ public class RubyHttpParser extends RubyObject {
|
|
203
227
|
ret = on_message_begin.callMethod(context, "call");
|
204
228
|
}
|
205
229
|
|
206
|
-
if (ret ==
|
230
|
+
if (ret == stopSym) {
|
207
231
|
throw new StopException();
|
208
232
|
} else {
|
209
233
|
return 0;
|
@@ -211,11 +235,13 @@ public class RubyHttpParser extends RubyObject {
|
|
211
235
|
}
|
212
236
|
};
|
213
237
|
this.settings.on_message_complete = new HTTPCallback() {
|
214
|
-
public int cb
|
238
|
+
public int cb(http_parser.lolevel.HTTPParser p) {
|
215
239
|
IRubyObject ret = runtime.getNil();
|
216
240
|
|
241
|
+
completed = true;
|
242
|
+
|
217
243
|
if (callback_object != null) {
|
218
|
-
if (((RubyObject)callback_object).
|
244
|
+
if (((RubyObject) callback_object).respondsTo("on_message_complete")) {
|
219
245
|
ThreadContext context = callback_object.getRuntime().getCurrentContext();
|
220
246
|
ret = callback_object.callMethod(context, "on_message_complete");
|
221
247
|
}
|
@@ -224,7 +250,7 @@ public class RubyHttpParser extends RubyObject {
|
|
224
250
|
ret = on_message_complete.callMethod(context, "call");
|
225
251
|
}
|
226
252
|
|
227
|
-
if (ret ==
|
253
|
+
if (ret == stopSym) {
|
228
254
|
throw new StopException();
|
229
255
|
} else {
|
230
256
|
return 0;
|
@@ -232,11 +258,11 @@ public class RubyHttpParser extends RubyObject {
|
|
232
258
|
}
|
233
259
|
};
|
234
260
|
this.settings.on_headers_complete = new HTTPCallback() {
|
235
|
-
public int cb
|
261
|
+
public int cb(http_parser.lolevel.HTTPParser p) {
|
236
262
|
IRubyObject ret = runtime.getNil();
|
237
263
|
|
238
264
|
if (callback_object != null) {
|
239
|
-
if (((RubyObject)callback_object).
|
265
|
+
if (((RubyObject) callback_object).respondsTo("on_headers_complete")) {
|
240
266
|
ThreadContext context = callback_object.getRuntime().getCurrentContext();
|
241
267
|
ret = callback_object.callMethod(context, "on_headers_complete", headers);
|
242
268
|
}
|
@@ -245,29 +271,32 @@ public class RubyHttpParser extends RubyObject {
|
|
245
271
|
ret = on_headers_complete.callMethod(context, "call", headers);
|
246
272
|
}
|
247
273
|
|
248
|
-
if (ret ==
|
274
|
+
if (ret == stopSym) {
|
249
275
|
throw new StopException();
|
276
|
+
} else if (ret == resetSym) {
|
277
|
+
return 1;
|
250
278
|
} else {
|
251
279
|
return 0;
|
252
280
|
}
|
253
281
|
}
|
254
282
|
};
|
255
283
|
this.settings.on_body = new HTTPDataCallback() {
|
256
|
-
public int cb
|
284
|
+
public int cb(http_parser.lolevel.HTTPParser p, ByteBuffer buf, int pos, int len) {
|
257
285
|
IRubyObject ret = runtime.getNil();
|
258
286
|
byte[] data = fetchBytes(buf, pos, len);
|
259
287
|
|
260
288
|
if (callback_object != null) {
|
261
|
-
if (((RubyObject)callback_object).
|
289
|
+
if (((RubyObject) callback_object).respondsTo("on_body")) {
|
262
290
|
ThreadContext context = callback_object.getRuntime().getCurrentContext();
|
263
|
-
ret = callback_object.callMethod(context, "on_body",
|
291
|
+
ret = callback_object.callMethod(context, "on_body",
|
292
|
+
RubyString.newString(runtime, new ByteList(data, UTF8, false)));
|
264
293
|
}
|
265
294
|
} else if (on_body != null) {
|
266
295
|
ThreadContext context = on_body.getRuntime().getCurrentContext();
|
267
|
-
ret = on_body.callMethod(context, "call",
|
296
|
+
ret = on_body.callMethod(context, "call", RubyString.newString(runtime, new ByteList(data, UTF8, false)));
|
268
297
|
}
|
269
298
|
|
270
|
-
if (ret ==
|
299
|
+
if (ret == stopSym) {
|
271
300
|
throw new StopException();
|
272
301
|
} else {
|
273
302
|
return 0;
|
@@ -278,6 +307,7 @@ public class RubyHttpParser extends RubyObject {
|
|
278
307
|
|
279
308
|
private void init() {
|
280
309
|
this.parser = new HTTPParser();
|
310
|
+
this.parser.HTTP_PARSER_STRICT = true;
|
281
311
|
this.headers = null;
|
282
312
|
|
283
313
|
this.requestUrl = runtime.getNil();
|
@@ -331,8 +361,9 @@ public class RubyHttpParser extends RubyObject {
|
|
331
361
|
|
332
362
|
@JRubyMethod(name = "<<")
|
333
363
|
public IRubyObject execute(IRubyObject data) {
|
334
|
-
RubyString str = (RubyString)data;
|
335
|
-
|
364
|
+
RubyString str = (RubyString) data;
|
365
|
+
ByteList byteList = str.getByteList();
|
366
|
+
ByteBuffer buf = ByteBuffer.wrap(byteList.getUnsafeBytes(), byteList.getBegin(), byteList.getRealSize());
|
336
367
|
boolean stopped = false;
|
337
368
|
|
338
369
|
try {
|
@@ -345,9 +376,12 @@ public class RubyHttpParser extends RubyObject {
|
|
345
376
|
|
346
377
|
if (parser.getUpgrade()) {
|
347
378
|
byte[] upData = fetchBytes(buf, buf.position(), buf.limit() - buf.position());
|
348
|
-
((
|
349
|
-
|
350
|
-
|
379
|
+
if (runtime.is1_9() || runtime.is2_0()) {
|
380
|
+
((RubyString) upgradeData).cat(upData, 0, upData.length, UTF8);
|
381
|
+
} else {
|
382
|
+
((RubyString) upgradeData).cat(upData);
|
383
|
+
}
|
384
|
+
} else if (buf.hasRemaining() && !completed) {
|
351
385
|
if (!stopped)
|
352
386
|
throw new RaiseException(runtime, eParserError, "Could not parse data entirely", true);
|
353
387
|
}
|
@@ -357,12 +391,12 @@ public class RubyHttpParser extends RubyObject {
|
|
357
391
|
|
358
392
|
@JRubyMethod(name = "keep_alive?")
|
359
393
|
public IRubyObject shouldKeepAlive() {
|
360
|
-
return parser.shouldKeepAlive()
|
394
|
+
return runtime.newBoolean(parser.shouldKeepAlive());
|
361
395
|
}
|
362
396
|
|
363
397
|
@JRubyMethod(name = "upgrade?")
|
364
398
|
public IRubyObject shouldUpgrade() {
|
365
|
-
return parser.getUpgrade()
|
399
|
+
return runtime.newBoolean(parser.getUpgrade());
|
366
400
|
}
|
367
401
|
|
368
402
|
@JRubyMethod(name = "http_major")
|
@@ -439,7 +473,8 @@ public class RubyHttpParser extends RubyObject {
|
|
439
473
|
|
440
474
|
@JRubyMethod(name = "header_value_type=")
|
441
475
|
public IRubyObject set_header_value_type(IRubyObject val) {
|
442
|
-
|
476
|
+
String valString = val.toString();
|
477
|
+
if (valString != "mixed" && valString != "arrays" && valString != "strings") {
|
443
478
|
throw runtime.newArgumentError("Invalid header value type");
|
444
479
|
}
|
445
480
|
header_value_type = val;
|