http_parser.rb 0.8.0 → 0.8.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.
- checksums.yaml +4 -4
- data/.github/workflows/linux.yml +2 -2
- data/.github/workflows/windows.yml +2 -2
- data/ext/ruby_http_parser/ext_help.h +6 -1
- data/ext/ruby_http_parser/ruby_http_parser.c +9 -1
- data/http_parser.rb.gemspec +2 -2
- data/tasks/compile.rake +1 -1
- metadata +3 -10
- data/spec/parser_spec.rb +0 -428
- data/spec/spec_helper.rb +0 -1
- data/spec/support/requests.json +0 -612
- data/spec/support/responses.json +0 -395
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7fb5f5d030bfee30671d56b87acf02da0839051af33452843cef949f11dc5f14
|
|
4
|
+
data.tar.gz: d232aab15c4758a799a6cf9c59d315ecbd814259aba71bcc609728b651841e1b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 263ea218dabc076ae0b10b8ed63d1383263a11d7c9d42539fd0e0349e78ffc9fb38a9e731f76d83367d1354e5b0c4d345d79b79be7d87327012d39a879a3f62d
|
|
7
|
+
data.tar.gz: b8118b7aa966b1be6b315c956afe8d55d633e5f5dfa8fc9a3f28e53b1b31d7d32624c905de208b29804336afe9f4ae64f52b29615c84846bbf44e326b6a60f66
|
data/.github/workflows/linux.yml
CHANGED
|
@@ -8,11 +8,11 @@ jobs:
|
|
|
8
8
|
strategy:
|
|
9
9
|
fail-fast: false
|
|
10
10
|
matrix:
|
|
11
|
-
ruby: [ '
|
|
11
|
+
ruby: [ '3.1', '3.2', '3.3', '3.4', 'head' ]
|
|
12
12
|
os: [ 'ubuntu-latest' ]
|
|
13
13
|
name: Ruby ${{ matrix.ruby }} unit testing on ${{ matrix.os }}
|
|
14
14
|
steps:
|
|
15
|
-
- uses: actions/checkout@
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
16
|
- uses: ruby/setup-ruby@v1
|
|
17
17
|
with:
|
|
18
18
|
ruby-version: ${{ matrix.ruby }}
|
|
@@ -8,11 +8,11 @@ jobs:
|
|
|
8
8
|
strategy:
|
|
9
9
|
fail-fast: false
|
|
10
10
|
matrix:
|
|
11
|
-
ruby: [ '
|
|
11
|
+
ruby: [ '3.1', '3.2', '3.3', '3.4', 'head' ]
|
|
12
12
|
os: [ 'windows-latest' ]
|
|
13
13
|
name: Ruby ${{ matrix.ruby }} unit testing on ${{ matrix.os }}
|
|
14
14
|
steps:
|
|
15
|
-
- uses: actions/checkout@
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
16
|
- uses: ruby/setup-ruby@v1
|
|
17
17
|
with:
|
|
18
18
|
ruby-version: ${{ matrix.ruby }}
|
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
#define ext_help_h
|
|
3
3
|
|
|
4
4
|
#define RAISE_NOT_NULL(T) if(T == NULL) rb_raise(rb_eArgError, "NULL found for " # T " when shouldn't be.");
|
|
5
|
-
#
|
|
5
|
+
#ifdef TypedData_Get_Struct
|
|
6
|
+
#define DATA_GET_STRUCT(from,type,name) TypedData_Get_Struct(from,type,&type##_type,name)
|
|
7
|
+
#else
|
|
8
|
+
#define DATA_GET_STRUCT(from,type,name) Data_Get_Struct(from,type,name)
|
|
9
|
+
#endif
|
|
10
|
+
#define DATA_GET(from,type,name) DATA_GET_STRUCT(from,type,name); RAISE_NOT_NULL(name);
|
|
6
11
|
#define REQUIRE_TYPE(V, T) if(TYPE(V) != T) rb_raise(rb_eTypeError, "Wrong argument type for " # V " required " # T);
|
|
7
12
|
|
|
8
13
|
/* for compatibility with Ruby 1.8.5, which doesn't declare RSTRING_PTR */
|
|
@@ -81,6 +81,14 @@ void ParserWrapper_free(void *data) {
|
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
+
static const rb_data_type_t ParserWrapper_type = {
|
|
85
|
+
"ParserWrapper",
|
|
86
|
+
{
|
|
87
|
+
ParserWrapper_mark,
|
|
88
|
+
ParserWrapper_free,
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
|
|
84
92
|
static VALUE cParser;
|
|
85
93
|
static VALUE cRequestParser;
|
|
86
94
|
static VALUE cResponseParser;
|
|
@@ -293,7 +301,7 @@ VALUE Parser_alloc_by_type(VALUE klass, enum ryah_http_parser_type type) {
|
|
|
293
301
|
|
|
294
302
|
ParserWrapper_init(wrapper);
|
|
295
303
|
|
|
296
|
-
return
|
|
304
|
+
return TypedData_Wrap_Struct(klass, &ParserWrapper_type, wrapper);
|
|
297
305
|
}
|
|
298
306
|
|
|
299
307
|
VALUE Parser_alloc(VALUE klass) {
|
data/http_parser.rb.gemspec
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Gem::Specification.new do |s|
|
|
2
2
|
s.name = "http_parser.rb"
|
|
3
|
-
s.version = "0.8.
|
|
3
|
+
s.version = "0.8.1"
|
|
4
4
|
s.summary = "Simple callback-based HTTP request/response parser"
|
|
5
5
|
s.description = "Ruby bindings to https://github.com/joyent/http-parser and https://github.com/http-parser/http-parser.java"
|
|
6
6
|
|
|
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
|
|
|
9
9
|
s.license = 'MIT'
|
|
10
10
|
|
|
11
11
|
s.homepage = "https://github.com/tmm1/http_parser.rb"
|
|
12
|
-
s.files = `git ls-files`.split("\n") + Dir['ext/ruby_http_parser/vendor/**/*']
|
|
12
|
+
s.files = `git ls-files`.split("\n").grep_v(%r{spec/}) + Dir['ext/ruby_http_parser/vendor/**/*']
|
|
13
13
|
|
|
14
14
|
s.require_paths = ["lib"]
|
|
15
15
|
s.extensions = ["ext/ruby_http_parser/extconf.rb"]
|
data/tasks/compile.rake
CHANGED
metadata
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: http_parser.rb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.8.
|
|
4
|
+
version: 0.8.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Marc-Andre Cournoyer
|
|
8
8
|
- Aman Gupta
|
|
9
|
-
autorequire:
|
|
10
9
|
bindir: bin
|
|
11
10
|
cert_chain: []
|
|
12
|
-
date:
|
|
11
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
13
12
|
dependencies:
|
|
14
13
|
- !ruby/object:Gem::Dependency
|
|
15
14
|
name: rake-compiler
|
|
@@ -182,10 +181,6 @@ files:
|
|
|
182
181
|
- http_parser.rb.gemspec
|
|
183
182
|
- lib/http/parser.rb
|
|
184
183
|
- lib/http_parser.rb
|
|
185
|
-
- spec/parser_spec.rb
|
|
186
|
-
- spec/spec_helper.rb
|
|
187
|
-
- spec/support/requests.json
|
|
188
|
-
- spec/support/responses.json
|
|
189
184
|
- tasks/compile.rake
|
|
190
185
|
- tasks/fixtures.rake
|
|
191
186
|
- tasks/spec.rake
|
|
@@ -194,7 +189,6 @@ homepage: https://github.com/tmm1/http_parser.rb
|
|
|
194
189
|
licenses:
|
|
195
190
|
- MIT
|
|
196
191
|
metadata: {}
|
|
197
|
-
post_install_message:
|
|
198
192
|
rdoc_options: []
|
|
199
193
|
require_paths:
|
|
200
194
|
- lib
|
|
@@ -209,8 +203,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
209
203
|
- !ruby/object:Gem::Version
|
|
210
204
|
version: '0'
|
|
211
205
|
requirements: []
|
|
212
|
-
rubygems_version: 3.
|
|
213
|
-
signing_key:
|
|
206
|
+
rubygems_version: 3.6.9
|
|
214
207
|
specification_version: 4
|
|
215
208
|
summary: Simple callback-based HTTP request/response parser
|
|
216
209
|
test_files: []
|
data/spec/parser_spec.rb
DELETED
|
@@ -1,428 +0,0 @@
|
|
|
1
|
-
if defined?(Encoding)
|
|
2
|
-
Encoding.default_external = "UTF-8"
|
|
3
|
-
end
|
|
4
|
-
require "spec_helper"
|
|
5
|
-
require "json"
|
|
6
|
-
|
|
7
|
-
describe HTTP::Parser do
|
|
8
|
-
before do
|
|
9
|
-
@parser = HTTP::Parser.new
|
|
10
|
-
|
|
11
|
-
@headers = nil
|
|
12
|
-
@body = ""
|
|
13
|
-
@started = false
|
|
14
|
-
@done = false
|
|
15
|
-
|
|
16
|
-
@parser.on_message_begin = proc{ @started = true }
|
|
17
|
-
@parser.on_headers_complete = proc { |e| @headers = e }
|
|
18
|
-
@parser.on_body = proc { |chunk| @body << chunk }
|
|
19
|
-
@parser.on_message_complete = proc{ @done = true }
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
it "should have initial state" do
|
|
23
|
-
expect(@parser.headers).to be_nil
|
|
24
|
-
|
|
25
|
-
expect(@parser.http_version).to be_nil
|
|
26
|
-
expect(@parser.http_method).to be_nil
|
|
27
|
-
expect(@parser.status_code).to be_nil
|
|
28
|
-
|
|
29
|
-
expect(@parser.request_url).to be_nil
|
|
30
|
-
|
|
31
|
-
expect(@parser.header_value_type).to eq(:mixed)
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
it "should be able to run in non-main ractors" do
|
|
35
|
-
skip unless Kernel.const_defined?(:Ractor)
|
|
36
|
-
default_header_value_type = HTTP::Parser.default_header_value_type
|
|
37
|
-
r = Ractor.new(default_header_value_type) { |type|
|
|
38
|
-
parser = HTTP::Parser.new(default_header_value_type: type)
|
|
39
|
-
done = false
|
|
40
|
-
parser.on_message_complete = proc {
|
|
41
|
-
done = true
|
|
42
|
-
}
|
|
43
|
-
parser <<
|
|
44
|
-
"GET /ractor HTTP/1.1\r\n" +
|
|
45
|
-
"Content-Length: 5\r\n" +
|
|
46
|
-
"\r\n" +
|
|
47
|
-
"World"
|
|
48
|
-
done
|
|
49
|
-
}
|
|
50
|
-
expect(r.take).to be true
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
it "should allow us to set the header value type" do
|
|
54
|
-
[:mixed, :arrays, :strings].each do |type|
|
|
55
|
-
@parser.header_value_type = type
|
|
56
|
-
expect(@parser.header_value_type).to eq(type)
|
|
57
|
-
|
|
58
|
-
parser_tmp = HTTP::Parser.new(nil, type)
|
|
59
|
-
expect(parser_tmp.header_value_type).to eq(type)
|
|
60
|
-
|
|
61
|
-
parser_tmp2 = HTTP::Parser.new(default_header_value_type: type)
|
|
62
|
-
expect(parser_tmp2.header_value_type).to eq(type)
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
it "should allow us to set the default header value type" do
|
|
67
|
-
[:mixed, :arrays, :strings].each do |type|
|
|
68
|
-
HTTP::Parser.default_header_value_type = type
|
|
69
|
-
|
|
70
|
-
parser = HTTP::Parser.new
|
|
71
|
-
expect(parser.header_value_type).to eq(type)
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
it "should throw an Argument Error if header value type is invalid" do
|
|
76
|
-
expect{ @parser.header_value_type = 'bob' }.to raise_error(ArgumentError)
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
it "should throw an Argument Error if default header value type is invalid" do
|
|
80
|
-
expect{ HTTP::Parser.default_header_value_type = 'bob' }.to raise_error(ArgumentError)
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
it "should implement basic api" do
|
|
84
|
-
@parser <<
|
|
85
|
-
"GET /test?ok=1 HTTP/1.1\r\n" +
|
|
86
|
-
"User-Agent: curl/7.18.0\r\n" +
|
|
87
|
-
"Host: 0.0.0.0:5000\r\n" +
|
|
88
|
-
"Accept: */*\r\n" +
|
|
89
|
-
"Content-Length: 5\r\n" +
|
|
90
|
-
"\r\n" +
|
|
91
|
-
"World"
|
|
92
|
-
|
|
93
|
-
expect(@started).to be true
|
|
94
|
-
expect(@done).to be true
|
|
95
|
-
|
|
96
|
-
expect(@parser.http_major).to eq(1)
|
|
97
|
-
expect(@parser.http_minor).to eq(1)
|
|
98
|
-
expect(@parser.http_version).to eq([1,1])
|
|
99
|
-
expect(@parser.http_method).to eq('GET')
|
|
100
|
-
expect(@parser.status_code).to be_nil
|
|
101
|
-
|
|
102
|
-
expect(@parser.request_url).to eq('/test?ok=1')
|
|
103
|
-
|
|
104
|
-
expect(@parser.headers).to eq(@headers)
|
|
105
|
-
expect(@parser.headers['User-Agent']).to eq('curl/7.18.0')
|
|
106
|
-
expect(@parser.headers['Host']).to eq('0.0.0.0:5000')
|
|
107
|
-
|
|
108
|
-
expect(@body).to eq("World")
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
it "should raise errors on invalid data" do
|
|
112
|
-
expect{ @parser << "BLAH" }.to raise_error(HTTP::Parser::Error)
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
it "should abort parser via header complete callback with a body" do
|
|
116
|
-
@parser.on_headers_complete = proc { |e| @headers = e; :stop }
|
|
117
|
-
|
|
118
|
-
data =
|
|
119
|
-
"GET / HTTP/1.0\r\n" +
|
|
120
|
-
"Content-Length: 5\r\n" +
|
|
121
|
-
"\r\n" +
|
|
122
|
-
"World"
|
|
123
|
-
|
|
124
|
-
bytes = @parser << data
|
|
125
|
-
|
|
126
|
-
expect(bytes).to eq(37)
|
|
127
|
-
expect(data[bytes..-1]).to eq('World')
|
|
128
|
-
|
|
129
|
-
expect(@headers).to eq({'Content-Length' => '5'})
|
|
130
|
-
expect(@body).to be_empty
|
|
131
|
-
expect(@done).to be false
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
it "should abort parser via header complete callback without a body" do
|
|
135
|
-
@parser.on_headers_complete = proc { |e| @headers = e; :stop }
|
|
136
|
-
|
|
137
|
-
data =
|
|
138
|
-
"GET / HTTP/1.0\r\n" +
|
|
139
|
-
"Content-Length: 0\r\n" +
|
|
140
|
-
"\r\n"
|
|
141
|
-
|
|
142
|
-
bytes = @parser << data
|
|
143
|
-
|
|
144
|
-
expect(bytes).to eq(37)
|
|
145
|
-
expect(data[bytes..-1]).to eq('')
|
|
146
|
-
|
|
147
|
-
expect(@headers).to eq({'Content-Length' => '0'})
|
|
148
|
-
expect(@body).to be_empty
|
|
149
|
-
expect(@done).to be false
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
it "should abort parser via message complete callback with a body" do
|
|
153
|
-
@parser.on_message_complete = proc { :stop }
|
|
154
|
-
|
|
155
|
-
data =
|
|
156
|
-
"CONNECT www.example.com:443 HTTP/1.0\r\n" +
|
|
157
|
-
"Connection: keep-alive\r\n" +
|
|
158
|
-
"\r\n" +
|
|
159
|
-
"World"
|
|
160
|
-
|
|
161
|
-
bytes = @parser << data
|
|
162
|
-
|
|
163
|
-
expect(bytes).to eq(64)
|
|
164
|
-
expect(data[bytes..-1]).to eq('World')
|
|
165
|
-
|
|
166
|
-
expect(@headers).to eq({'Connection' => 'keep-alive'})
|
|
167
|
-
expect(@parser.upgrade_data).to eq('World')
|
|
168
|
-
expect(@body).to be_empty
|
|
169
|
-
expect(@done).to be false
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
it "should abort parser via message complete callback without a body" do
|
|
173
|
-
@parser.on_message_complete = proc { :stop }
|
|
174
|
-
|
|
175
|
-
data =
|
|
176
|
-
"CONNECT www.example.com:443 HTTP/1.0\r\n" +
|
|
177
|
-
"Connection: keep-alive\r\n" +
|
|
178
|
-
"\r\n"
|
|
179
|
-
|
|
180
|
-
bytes = @parser << data
|
|
181
|
-
|
|
182
|
-
expect(bytes).to eq(64)
|
|
183
|
-
expect(data[bytes..-1]).to eq('')
|
|
184
|
-
|
|
185
|
-
expect(@headers).to eq({'Connection' => 'keep-alive'})
|
|
186
|
-
expect(@parser.upgrade_data).to eq('')
|
|
187
|
-
expect(@body).to be_empty
|
|
188
|
-
expect(@done).to be false
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
it "should reset to initial state" do
|
|
192
|
-
@parser << "GET / HTTP/1.0\r\n\r\n"
|
|
193
|
-
|
|
194
|
-
expect(@parser.http_method).to eq('GET')
|
|
195
|
-
expect(@parser.http_version).to eq([1,0])
|
|
196
|
-
|
|
197
|
-
expect(@parser.request_url).to eq('/')
|
|
198
|
-
|
|
199
|
-
expect(@parser.reset!).to be true
|
|
200
|
-
|
|
201
|
-
expect(@parser.http_version).to be_nil
|
|
202
|
-
expect(@parser.http_method).to be_nil
|
|
203
|
-
expect(@parser.status_code).to be_nil
|
|
204
|
-
|
|
205
|
-
expect(@parser.request_url).to be_nil
|
|
206
|
-
end
|
|
207
|
-
|
|
208
|
-
it "should optionally reset parser state on no-body responses" do
|
|
209
|
-
expect(@parser.reset!).to be true
|
|
210
|
-
|
|
211
|
-
@head, @complete = 0, 0
|
|
212
|
-
@parser.on_headers_complete = proc {|h| @head += 1; :reset }
|
|
213
|
-
@parser.on_message_complete = proc { @complete += 1 }
|
|
214
|
-
@parser.on_body = proc {|b| fail }
|
|
215
|
-
|
|
216
|
-
head_response = "HTTP/1.1 200 OK\r\nContent-Length:10\r\n\r\n"
|
|
217
|
-
|
|
218
|
-
@parser << head_response
|
|
219
|
-
expect(@head).to eq(1)
|
|
220
|
-
expect(@complete).to eq(1)
|
|
221
|
-
|
|
222
|
-
@parser << head_response
|
|
223
|
-
expect(@head).to eq(2)
|
|
224
|
-
expect(@complete).to eq(2)
|
|
225
|
-
end
|
|
226
|
-
|
|
227
|
-
it "should retain callbacks after reset" do
|
|
228
|
-
expect(@parser.reset!).to be true
|
|
229
|
-
|
|
230
|
-
@parser << "GET / HTTP/1.0\r\n\r\n"
|
|
231
|
-
expect(@started).to be true
|
|
232
|
-
expect(@headers).to eq({})
|
|
233
|
-
expect(@done).to be true
|
|
234
|
-
end
|
|
235
|
-
|
|
236
|
-
it "should parse headers incrementally" do
|
|
237
|
-
request =
|
|
238
|
-
"GET / HTTP/1.0\r\n" +
|
|
239
|
-
"Header1: value 1\r\n" +
|
|
240
|
-
"Header2: value 2\r\n" +
|
|
241
|
-
"\r\n"
|
|
242
|
-
|
|
243
|
-
while chunk = request.slice!(0,2) and !chunk.empty?
|
|
244
|
-
@parser << chunk
|
|
245
|
-
end
|
|
246
|
-
|
|
247
|
-
expect(@parser.headers).to eq({
|
|
248
|
-
'Header1' => 'value 1',
|
|
249
|
-
'Header2' => 'value 2'
|
|
250
|
-
})
|
|
251
|
-
end
|
|
252
|
-
|
|
253
|
-
it "should handle multiple headers using strings" do
|
|
254
|
-
@parser.header_value_type = :strings
|
|
255
|
-
|
|
256
|
-
@parser <<
|
|
257
|
-
"GET / HTTP/1.0\r\n" +
|
|
258
|
-
"Set-Cookie: PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com\r\n" +
|
|
259
|
-
"Set-Cookie: NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly\r\n" +
|
|
260
|
-
"\r\n"
|
|
261
|
-
|
|
262
|
-
expect(@parser.headers["Set-Cookie"]).to eq("PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com, NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly")
|
|
263
|
-
end
|
|
264
|
-
|
|
265
|
-
it "should handle multiple headers using strings" do
|
|
266
|
-
@parser.header_value_type = :arrays
|
|
267
|
-
|
|
268
|
-
@parser <<
|
|
269
|
-
"GET / HTTP/1.0\r\n" +
|
|
270
|
-
"Set-Cookie: PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com\r\n" +
|
|
271
|
-
"Set-Cookie: NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly\r\n" +
|
|
272
|
-
"\r\n"
|
|
273
|
-
|
|
274
|
-
expect(@parser.headers["Set-Cookie"]).to eq([
|
|
275
|
-
"PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com",
|
|
276
|
-
"NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly"
|
|
277
|
-
])
|
|
278
|
-
end
|
|
279
|
-
|
|
280
|
-
it "should handle multiple headers using mixed" do
|
|
281
|
-
@parser.header_value_type = :mixed
|
|
282
|
-
|
|
283
|
-
@parser <<
|
|
284
|
-
"GET / HTTP/1.0\r\n" +
|
|
285
|
-
"Set-Cookie: PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com\r\n" +
|
|
286
|
-
"Set-Cookie: NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly\r\n" +
|
|
287
|
-
"\r\n"
|
|
288
|
-
|
|
289
|
-
expect(@parser.headers["Set-Cookie"]).to eq([
|
|
290
|
-
"PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com",
|
|
291
|
-
"NID=46jSHxPM; path=/; domain=.bob.com; HttpOnly"
|
|
292
|
-
])
|
|
293
|
-
end
|
|
294
|
-
|
|
295
|
-
it "should handle a single cookie using mixed" do
|
|
296
|
-
@parser.header_value_type = :mixed
|
|
297
|
-
|
|
298
|
-
@parser <<
|
|
299
|
-
"GET / HTTP/1.0\r\n" +
|
|
300
|
-
"Set-Cookie: PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com\r\n" +
|
|
301
|
-
"\r\n"
|
|
302
|
-
|
|
303
|
-
expect(@parser.headers["Set-Cookie"]).to eq("PREF=ID=a7d2c98; expires=Fri, 05-Apr-2013 05:00:45 GMT; path=/; domain=.bob.com")
|
|
304
|
-
end
|
|
305
|
-
|
|
306
|
-
it "should support alternative api" do
|
|
307
|
-
callbacks = double('callbacks')
|
|
308
|
-
allow(callbacks).to receive(:on_message_begin){ @started = true }
|
|
309
|
-
allow(callbacks).to receive(:on_headers_complete){ |e| @headers = e }
|
|
310
|
-
allow(callbacks).to receive(:on_body){ |chunk| @body << chunk }
|
|
311
|
-
allow(callbacks).to receive(:on_message_complete){ @done = true }
|
|
312
|
-
|
|
313
|
-
@parser = HTTP::Parser.new(callbacks)
|
|
314
|
-
@parser << "GET / HTTP/1.0\r\n\r\n"
|
|
315
|
-
|
|
316
|
-
expect(@started).to be true
|
|
317
|
-
expect(@headers).to eq({})
|
|
318
|
-
expect(@body).to eq('')
|
|
319
|
-
expect(@done).to be true
|
|
320
|
-
end
|
|
321
|
-
|
|
322
|
-
it "should ignore extra content beyond specified length" do
|
|
323
|
-
@parser <<
|
|
324
|
-
"GET / HTTP/1.0\r\n" +
|
|
325
|
-
"Content-Length: 5\r\n" +
|
|
326
|
-
"\r\n" +
|
|
327
|
-
"hello" +
|
|
328
|
-
" \n"
|
|
329
|
-
|
|
330
|
-
expect(@body).to eq('hello')
|
|
331
|
-
expect(@done).to be true
|
|
332
|
-
end
|
|
333
|
-
|
|
334
|
-
it 'sets upgrade_data if available' do
|
|
335
|
-
@parser <<
|
|
336
|
-
"GET /demo HTTP/1.1\r\n" +
|
|
337
|
-
"Connection: Upgrade\r\n" +
|
|
338
|
-
"Upgrade: WebSocket\r\n\r\n" +
|
|
339
|
-
"third key data"
|
|
340
|
-
|
|
341
|
-
expect(@parser.upgrade?).to be true
|
|
342
|
-
expect(@parser.upgrade_data).to eq('third key data')
|
|
343
|
-
end
|
|
344
|
-
|
|
345
|
-
it 'sets upgrade_data to blank if un-available' do
|
|
346
|
-
@parser <<
|
|
347
|
-
"GET /demo HTTP/1.1\r\n" +
|
|
348
|
-
"Connection: Upgrade\r\n" +
|
|
349
|
-
"Upgrade: WebSocket\r\n\r\n"
|
|
350
|
-
|
|
351
|
-
expect(@parser.upgrade?).to be true
|
|
352
|
-
expect(@parser.upgrade_data).to eq('')
|
|
353
|
-
end
|
|
354
|
-
|
|
355
|
-
it 'should stop parsing headers when instructed' do
|
|
356
|
-
request = "GET /websocket HTTP/1.1\r\n" +
|
|
357
|
-
"host: localhost\r\n" +
|
|
358
|
-
"connection: Upgrade\r\n" +
|
|
359
|
-
"upgrade: websocket\r\n" +
|
|
360
|
-
"sec-websocket-key: SD6/hpYbKjQ6Sown7pBbWQ==\r\n" +
|
|
361
|
-
"sec-websocket-version: 13\r\n" +
|
|
362
|
-
"\r\n"
|
|
363
|
-
|
|
364
|
-
@parser.on_headers_complete = proc { |e| :stop }
|
|
365
|
-
offset = (@parser << request)
|
|
366
|
-
expect(@parser.upgrade?).to be true
|
|
367
|
-
expect(@parser.upgrade_data).to eq('')
|
|
368
|
-
expect(offset).to eq(request.length)
|
|
369
|
-
end
|
|
370
|
-
|
|
371
|
-
it "should execute on_body on requests with no content-length" do
|
|
372
|
-
expect(@parser.reset!).to be true
|
|
373
|
-
|
|
374
|
-
@head, @complete, @body = 0, 0, 0
|
|
375
|
-
@parser.on_headers_complete = proc {|h| @head += 1 }
|
|
376
|
-
@parser.on_message_complete = proc { @complete += 1 }
|
|
377
|
-
@parser.on_body = proc {|b| @body += 1 }
|
|
378
|
-
|
|
379
|
-
head_response = "HTTP/1.1 200 OK\r\n\r\nstuff"
|
|
380
|
-
|
|
381
|
-
@parser << head_response
|
|
382
|
-
@parser << ''
|
|
383
|
-
expect(@head).to eq(1)
|
|
384
|
-
expect(@complete).to eq(1)
|
|
385
|
-
expect(@body).to eq(1)
|
|
386
|
-
end
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
%w[ request response ].each do |type|
|
|
390
|
-
JSON.parse(File.read(File.expand_path("../support/#{type}s.json", __FILE__))).each do |test|
|
|
391
|
-
test['headers'] ||= {}
|
|
392
|
-
next if !defined?(JRUBY_VERSION) and HTTP::Parser.strict? != test['strict']
|
|
393
|
-
|
|
394
|
-
it "should parse #{type}: #{test['name']}" do
|
|
395
|
-
@parser << test['raw']
|
|
396
|
-
|
|
397
|
-
expect(@parser.http_method).to eq(test['method'])
|
|
398
|
-
expect(@parser.keep_alive?).to eq(test['should_keep_alive'])
|
|
399
|
-
|
|
400
|
-
if test.has_key?('upgrade') and test['upgrade'] != 0
|
|
401
|
-
expect(@parser.upgrade?).to be true
|
|
402
|
-
expect(@parser.upgrade_data).to eq(test['upgrade'])
|
|
403
|
-
end
|
|
404
|
-
|
|
405
|
-
expect(@parser.send("http_major")).to eq(test["http_major"])
|
|
406
|
-
expect(@parser.send("http_minor")).to eq(test["http_minor"])
|
|
407
|
-
|
|
408
|
-
if test['type'] == 'HTTP_REQUEST'
|
|
409
|
-
if defined?(JRUBY_VERSION)
|
|
410
|
-
expect(@parser.send("request_url")).to eq(test["request_url"])
|
|
411
|
-
else
|
|
412
|
-
# It's created by rb_str_new(), so that encoding is Encoding::ASCII_8BIT a.k.a Encoding::BINARY
|
|
413
|
-
expect(@parser.send("request_url")).to eq(test["request_url"].force_encoding(Encoding::ASCII_8BIT))
|
|
414
|
-
end
|
|
415
|
-
else
|
|
416
|
-
expect(@parser.send("status_code")).to eq(test["status_code"])
|
|
417
|
-
expect(@parser.send("status")).to eq(test["status"].force_encoding(Encoding::ASCII_8BIT)) if !defined?(JRUBY_VERSION)
|
|
418
|
-
end
|
|
419
|
-
|
|
420
|
-
expect(@headers.size).to eq(test['num_headers'])
|
|
421
|
-
expect(@headers).to eq(test['headers'])
|
|
422
|
-
|
|
423
|
-
expect(@body).to eq(test['body'])
|
|
424
|
-
expect(@body.size).to eq(test['body_size']) if test['body_size']
|
|
425
|
-
end
|
|
426
|
-
end
|
|
427
|
-
end
|
|
428
|
-
end
|
data/spec/spec_helper.rb
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
require "http_parser"
|