ffi-http-parser 0.1.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.
- data/.document +3 -0
- data/.gitignore +2 -0
- data/.rspec +1 -0
- data/.yardopts +1 -0
- data/ChangeLog.md +11 -0
- data/LICENSE.txt +20 -0
- data/README.md +66 -0
- data/Rakefile +40 -0
- data/ffi-http-parser.gemspec +60 -0
- data/gemspec.yml +17 -0
- data/lib/ffi/http/parser.rb +2 -0
- data/lib/ffi/http/parser/instance.rb +398 -0
- data/lib/ffi/http/parser/parser.rb +31 -0
- data/lib/ffi/http/parser/settings.rb +22 -0
- data/lib/ffi/http/parser/types.rb +50 -0
- data/lib/ffi/http/parser/version.rb +10 -0
- data/spec/callback_examples.rb +26 -0
- data/spec/instance_spec.rb +458 -0
- data/spec/parser_spec.rb +24 -0
- data/spec/spec_helper.rb +5 -0
- metadata +133 -0
data/.document
ADDED
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour --format documentation
|
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--markup markdown --title "FFI::HTTP::Parser Documentation" --protected
|
data/ChangeLog.md
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
### 0.1.0 / 2012-06-23
|
2
|
+
|
3
|
+
* Initial release:
|
4
|
+
* Provides the same API as [http-parser-lite].
|
5
|
+
* Supports:
|
6
|
+
* Ruby 1.8.7
|
7
|
+
* Ruby >= 1.9.1
|
8
|
+
* JRuby >= 1.6.7
|
9
|
+
|
10
|
+
[http-parser]: https://github.com/joyent/http-parser#readme
|
11
|
+
[http-parser-lite]: https://github.com/deepfryed/http-parser-lite#readme
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Hal Brodigan
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
# ffi-http-parser
|
2
|
+
|
3
|
+
* [Homepage](https://github.com/postmodern/ffi-http-parser#readme)
|
4
|
+
* [Issues](https://github.com/postmodern/ffi-http-parser/issues)
|
5
|
+
* [Documentation](http://rubydoc.info/gems/ffi-http-parser/frames)
|
6
|
+
* [Email](mailto:postmodern.mod3 at gmail.com)
|
7
|
+
|
8
|
+
## Description
|
9
|
+
|
10
|
+
Ruby FFI bindings to the [http-parser][1] library.
|
11
|
+
|
12
|
+
## Features
|
13
|
+
|
14
|
+
* Provides the same API as [http-parser-lite][2].
|
15
|
+
* Supports:
|
16
|
+
* Ruby 1.8.7
|
17
|
+
* Ruby >= 1.9.1
|
18
|
+
* JRuby >= 1.6.7
|
19
|
+
|
20
|
+
## Examples
|
21
|
+
|
22
|
+
require 'ffi/http/parser'
|
23
|
+
|
24
|
+
parser = FFI::HTTP::Parser.new do |parser|
|
25
|
+
parser.on_message_begin do
|
26
|
+
puts "message begin"
|
27
|
+
end
|
28
|
+
|
29
|
+
parser.on_message_complete do
|
30
|
+
puts "message end"
|
31
|
+
end
|
32
|
+
|
33
|
+
parser.on_url do |data|
|
34
|
+
puts "url: #{data}"
|
35
|
+
end
|
36
|
+
|
37
|
+
parser.on_header_field do |data|
|
38
|
+
puts "field: #{data}"
|
39
|
+
end
|
40
|
+
|
41
|
+
parser.on_header_value do |data|
|
42
|
+
puts "value: #{data}"
|
43
|
+
end
|
44
|
+
|
45
|
+
parser.on_body do |data|
|
46
|
+
puts "body: #{data}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
## Requirements
|
51
|
+
|
52
|
+
* [http-parser](https://github.com/joyent/http-parser#readme) 1.0
|
53
|
+
* [ffi](https://github.com/ffi/ffi#readme) ~> 1.0
|
54
|
+
|
55
|
+
## Install
|
56
|
+
|
57
|
+
$ gem install ffi-http-parser
|
58
|
+
|
59
|
+
## Copyright
|
60
|
+
|
61
|
+
Copyright (c) 2012 Hal Brodigan
|
62
|
+
|
63
|
+
See {file:LICENSE.txt} for details.
|
64
|
+
|
65
|
+
[1]: https://github.com/joyent/http-parser#readme
|
66
|
+
[2]: https://github.com/deepfryed/http-parser-lite#readme
|
data/Rakefile
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'rake'
|
5
|
+
|
6
|
+
begin
|
7
|
+
gem 'rubygems-tasks', '~> 0.2'
|
8
|
+
require 'rubygems/tasks'
|
9
|
+
|
10
|
+
Gem::Tasks.new
|
11
|
+
rescue LoadError => e
|
12
|
+
warn e.message
|
13
|
+
warn "Run `gem install rubygems-tasks` to install 'rubygems/tasks'."
|
14
|
+
end
|
15
|
+
|
16
|
+
begin
|
17
|
+
gem 'rspec', '~> 2.4'
|
18
|
+
require 'rspec/core/rake_task'
|
19
|
+
|
20
|
+
RSpec::Core::RakeTask.new
|
21
|
+
rescue LoadError => e
|
22
|
+
task :spec do
|
23
|
+
abort "Please run `gem install rspec` to install RSpec."
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
task :test => :spec
|
28
|
+
task :default => :spec
|
29
|
+
|
30
|
+
begin
|
31
|
+
gem 'yard', '~> 0.7'
|
32
|
+
require 'yard'
|
33
|
+
|
34
|
+
YARD::Rake::YardocTask.new
|
35
|
+
rescue LoadError => e
|
36
|
+
task :yard do
|
37
|
+
abort "Please run `gem install yard` to install YARD."
|
38
|
+
end
|
39
|
+
end
|
40
|
+
task :doc => :yard
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gemspec = YAML.load_file('gemspec.yml')
|
7
|
+
|
8
|
+
gem.name = gemspec.fetch('name')
|
9
|
+
gem.version = gemspec.fetch('version') do
|
10
|
+
lib_dir = File.join(File.dirname(__FILE__),'lib')
|
11
|
+
$LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
|
12
|
+
|
13
|
+
require 'ffi/http/parser/version'
|
14
|
+
FFI::HTTP::Parser::VERSION
|
15
|
+
end
|
16
|
+
|
17
|
+
gem.summary = gemspec['summary']
|
18
|
+
gem.description = gemspec['description']
|
19
|
+
gem.licenses = Array(gemspec['license'])
|
20
|
+
gem.authors = Array(gemspec['authors'])
|
21
|
+
gem.email = gemspec['email']
|
22
|
+
gem.homepage = gemspec['homepage']
|
23
|
+
|
24
|
+
glob = lambda { |patterns| gem.files & Dir[*patterns] }
|
25
|
+
|
26
|
+
gem.files = `git ls-files`.split($/)
|
27
|
+
gem.files = glob[gemspec['files']] if gemspec['files']
|
28
|
+
|
29
|
+
gem.executables = gemspec.fetch('executables') do
|
30
|
+
glob['bin/*'].map { |path| File.basename(path) }
|
31
|
+
end
|
32
|
+
gem.default_executable = gem.executables.first if Gem::VERSION < '1.7.'
|
33
|
+
|
34
|
+
gem.extensions = glob[gemspec['extensions'] || 'ext/**/extconf.rb']
|
35
|
+
gem.test_files = glob[gemspec['test_files'] || '{test/{**/}*_test.rb']
|
36
|
+
gem.extra_rdoc_files = glob[gemspec['extra_doc_files'] || '*.{txt,md}']
|
37
|
+
|
38
|
+
gem.require_paths = Array(gemspec.fetch('require_paths') {
|
39
|
+
%w[ext lib].select { |dir| File.directory?(dir) }
|
40
|
+
})
|
41
|
+
|
42
|
+
gem.requirements = gemspec['requirements']
|
43
|
+
gem.required_ruby_version = gemspec['required_ruby_version']
|
44
|
+
gem.required_rubygems_version = gemspec['required_rubygems_version']
|
45
|
+
gem.post_install_message = gemspec['post_install_message']
|
46
|
+
|
47
|
+
split = lambda { |string| string.split(/,\s*/) }
|
48
|
+
|
49
|
+
if gemspec['dependencies']
|
50
|
+
gemspec['dependencies'].each do |name,versions|
|
51
|
+
gem.add_dependency(name,split[versions])
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
if gemspec['development_dependencies']
|
56
|
+
gemspec['development_dependencies'].each do |name,versions|
|
57
|
+
gem.add_development_dependency(name,split[versions])
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/gemspec.yml
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
name: ffi-http-parser
|
2
|
+
summary: FFI bindings for http-parser
|
3
|
+
description: Ruby FFI bindings to the http-parser library.
|
4
|
+
license: MIT
|
5
|
+
authors: Postmodern
|
6
|
+
email: postmodern.mod3@gmail.com
|
7
|
+
homepage: https://github.com/postmodern/ffi-http-parser#readme
|
8
|
+
|
9
|
+
requirements: http-parser 1.0
|
10
|
+
|
11
|
+
dependencies:
|
12
|
+
ffi: ~> 1.0
|
13
|
+
|
14
|
+
development_dependencies:
|
15
|
+
rubygems-tasks: ~> 0.2
|
16
|
+
rspec: ~> 2.4
|
17
|
+
yard: ~> 0.7
|
@@ -0,0 +1,398 @@
|
|
1
|
+
require 'ffi/http/parser/parser'
|
2
|
+
require 'ffi/http/parser/settings'
|
3
|
+
|
4
|
+
require 'ffi'
|
5
|
+
|
6
|
+
module FFI
|
7
|
+
module HTTP
|
8
|
+
module Parser
|
9
|
+
class Instance < FFI::Struct
|
10
|
+
|
11
|
+
layout :type_flags, :uchar,
|
12
|
+
:state, :uchar,
|
13
|
+
:header_state, :uchar,
|
14
|
+
:index, :uchar,
|
15
|
+
|
16
|
+
:nread, :uint32,
|
17
|
+
:content_length, :int64,
|
18
|
+
|
19
|
+
# READ-ONLY
|
20
|
+
:http_major, :ushort,
|
21
|
+
:http_minor, :ushort,
|
22
|
+
:status_code, :ushort, # responses only
|
23
|
+
:method, :uchar, # requests only
|
24
|
+
|
25
|
+
# 1 = Upgrade header was present and the parser has exited because of that.
|
26
|
+
# 0 = No upgrade header present.
|
27
|
+
#
|
28
|
+
# Should be checked when http_parser_execute() returns in addition to
|
29
|
+
# error checking.
|
30
|
+
:upgrade, :char,
|
31
|
+
|
32
|
+
# PUBLIC
|
33
|
+
:data, :pointer
|
34
|
+
|
35
|
+
# The parser type (`:request`, `:response` or `:both`)
|
36
|
+
attr_accessor :type
|
37
|
+
|
38
|
+
#
|
39
|
+
# Initializes the Parser instance.
|
40
|
+
#
|
41
|
+
# @param [FFI::Pointer] ptr
|
42
|
+
# Optional pointer to an existing `http_parser` struct.
|
43
|
+
#
|
44
|
+
def initialize(ptr=nil)
|
45
|
+
if ptr then super(ptr)
|
46
|
+
else super()
|
47
|
+
end
|
48
|
+
|
49
|
+
@settings = Settings.new
|
50
|
+
|
51
|
+
yield self if block_given?
|
52
|
+
|
53
|
+
Parser.http_parser_init(self,type) unless ptr
|
54
|
+
end
|
55
|
+
|
56
|
+
#
|
57
|
+
# Registers an `on_message_begin` callback.
|
58
|
+
#
|
59
|
+
# @yield []
|
60
|
+
# The given block will be called when the HTTP message begins.
|
61
|
+
#
|
62
|
+
def on_message_begin(&block)
|
63
|
+
@settings[:on_message_begin] = wrap_callback(block)
|
64
|
+
end
|
65
|
+
|
66
|
+
#
|
67
|
+
# Registers an `on_path` callback.
|
68
|
+
#
|
69
|
+
# @yield [path]
|
70
|
+
# The given block will be called when the path is recognized within
|
71
|
+
# the Request URI.
|
72
|
+
#
|
73
|
+
# @yieldparam [String] path
|
74
|
+
# The recognized URI path.
|
75
|
+
#
|
76
|
+
# @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
|
77
|
+
#
|
78
|
+
def on_path(&block)
|
79
|
+
@settings[:on_path] = wrap_data_callback(block)
|
80
|
+
end
|
81
|
+
|
82
|
+
#
|
83
|
+
# Registers an `on_query_string` callback.
|
84
|
+
#
|
85
|
+
# @yield [query]
|
86
|
+
# The given block will be called when the query-string is recognized
|
87
|
+
# within the Request URI.
|
88
|
+
#
|
89
|
+
# @yieldparam [String] query
|
90
|
+
# The recognized URI query-string.
|
91
|
+
#
|
92
|
+
# @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
|
93
|
+
#
|
94
|
+
def on_query_string(&block)
|
95
|
+
@settings[:on_query_string] = wrap_data_callback(block)
|
96
|
+
end
|
97
|
+
|
98
|
+
#
|
99
|
+
# Registers an `on_fragment` callback.
|
100
|
+
#
|
101
|
+
# @yield [fragment]
|
102
|
+
# The given block will be called when the fragment is recognized
|
103
|
+
# within the Request URI.
|
104
|
+
#
|
105
|
+
# @yieldparam [String] fragment
|
106
|
+
# The recognized URI fragment.
|
107
|
+
#
|
108
|
+
# @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
|
109
|
+
#
|
110
|
+
def on_fragment(&block)
|
111
|
+
@settings[:on_fragment] = wrap_data_callback(block)
|
112
|
+
end
|
113
|
+
|
114
|
+
#
|
115
|
+
# Registers an `on_url` callback.
|
116
|
+
#
|
117
|
+
# @yield [url]
|
118
|
+
# The given block will be called when the Request URI is recognized
|
119
|
+
# within the Request-Line.
|
120
|
+
#
|
121
|
+
# @yieldparam [String] url
|
122
|
+
# The recognized Request URI.
|
123
|
+
#
|
124
|
+
# @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
|
125
|
+
#
|
126
|
+
def on_url(&block)
|
127
|
+
@settings[:on_url] = wrap_data_callback(block)
|
128
|
+
end
|
129
|
+
|
130
|
+
#
|
131
|
+
# Registers an `on_header_field` callback.
|
132
|
+
#
|
133
|
+
# @yield [field]
|
134
|
+
# The given block will be called when a Header name is recognized
|
135
|
+
# in the Headers.
|
136
|
+
#
|
137
|
+
# @yieldparam [String] field
|
138
|
+
# A recognized Header name.
|
139
|
+
#
|
140
|
+
# @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.5
|
141
|
+
#
|
142
|
+
def on_header_field(&block)
|
143
|
+
@settings[:on_header_field] = wrap_data_callback(block)
|
144
|
+
end
|
145
|
+
|
146
|
+
#
|
147
|
+
# Registers an `on_header_value` callback.
|
148
|
+
#
|
149
|
+
# @yield [value]
|
150
|
+
# The given block will be called when a Header value is recognized
|
151
|
+
# in the Headers.
|
152
|
+
#
|
153
|
+
# @yieldparam [String] value
|
154
|
+
# A recognized Header value.
|
155
|
+
#
|
156
|
+
# @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.5
|
157
|
+
#
|
158
|
+
def on_header_value(&block)
|
159
|
+
@settings[:on_header_value] = wrap_data_callback(block)
|
160
|
+
end
|
161
|
+
|
162
|
+
#
|
163
|
+
# Registers an `on_headers_complete` callback.
|
164
|
+
#
|
165
|
+
# @yield []
|
166
|
+
# The given block will be called when the Headers stop.
|
167
|
+
#
|
168
|
+
def on_headers_complete(&block)
|
169
|
+
@settings[:on_headers_complete] = proc { |parser|
|
170
|
+
case block.call()
|
171
|
+
when :error then -1
|
172
|
+
when :stop then 1
|
173
|
+
else 0
|
174
|
+
end
|
175
|
+
}
|
176
|
+
end
|
177
|
+
|
178
|
+
#
|
179
|
+
# Registers an `on_body` callback.
|
180
|
+
#
|
181
|
+
# @yield [body]
|
182
|
+
# The given block will be called when the body is recognized in the
|
183
|
+
# message body.
|
184
|
+
#
|
185
|
+
# @yieldparam [String] body
|
186
|
+
# The full body or a chunk of the body from a chunked
|
187
|
+
# Transfer-Encoded stream.
|
188
|
+
#
|
189
|
+
# @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.5
|
190
|
+
#
|
191
|
+
def on_body(&block)
|
192
|
+
@settings[:on_body] = wrap_data_callback(block)
|
193
|
+
end
|
194
|
+
|
195
|
+
#
|
196
|
+
# Registers an `on_message_begin` callback.
|
197
|
+
#
|
198
|
+
# @yield []
|
199
|
+
# The given block will be called when the message completes.
|
200
|
+
#
|
201
|
+
def on_message_complete(&block)
|
202
|
+
@settings[:on_message_complete] = wrap_callback(block)
|
203
|
+
end
|
204
|
+
|
205
|
+
#
|
206
|
+
# Parses data.
|
207
|
+
#
|
208
|
+
# @param [String] data
|
209
|
+
# The data to parse.
|
210
|
+
#
|
211
|
+
# @return [Integer]
|
212
|
+
# The number of bytes parsed. `0` will be returned if the parser
|
213
|
+
# encountered an error.
|
214
|
+
#
|
215
|
+
def parse(data)
|
216
|
+
Parser.http_parser_execute(self,@settings,data,data.length)
|
217
|
+
end
|
218
|
+
|
219
|
+
#
|
220
|
+
# Parses data.
|
221
|
+
#
|
222
|
+
# @param [String] data
|
223
|
+
# The data to parse.
|
224
|
+
#
|
225
|
+
# @return [Instance]
|
226
|
+
# The Instance parser.
|
227
|
+
#
|
228
|
+
def <<(data)
|
229
|
+
parse(data)
|
230
|
+
return self
|
231
|
+
end
|
232
|
+
|
233
|
+
#
|
234
|
+
# Resets the parser.
|
235
|
+
#
|
236
|
+
def reset!
|
237
|
+
Parser.http_parser_init(self,type)
|
238
|
+
end
|
239
|
+
|
240
|
+
alias reset reset!
|
241
|
+
|
242
|
+
#
|
243
|
+
# The type of the parser.
|
244
|
+
#
|
245
|
+
# @return [:request, :response, :both]
|
246
|
+
# The parser type.
|
247
|
+
#
|
248
|
+
def type
|
249
|
+
TYPES[self[:type_flags] & 0x3]
|
250
|
+
end
|
251
|
+
|
252
|
+
#
|
253
|
+
# Sets the type of the parser.
|
254
|
+
#
|
255
|
+
# @param [:request, :response, :both] new_type
|
256
|
+
# The new parser type.
|
257
|
+
#
|
258
|
+
def type=(new_type)
|
259
|
+
self[:type_flags] = ((flags << 2) | TYPES[new_type])
|
260
|
+
end
|
261
|
+
|
262
|
+
#
|
263
|
+
# Flags for the parser.
|
264
|
+
#
|
265
|
+
# @return [Integer]
|
266
|
+
# Parser flags.
|
267
|
+
#
|
268
|
+
def flags
|
269
|
+
(self[:type_flags] & 0xfc) >> 2
|
270
|
+
end
|
271
|
+
|
272
|
+
#
|
273
|
+
# The parsed HTTP major version number.
|
274
|
+
#
|
275
|
+
# @return [Integer]
|
276
|
+
# The HTTP major version number.
|
277
|
+
#
|
278
|
+
def http_major
|
279
|
+
self[:http_major]
|
280
|
+
end
|
281
|
+
|
282
|
+
#
|
283
|
+
# The parsed HTTP minor version number.
|
284
|
+
#
|
285
|
+
# @return [Integer]
|
286
|
+
# The HTTP minor version number.
|
287
|
+
#
|
288
|
+
def http_minor
|
289
|
+
self[:http_minor]
|
290
|
+
end
|
291
|
+
|
292
|
+
#
|
293
|
+
# The parsed HTTP version.
|
294
|
+
#
|
295
|
+
# @return [String]
|
296
|
+
# The HTTP version.
|
297
|
+
#
|
298
|
+
def http_version
|
299
|
+
"%d.%d" % [self[:http_major], self[:http_minor]]
|
300
|
+
end
|
301
|
+
|
302
|
+
#
|
303
|
+
# The parsed HTTP response Status Code.
|
304
|
+
#
|
305
|
+
# @return [Integer]
|
306
|
+
# The HTTP Status Code.
|
307
|
+
#
|
308
|
+
# @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1.1
|
309
|
+
#
|
310
|
+
def http_status
|
311
|
+
self[:status_code]
|
312
|
+
end
|
313
|
+
|
314
|
+
#
|
315
|
+
# The parsed HTTP Method.
|
316
|
+
#
|
317
|
+
# @return [Symbol]
|
318
|
+
# The HTTP Method name.
|
319
|
+
#
|
320
|
+
# @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.1
|
321
|
+
#
|
322
|
+
def http_method
|
323
|
+
METHODS[self[:method]]
|
324
|
+
end
|
325
|
+
|
326
|
+
#
|
327
|
+
# Determines whether the `Upgrade` header has been parsed.
|
328
|
+
#
|
329
|
+
# @return [Boolean]
|
330
|
+
# Specifies whether the `Upgrade` header has been seen.
|
331
|
+
#
|
332
|
+
# @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.42
|
333
|
+
#
|
334
|
+
def upgrade?
|
335
|
+
self[:upgrade] == 1
|
336
|
+
end
|
337
|
+
|
338
|
+
#
|
339
|
+
# Additional data attached to the parser.
|
340
|
+
#
|
341
|
+
# @return [FFI::Pointer]
|
342
|
+
# Pointer to the additional data.
|
343
|
+
#
|
344
|
+
def data
|
345
|
+
self[:data]
|
346
|
+
end
|
347
|
+
|
348
|
+
#
|
349
|
+
# Determines whether the `Connection: keep-alive` header has been
|
350
|
+
# parsed.
|
351
|
+
#
|
352
|
+
# @return [Boolean]
|
353
|
+
# Specifies whether the Connection should be kept alive.
|
354
|
+
#
|
355
|
+
# @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.10
|
356
|
+
#
|
357
|
+
def keep_alive?
|
358
|
+
Parser.http_should_keep_alive(self) > 0
|
359
|
+
end
|
360
|
+
|
361
|
+
protected
|
362
|
+
|
363
|
+
#
|
364
|
+
# Wraps a callback, so if it returns `:error`, `-1` will be returned.
|
365
|
+
# `0` will be returned by default.
|
366
|
+
#
|
367
|
+
# @param [Proc] callback
|
368
|
+
# The callback to wrap.
|
369
|
+
#
|
370
|
+
# @return [Proc]
|
371
|
+
# The wrapped callback.
|
372
|
+
#
|
373
|
+
def wrap_callback(callback)
|
374
|
+
proc { |parser| (callback.call() == :error) ? -1 : 0 }
|
375
|
+
end
|
376
|
+
|
377
|
+
#
|
378
|
+
# Wraps a data callback, so if it returns `:error`, `-1` will be
|
379
|
+
# returned. `0` will be returned by default.
|
380
|
+
#
|
381
|
+
# @param [Proc] callback
|
382
|
+
# The callback to wrap.
|
383
|
+
#
|
384
|
+
# @return [Proc]
|
385
|
+
# The wrapped callback.
|
386
|
+
#
|
387
|
+
def wrap_data_callback(callback)
|
388
|
+
proc { |parser,buffer,length|
|
389
|
+
data = buffer.get_bytes(0,length)
|
390
|
+
|
391
|
+
(callback.call(data) == :error) ? -1 : 0
|
392
|
+
}
|
393
|
+
end
|
394
|
+
|
395
|
+
end
|
396
|
+
end
|
397
|
+
end
|
398
|
+
end
|