http-parser 1.0.0
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 +7 -0
- data/LICENSE +20 -0
- data/README.md +70 -0
- data/Rakefile +0 -0
- data/ext/Rakefile +9 -0
- data/ext/http-parser/http_parser.c +2175 -0
- data/ext/http-parser/http_parser.h +305 -0
- data/http-parser.gemspec +32 -0
- data/lib/http-parser.rb +9 -0
- data/lib/http-parser/errors.rb +74 -0
- data/lib/http-parser/ext.rb +7 -0
- data/lib/http-parser/parser.rb +198 -0
- data/lib/http-parser/types.rb +312 -0
- data/lib/http-parser/version.rb +3 -0
- data/spec/error_spec.rb +45 -0
- data/spec/instance_spec.rb +98 -0
- data/spec/parser_spec.rb +274 -0
- metadata +123 -0
data/spec/parser_spec.rb
ADDED
@@ -0,0 +1,274 @@
|
|
1
|
+
require 'http-parser'
|
2
|
+
|
3
|
+
describe HttpParser::Parser, "#initialize" do
|
4
|
+
before :each do
|
5
|
+
@inst = HttpParser::Parser.new_instance
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "callbacks" do
|
9
|
+
describe "on_message_begin" do
|
10
|
+
subject do
|
11
|
+
described_class.new do |parser|
|
12
|
+
parser.on_message_begin { @begun = true }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should trigger on a new request" do
|
17
|
+
subject.parse @inst, "GET / HTTP/1.1"
|
18
|
+
@begun.should be_true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "on_url" do
|
23
|
+
let(:expected) { '/foo?q=1' }
|
24
|
+
|
25
|
+
subject do
|
26
|
+
described_class.new do |parser|
|
27
|
+
parser.on_url { |inst, data| @url = data }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should pass the recognized url" do
|
32
|
+
subject.parse @inst, "GET "
|
33
|
+
|
34
|
+
@url.should be_nil
|
35
|
+
|
36
|
+
subject.parse @inst, "#{expected} HTTP/1.1"
|
37
|
+
|
38
|
+
@url.should == expected
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "on_header_field" do
|
43
|
+
let(:expected) { 'Host' }
|
44
|
+
|
45
|
+
subject do
|
46
|
+
described_class.new do |parser|
|
47
|
+
parser.on_header_field { |inst, data| @header_field = data }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should pass the recognized header-name" do
|
52
|
+
subject.parse @inst, "GET /foo HTTP/1.1\r\n"
|
53
|
+
|
54
|
+
@header_field.should be_nil
|
55
|
+
|
56
|
+
subject.parse @inst, "#{expected}: example.com\r\n"
|
57
|
+
|
58
|
+
@header_field.should == expected
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "on_header_value" do
|
63
|
+
let(:expected) { 'example.com' }
|
64
|
+
|
65
|
+
subject do
|
66
|
+
described_class.new do |parser|
|
67
|
+
parser.on_header_value { |inst, data| @header_value = data }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should pass the recognized header-value" do
|
72
|
+
subject.parse @inst, "GET /foo HTTP/1.1\r\n"
|
73
|
+
|
74
|
+
@header_value.should be_nil
|
75
|
+
|
76
|
+
subject.parse @inst, "Host: #{expected}\r\n"
|
77
|
+
|
78
|
+
@header_value.should == expected
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "on_headers_complete" do
|
83
|
+
subject do
|
84
|
+
described_class.new do |parser|
|
85
|
+
parser.on_headers_complete { @header_complete = true }
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should trigger on the last header" do
|
90
|
+
subject.parse @inst, "GET / HTTP/1.1\r\nHost: example.com\r\n"
|
91
|
+
|
92
|
+
@header_complete.should be_nil
|
93
|
+
|
94
|
+
subject.parse @inst, "\r\n"
|
95
|
+
|
96
|
+
@header_complete.should be_true
|
97
|
+
end
|
98
|
+
|
99
|
+
context "when #stop! is called" do
|
100
|
+
subject do
|
101
|
+
described_class.new do |parser|
|
102
|
+
parser.on_headers_complete { @inst.stop! }
|
103
|
+
|
104
|
+
parser.on_body { |inst, data| @body = data }
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should indicate there is no request body to parse" do
|
109
|
+
subject.parse @inst, "GET / HTTP/1.1\r\nHost: example.com\r\n\r\nBody"
|
110
|
+
|
111
|
+
@body.should be_nil
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe "on_body" do
|
117
|
+
let(:expected) { "Body" }
|
118
|
+
|
119
|
+
subject do
|
120
|
+
described_class.new do |parser|
|
121
|
+
parser.on_body { |inst, data| @body = data }
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should trigger on the body" do
|
126
|
+
subject.parse @inst, "POST / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n"
|
127
|
+
|
128
|
+
@body.should be_nil
|
129
|
+
|
130
|
+
subject.parse @inst, "#{"%x" % expected.length}\r\n#{expected}"
|
131
|
+
|
132
|
+
@body.should == expected
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
describe "on_message_complete" do
|
137
|
+
subject do
|
138
|
+
described_class.new do |parser|
|
139
|
+
parser.on_message_complete { @message_complete = true }
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should trigger at the end of the message" do
|
144
|
+
subject.parse @inst, "GET / HTTP/1.1\r\n"
|
145
|
+
|
146
|
+
@message_complete.should be_nil
|
147
|
+
|
148
|
+
subject.parse @inst, "Host: example.com\r\n\r\n"
|
149
|
+
|
150
|
+
@message_complete.should be_true
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
|
156
|
+
describe "#http_method" do
|
157
|
+
let(:expected) { :POST }
|
158
|
+
|
159
|
+
it "should set the http_method field" do
|
160
|
+
subject.parse @inst, "#{expected} / HTTP/1.1\r\n"
|
161
|
+
|
162
|
+
@inst.http_method.should == expected
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
describe "#http_major" do
|
167
|
+
let(:expected) { 1 }
|
168
|
+
|
169
|
+
before do
|
170
|
+
@inst.type = :request
|
171
|
+
end
|
172
|
+
|
173
|
+
context "when parsing requests" do
|
174
|
+
it "should set the http_major field" do
|
175
|
+
subject.parse @inst, "GET / HTTP/#{expected}."
|
176
|
+
|
177
|
+
@inst.http_major.should == expected
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
context "when parsing responses" do
|
182
|
+
before do
|
183
|
+
@inst.type = :response
|
184
|
+
end
|
185
|
+
|
186
|
+
it "should set the http_major field" do
|
187
|
+
subject.parse @inst, "HTTP/#{expected}."
|
188
|
+
|
189
|
+
@inst.http_major.should == expected
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
describe "#http_minor" do
|
195
|
+
let(:expected) { 2 }
|
196
|
+
|
197
|
+
context "when parsing requests" do
|
198
|
+
it "should set the http_minor field" do
|
199
|
+
subject.parse @inst, "GET / HTTP/1.#{expected}\r\n"
|
200
|
+
|
201
|
+
@inst.http_minor.should == expected
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
context "when parsing responses" do
|
206
|
+
before do
|
207
|
+
@inst.type = :response
|
208
|
+
end
|
209
|
+
|
210
|
+
it "should set the http_major field" do
|
211
|
+
subject.parse @inst, "HTTP/1.#{expected} "
|
212
|
+
|
213
|
+
@inst.http_minor.should == expected
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
describe "#http_version" do
|
219
|
+
let(:expected) { '1.1' }
|
220
|
+
|
221
|
+
before do
|
222
|
+
subject.parse @inst, "GET / HTTP/#{expected}\r\n"
|
223
|
+
end
|
224
|
+
|
225
|
+
it "should combine #http_major and #http_minor" do
|
226
|
+
@inst.http_version.should == expected
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
describe "#http_status" do
|
231
|
+
context "when parsing requests" do
|
232
|
+
before do
|
233
|
+
subject.parse @inst, "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"
|
234
|
+
end
|
235
|
+
|
236
|
+
it "should not be set" do
|
237
|
+
@inst.http_status.should be_zero
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
context "when parsing responses" do
|
242
|
+
let(:expected) { 200 }
|
243
|
+
|
244
|
+
before do
|
245
|
+
@inst.type = :response
|
246
|
+
subject.parse @inst, "HTTP/1.1 #{expected} OK\r\n"
|
247
|
+
subject.parse @inst, "Location: http://example.com/\r\n\r\n"
|
248
|
+
end
|
249
|
+
|
250
|
+
it "should set the http_status field" do
|
251
|
+
@inst.http_status.should == expected
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
describe "#upgrade?" do
|
257
|
+
let(:upgrade) { 'WebSocket' }
|
258
|
+
|
259
|
+
before do
|
260
|
+
subject.parse @inst, "GET /demo HTTP/1.1\r\n"
|
261
|
+
subject.parse @inst, "Upgrade: #{upgrade}\r\n"
|
262
|
+
subject.parse @inst, "Connection: Upgrade\r\n"
|
263
|
+
subject.parse @inst, "Host: example.com\r\n"
|
264
|
+
subject.parse @inst, "Origin: http://example.com\r\n"
|
265
|
+
subject.parse @inst, "WebSocket-Protocol: sample\r\n"
|
266
|
+
subject.parse @inst, "\r\n"
|
267
|
+
end
|
268
|
+
|
269
|
+
it "should return true if the Upgrade header was set" do
|
270
|
+
@inst.upgrade?.should be_true
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
metadata
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: http-parser
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Stephen von Takach
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-08-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ffi-compiler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.0.2
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.0.2
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: yard
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: |2
|
70
|
+
A super fast http parser for ruby.
|
71
|
+
Cross platform and multiple ruby implementation support thanks to ffi.
|
72
|
+
email:
|
73
|
+
- steve@cotag.me
|
74
|
+
executables: []
|
75
|
+
extensions:
|
76
|
+
- ext/Rakefile
|
77
|
+
extra_rdoc_files:
|
78
|
+
- README.md
|
79
|
+
files:
|
80
|
+
- lib/http-parser/errors.rb
|
81
|
+
- lib/http-parser/ext.rb
|
82
|
+
- lib/http-parser/parser.rb
|
83
|
+
- lib/http-parser/types.rb
|
84
|
+
- lib/http-parser/version.rb
|
85
|
+
- lib/http-parser.rb
|
86
|
+
- Rakefile
|
87
|
+
- http-parser.gemspec
|
88
|
+
- README.md
|
89
|
+
- LICENSE
|
90
|
+
- ext/http-parser/http_parser.c
|
91
|
+
- ext/http-parser/http_parser.h
|
92
|
+
- spec/error_spec.rb
|
93
|
+
- spec/instance_spec.rb
|
94
|
+
- spec/parser_spec.rb
|
95
|
+
- ext/Rakefile
|
96
|
+
homepage: https://github.com/cotag/http-parser
|
97
|
+
licenses: []
|
98
|
+
metadata: {}
|
99
|
+
post_install_message:
|
100
|
+
rdoc_options: []
|
101
|
+
require_paths:
|
102
|
+
- lib
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - '>='
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '0'
|
108
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - '>='
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
requirements: []
|
114
|
+
rubyforge_project:
|
115
|
+
rubygems_version: 2.0.6
|
116
|
+
signing_key:
|
117
|
+
specification_version: 4
|
118
|
+
summary: Ruby bindings to joyent/http-parser
|
119
|
+
test_files:
|
120
|
+
- spec/error_spec.rb
|
121
|
+
- spec/instance_spec.rb
|
122
|
+
- spec/parser_spec.rb
|
123
|
+
has_rdoc:
|