http2 0.0.23 → 0.0.24
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +4 -1
- data/Gemfile.lock +45 -5
- data/README.md +50 -0
- data/VERSION +1 -1
- data/http2.gemspec +12 -6
- data/include/post_multipart_helper.rb +77 -0
- data/include/response_reader.rb +251 -0
- data/lib/http2.rb +182 -449
- data/shippable.yml +7 -0
- data/spec/http2_spec.rb +20 -20
- data/spec/spec_helper.rb +4 -1
- metadata +41 -37
- data/README.rdoc +0 -45
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1ceccc4ed3d44786cd9e606a534761f41e14fac6
|
4
|
+
data.tar.gz: e89411685ce84e2fa7d2de4275a6a94fe60dfa5d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 00e97764f4dfea2d97014bc8e88e43e4ad3644a73570775789b293c89fbd5bc991f77b9411e36548f3d3ab473291b8794e228893066b25c5e8548144a788523a
|
7
|
+
data.tar.gz: b7a44522fa4032401c88e6f552702e9f50a6c207edb357211b91f5af645e4d40e666041abda4b7c37eadaf2bd5555cc20e4e275fbf8d6e1b4297ebc47662ff0f
|
data/Gemfile
CHANGED
@@ -2,6 +2,7 @@ source "http://rubygems.org"
|
|
2
2
|
# Add dependencies required to use your gem here.
|
3
3
|
# Example:
|
4
4
|
# gem "activesupport", ">= 2.3.5"
|
5
|
+
gem "string-cases"
|
5
6
|
|
6
7
|
# Add dependencies to develop your gem here.
|
7
8
|
# Include everything needed to run rake, tests, features, etc.
|
@@ -9,5 +10,7 @@ group :development do
|
|
9
10
|
gem "rspec", "~> 2.8.0"
|
10
11
|
gem "rdoc", "~> 3.12"
|
11
12
|
gem "bundler", ">= 1.0.0"
|
12
|
-
gem "jeweler", "
|
13
|
+
gem "jeweler", ">= 1.8.4"
|
13
14
|
end
|
15
|
+
|
16
|
+
gem "codeclimate-test-reporter", group: :test, require: nil
|
data/Gemfile.lock
CHANGED
@@ -1,15 +1,47 @@
|
|
1
1
|
GEM
|
2
2
|
remote: http://rubygems.org/
|
3
3
|
specs:
|
4
|
+
addressable (2.3.6)
|
5
|
+
builder (3.2.2)
|
6
|
+
codeclimate-test-reporter (0.3.0)
|
7
|
+
simplecov (>= 0.7.1, < 1.0.0)
|
4
8
|
diff-lcs (1.1.3)
|
5
|
-
|
6
|
-
|
9
|
+
docile (1.1.5)
|
10
|
+
faraday (0.8.9)
|
11
|
+
multipart-post (~> 1.2.0)
|
12
|
+
git (1.2.6)
|
13
|
+
github_api (0.10.1)
|
14
|
+
addressable
|
15
|
+
faraday (~> 0.8.1)
|
16
|
+
hashie (>= 1.2)
|
17
|
+
multi_json (~> 1.4)
|
18
|
+
nokogiri (~> 1.5.2)
|
19
|
+
oauth2
|
20
|
+
hashie (2.1.1)
|
21
|
+
highline (1.6.21)
|
22
|
+
jeweler (1.8.8)
|
23
|
+
builder
|
7
24
|
bundler (~> 1.0)
|
8
25
|
git (>= 1.2.5)
|
26
|
+
github_api (= 0.10.1)
|
27
|
+
highline (>= 1.6.15)
|
28
|
+
nokogiri (= 1.5.10)
|
9
29
|
rake
|
10
30
|
rdoc
|
11
|
-
json (1.8.
|
12
|
-
|
31
|
+
json (1.8.1)
|
32
|
+
jwt (1.0.0)
|
33
|
+
multi_json (1.10.1)
|
34
|
+
multi_xml (0.5.5)
|
35
|
+
multipart-post (1.2.0)
|
36
|
+
nokogiri (1.5.10)
|
37
|
+
oauth2 (0.9.4)
|
38
|
+
faraday (>= 0.8, < 0.10)
|
39
|
+
jwt (~> 1.0)
|
40
|
+
multi_json (~> 1.3)
|
41
|
+
multi_xml (~> 0.5)
|
42
|
+
rack (~> 1.2)
|
43
|
+
rack (1.5.2)
|
44
|
+
rake (10.3.2)
|
13
45
|
rdoc (3.12.2)
|
14
46
|
json (~> 1.4)
|
15
47
|
rspec (2.8.0)
|
@@ -20,12 +52,20 @@ GEM
|
|
20
52
|
rspec-expectations (2.8.0)
|
21
53
|
diff-lcs (~> 1.1.2)
|
22
54
|
rspec-mocks (2.8.0)
|
55
|
+
simplecov (0.8.2)
|
56
|
+
docile (~> 1.1.0)
|
57
|
+
multi_json
|
58
|
+
simplecov-html (~> 0.8.0)
|
59
|
+
simplecov-html (0.8.0)
|
60
|
+
string-cases (0.0.0)
|
23
61
|
|
24
62
|
PLATFORMS
|
25
63
|
ruby
|
26
64
|
|
27
65
|
DEPENDENCIES
|
28
66
|
bundler (>= 1.0.0)
|
29
|
-
|
67
|
+
codeclimate-test-reporter
|
68
|
+
jeweler (>= 1.8.4)
|
30
69
|
rdoc (~> 3.12)
|
31
70
|
rspec (~> 2.8.0)
|
71
|
+
string-cases
|
data/README.md
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# http2
|
2
|
+
|
3
|
+
[![Build Status](https://api.shippable.com/projects/53bd3eef2e23bdcb03c0df9e/badge/master)](https://www.shippable.com/projects/53bd3eef2e23bdcb03c0df9e)
|
4
|
+
[![Code Climate](https://codeclimate.com/github/kaspernj/http2.png)](https://codeclimate.com/github/kaspernj/http2)
|
5
|
+
|
6
|
+
Example of usage:
|
7
|
+
|
8
|
+
```ruby
|
9
|
+
require "rubygems"
|
10
|
+
require "http2"
|
11
|
+
|
12
|
+
Http2.new(:host => "www.google.dk") do |http|
|
13
|
+
#Get-request.
|
14
|
+
res = http.get("path/to/something")
|
15
|
+
puts res.body
|
16
|
+
puts "All response-headers: #{res.headers}"
|
17
|
+
puts "Specific header: #{res.header("HeaderName")}"
|
18
|
+
|
19
|
+
#Post-request.
|
20
|
+
res = http.post(:url => "path/to/something", :post => {
|
21
|
+
"some_post_val" => "some_value"
|
22
|
+
})
|
23
|
+
|
24
|
+
#Post-multipart (upload).
|
25
|
+
res = http.post_multipart(:url => "path/to/something", :post => {
|
26
|
+
"test_file1" => {
|
27
|
+
:fpath => fpath,
|
28
|
+
:filename => "specfile"
|
29
|
+
}
|
30
|
+
})
|
31
|
+
|
32
|
+
puts "Cookies until now: #{http.cookies}"
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
36
|
+
## Contributing to http2
|
37
|
+
|
38
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
39
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
40
|
+
* Fork the project.
|
41
|
+
* Start a feature/bugfix branch.
|
42
|
+
* Commit and push until you are happy with your contribution.
|
43
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
44
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
45
|
+
|
46
|
+
## Copyright
|
47
|
+
|
48
|
+
Copyright (c) 2012 Kasper Johansen. See LICENSE.txt for
|
49
|
+
further details.
|
50
|
+
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.24
|
data/http2.gemspec
CHANGED
@@ -5,16 +5,16 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "http2"
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.24"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Kasper Johansen"]
|
12
|
-
s.date = "
|
12
|
+
s.date = "2014-07-09"
|
13
13
|
s.description = "A lightweight framework for doing http-connections in Ruby. Supports cookies, keep-alive, compressing and much more."
|
14
14
|
s.email = "k@spernj.org"
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"LICENSE.txt",
|
17
|
-
"README.
|
17
|
+
"README.md"
|
18
18
|
]
|
19
19
|
s.files = [
|
20
20
|
".document",
|
@@ -22,38 +22,44 @@ Gem::Specification.new do |s|
|
|
22
22
|
"Gemfile",
|
23
23
|
"Gemfile.lock",
|
24
24
|
"LICENSE.txt",
|
25
|
-
"README.
|
25
|
+
"README.md",
|
26
26
|
"Rakefile",
|
27
27
|
"VERSION",
|
28
28
|
"http2.gemspec",
|
29
29
|
"include/errors.rb",
|
30
|
+
"include/post_multipart_helper.rb",
|
30
31
|
"include/response.rb",
|
32
|
+
"include/response_reader.rb",
|
31
33
|
"include/utils.rb",
|
32
34
|
"lib/http2.rb",
|
35
|
+
"shippable.yml",
|
33
36
|
"spec/http2_spec.rb",
|
34
37
|
"spec/spec_helper.rb"
|
35
38
|
]
|
36
39
|
s.homepage = "http://github.com/kaspernj/http2"
|
37
40
|
s.licenses = ["MIT"]
|
38
41
|
s.require_paths = ["lib"]
|
39
|
-
s.rubygems_version = "
|
42
|
+
s.rubygems_version = "2.0.14"
|
40
43
|
s.summary = "A lightweight framework for doing http-connections in Ruby. Supports cookies, keep-alive, compressing and much more."
|
41
44
|
|
42
45
|
if s.respond_to? :specification_version then
|
43
|
-
s.specification_version =
|
46
|
+
s.specification_version = 4
|
44
47
|
|
45
48
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
49
|
+
s.add_runtime_dependency(%q<string-cases>, [">= 0"])
|
46
50
|
s.add_development_dependency(%q<rspec>, ["~> 2.8.0"])
|
47
51
|
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
48
52
|
s.add_development_dependency(%q<bundler>, [">= 1.0.0"])
|
49
53
|
s.add_development_dependency(%q<jeweler>, ["~> 1.8.4"])
|
50
54
|
else
|
55
|
+
s.add_dependency(%q<string-cases>, [">= 0"])
|
51
56
|
s.add_dependency(%q<rspec>, ["~> 2.8.0"])
|
52
57
|
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
53
58
|
s.add_dependency(%q<bundler>, [">= 1.0.0"])
|
54
59
|
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
55
60
|
end
|
56
61
|
else
|
62
|
+
s.add_dependency(%q<string-cases>, [">= 0"])
|
57
63
|
s.add_dependency(%q<rspec>, ["~> 2.8.0"])
|
58
64
|
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
59
65
|
s.add_dependency(%q<bundler>, [">= 1.0.0"])
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require "tempfile"
|
2
|
+
|
3
|
+
class Http2::PostMultipartHelper
|
4
|
+
attr_reader :boundary
|
5
|
+
|
6
|
+
def initialize(http2)
|
7
|
+
@nl = http2.nl
|
8
|
+
|
9
|
+
#Generate random string.
|
10
|
+
@boundary = rand(36**50).to_s(36)
|
11
|
+
end
|
12
|
+
|
13
|
+
def generate_raw(phash)
|
14
|
+
Tempfile.open("http2_post_multipart_tmp_#{@boundary}") do |praw|
|
15
|
+
phash.each do |key, val|
|
16
|
+
praw << "--#{@boundary}#{@nl}"
|
17
|
+
|
18
|
+
if val.is_a?(Tempfile) && val.respond_to?(:original_filename)
|
19
|
+
parse_temp_file(key, val, praw)
|
20
|
+
elsif val.is_a?(Hash) && val[:filename]
|
21
|
+
parse_file(key, val, praw)
|
22
|
+
else
|
23
|
+
praw << "Content-Disposition: form-data; name=\"#{key}\";#{@nl}"
|
24
|
+
praw << "Content-Length: #{val.to_s.bytesize}#{@nl}"
|
25
|
+
end
|
26
|
+
|
27
|
+
praw << "Content-Type: text/plain#{@nl}"
|
28
|
+
praw << @nl
|
29
|
+
|
30
|
+
if val.class.name.to_s == "StringIO"
|
31
|
+
praw << val.read
|
32
|
+
elsif val.is_a?(Hash) && val[:content]
|
33
|
+
praw << val[:content].to_s
|
34
|
+
elsif val.is_a?(Hash) && val[:fpath]
|
35
|
+
read_file(val[:fpath], praw)
|
36
|
+
else
|
37
|
+
praw << val.to_s
|
38
|
+
end
|
39
|
+
|
40
|
+
praw << @nl
|
41
|
+
end
|
42
|
+
|
43
|
+
praw << "--#{@boundary}--"
|
44
|
+
|
45
|
+
yield self, praw
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def read_file(path, praw)
|
50
|
+
File.open(path, "r") do |fp|
|
51
|
+
begin
|
52
|
+
while data = fp.sysread(4096)
|
53
|
+
praw << data
|
54
|
+
end
|
55
|
+
rescue EOFError
|
56
|
+
# Happens when done.
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def parse_temp_file(key, val, praw)
|
62
|
+
praw << "Content-Disposition: form-data; name=\"#{key}\"; filename=\"#{val.original_filename}\";#{@nl}"
|
63
|
+
praw << "Content-Length: #{val.to_s.bytesize}#{@nl}"
|
64
|
+
end
|
65
|
+
|
66
|
+
def parse_file(key, val, praw)
|
67
|
+
praw << "Content-Disposition: form-data; name=\"#{key}\"; filename=\"#{val[:filename]}\";#{@nl}"
|
68
|
+
|
69
|
+
if val[:content]
|
70
|
+
praw << "Content-Length: #{val[:content].to_s.bytesize}#{@nl}"
|
71
|
+
elsif val[:fpath]
|
72
|
+
praw << "Content-Length: #{File.size(val[:fpath])}#{@nl}"
|
73
|
+
else
|
74
|
+
raise "Could not figure out where to get content from."
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,251 @@
|
|
1
|
+
class Http2::ResponseReader
|
2
|
+
attr_reader :response
|
3
|
+
|
4
|
+
def initialize(args)
|
5
|
+
@mode = "headers"
|
6
|
+
@transfer_encoding = nil
|
7
|
+
@response = Http2::Response.new(:request_args => args, :debug => @debug)
|
8
|
+
@rec_count = 0
|
9
|
+
@args, @debug, @http2, @sock = args[:args], args[:debug], args[:http2], args[:sock]
|
10
|
+
@nl = @http2.nl
|
11
|
+
|
12
|
+
read_headers
|
13
|
+
read_body
|
14
|
+
finish
|
15
|
+
end
|
16
|
+
|
17
|
+
def read_headers
|
18
|
+
loop do
|
19
|
+
line = @sock.gets
|
20
|
+
check_line_read(line)
|
21
|
+
|
22
|
+
if line == "\n" || line == "\r\n" || line == @nl
|
23
|
+
puts "Http2: Changing mode to body!" if @debug
|
24
|
+
raise "No headers was given at all? Possibly corrupt state after last request?" if @response.headers.empty?
|
25
|
+
break if @length == 0
|
26
|
+
@mode = "body"
|
27
|
+
@http2.on_content_call(@args, @nl)
|
28
|
+
break
|
29
|
+
end
|
30
|
+
|
31
|
+
parse_header(line)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def read_body
|
36
|
+
loop do
|
37
|
+
if @length && @length > 0
|
38
|
+
line = @sock.read(@length)
|
39
|
+
raise "Expected to get #{@length} of bytes but got #{line.bytesize}" if @length != line.bytesize
|
40
|
+
else
|
41
|
+
line = @sock.gets
|
42
|
+
end
|
43
|
+
|
44
|
+
check_line_read(line)
|
45
|
+
stat = parse_body(line)
|
46
|
+
break if stat == "break"
|
47
|
+
next if stat == "next"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def finish
|
52
|
+
#Check if we should reconnect based on keep-alive-max.
|
53
|
+
if @keepalive_max == 1 or @connection == "close"
|
54
|
+
@sock.close unless @sock.closed?
|
55
|
+
end
|
56
|
+
|
57
|
+
# Validate that the response is as it should be.
|
58
|
+
puts "Http2: Validating response." if @debug
|
59
|
+
|
60
|
+
if !@response.args[:code]
|
61
|
+
raise "No status-code was received from the server. Headers: '#{@response.headers}' Body: '#{resp.args[:body]}'."
|
62
|
+
end
|
63
|
+
|
64
|
+
@response.validate!
|
65
|
+
check_and_decode
|
66
|
+
check_and_follow_redirect
|
67
|
+
handle_errors
|
68
|
+
|
69
|
+
@http2.autostate_register(@response) if @http2.args[:autostate]
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def check_and_follow_redirect
|
75
|
+
if (@response.args[:code].to_s == "302" || @response.args[:code].to_s == "307") && @response.header?("location") && (!@http2.args.key?(:follow_redirects) || @http2.args[:follow_redirects])
|
76
|
+
uri = URI.parse(@response.header("location"))
|
77
|
+
url = uri.path
|
78
|
+
url << "?#{uri.query}" if uri.query.to_s.length > 0
|
79
|
+
|
80
|
+
args = {:host => uri.host}
|
81
|
+
args[:ssl] = true if uri.scheme == "https"
|
82
|
+
args[:port] = uri.port if uri.port
|
83
|
+
|
84
|
+
puts "Http2: Redirecting from location-header to '#{url}'." if @debug
|
85
|
+
|
86
|
+
if !args[:host] or args[:host] == @args[:host]
|
87
|
+
return self.get(url)
|
88
|
+
else
|
89
|
+
http = Http2.new(args)
|
90
|
+
return http.get(url)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def check_and_decode
|
96
|
+
# Check if the content is gzip-encoded - if so: decode it!
|
97
|
+
if @encoding == "gzip"
|
98
|
+
puts "Http2: Decoding GZip." if @debug
|
99
|
+
require "zlib"
|
100
|
+
require "stringio"
|
101
|
+
io = StringIO.new(@response.args[:body])
|
102
|
+
gz = Zlib::GzipReader.new(io)
|
103
|
+
untrusted_str = gz.read
|
104
|
+
|
105
|
+
begin
|
106
|
+
valid_string = ic.encode("UTF-8")
|
107
|
+
rescue
|
108
|
+
valid_string = untrusted_str.force_encoding("UTF-8").encode("UTF-8", :invalid => :replace, :replace => "").encode("UTF-8")
|
109
|
+
end
|
110
|
+
|
111
|
+
@response.args[:body] = valid_string
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def handle_errors
|
116
|
+
if @http2.raise_errors
|
117
|
+
if @response.args[:code].to_i == 500
|
118
|
+
err = Http2::Errors::Internalserver.new("A internal server error occurred")
|
119
|
+
elsif @response.args[:code].to_i == 403
|
120
|
+
err = Http2::Errors::Noaccess.new("No access")
|
121
|
+
elsif @response.args[:code].to_i == 400
|
122
|
+
err = Http2::Errors::Badrequest.new("Bad request")
|
123
|
+
elsif @response.args[:code].to_i == 404
|
124
|
+
err = Http2::Errors::Notfound.new("Not found")
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
if err
|
129
|
+
err.response = @response
|
130
|
+
raise err
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def check_line_read(line)
|
135
|
+
if line
|
136
|
+
@rec_count += line.length
|
137
|
+
elsif !line && @rec_count <= 0
|
138
|
+
@sock = nil
|
139
|
+
raise Errno::ECONNABORTED, "Server closed the connection before being able to read anything (KeepAliveMax: '#{@keepalive_max}', Connection: '#{@connection}', PID: '#{Process.pid}')."
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def parse_cookie(cookie_line)
|
144
|
+
::Http2::Utils.parse_set_cookies(cookie_line).each do |cookie_data|
|
145
|
+
@http2.cookies[cookie_data["name"]] = cookie_data
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def parse_keep_alive(keep_alive_line)
|
150
|
+
if ka_max = keep_alive_line.match(/max=(\d+)/)
|
151
|
+
@keepalive_max = ka_max[1].to_i
|
152
|
+
print "Http2: Keepalive-max set to: '#{@keepalive_max}'.\n" if @debug
|
153
|
+
end
|
154
|
+
|
155
|
+
if ka_timeout = keep_alive_line.match(/timeout=(\d+)/)
|
156
|
+
@keepalive_timeout = ka_timeout[1].to_i
|
157
|
+
print "Http2: Keepalive-timeout set to: '#{@keepalive_timeout}'.\n" if @debug
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def parse_content_type(content_type_line)
|
162
|
+
if match_charset = content_type_line.match(/\s*;\s*charset=(.+)/i)
|
163
|
+
@charset = match_charset[1].downcase
|
164
|
+
@response.args[:charset] = @charset
|
165
|
+
content_type_line.gsub!(match_charset[0], "")
|
166
|
+
end
|
167
|
+
|
168
|
+
@ctype = content_type_line
|
169
|
+
@response.args[:contenttype] = @content_type_line
|
170
|
+
end
|
171
|
+
|
172
|
+
#Parse a header-line and saves it on the object.
|
173
|
+
#===Examples
|
174
|
+
# http.parse_header("Content-Type: text/html\r\n")
|
175
|
+
def parse_header(line)
|
176
|
+
if match = line.match(/^(.+?):\s*(.+)#{@nl}$/)
|
177
|
+
key = match[1].to_s.downcase
|
178
|
+
|
179
|
+
parse_cookie(match[2]) if key == "set-cookie"
|
180
|
+
parse_keep_alive(match[2]) if key == "keep-alive"
|
181
|
+
parse_content_type(match[2]) if key == "content-type"
|
182
|
+
|
183
|
+
if key == "connection"
|
184
|
+
@connection = match[2].to_s.downcase
|
185
|
+
elsif key == "content-encoding"
|
186
|
+
@encoding = match[2].to_s.downcase
|
187
|
+
puts "Http2: Setting encoding to #{@encoding}" if @debug
|
188
|
+
elsif key == "content-length"
|
189
|
+
@length = match[2].to_i
|
190
|
+
elsif key == "transfer-encoding"
|
191
|
+
@transfer_encoding = match[2].to_s.downcase.strip
|
192
|
+
end
|
193
|
+
|
194
|
+
puts "Http2: Parsed header: #{match[1]}: #{match[2]}" if @debug
|
195
|
+
@response.headers[key] = [] unless @response.headers.key?(key)
|
196
|
+
@response.headers[key] << match[2]
|
197
|
+
|
198
|
+
if key != "transfer-encoding" && key != "content-length" && key != "connection" && key != "keep-alive"
|
199
|
+
@http2.on_content_call(@args, line)
|
200
|
+
end
|
201
|
+
elsif match = line.match(/^HTTP\/([\d\.]+)\s+(\d+)\s+(.+)$/)
|
202
|
+
@response.args[:code] = match[2]
|
203
|
+
@response.args[:http_version] = match[1]
|
204
|
+
|
205
|
+
@http2.on_content_call(@args, line)
|
206
|
+
else
|
207
|
+
raise "Could not understand header string: '#{line}'.\n\n#{@sock.read(409600)}"
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
#Parses the body based on given headers and saves it to the result-object.
|
212
|
+
# http.parse_body(str)
|
213
|
+
def parse_body(line)
|
214
|
+
if @response.args[:http_version] = "1.1"
|
215
|
+
return "break" if @length == 0
|
216
|
+
|
217
|
+
if @transfer_encoding == "chunked"
|
218
|
+
parse_body_chunked(line)
|
219
|
+
else
|
220
|
+
puts "Http2: Adding #{line.to_s.bytesize} to the body." if @debug
|
221
|
+
@response.args[:body] << line.to_s
|
222
|
+
@http2.on_content_call(@args, line)
|
223
|
+
return "break" if @response.header?("content-length") && @response.args[:body].length >= @response.header("content-length").to_i
|
224
|
+
end
|
225
|
+
else
|
226
|
+
raise "Dont know how to read HTTP version: '#{@resp.args[:http_version]}'."
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
def parse_body_chunked(line)
|
231
|
+
len = line.strip.hex
|
232
|
+
|
233
|
+
if len > 0
|
234
|
+
read = @sock.read(len)
|
235
|
+
return "break" if read == "" or (read == "\n" || read == "\r\n")
|
236
|
+
@response.args[:body] << read
|
237
|
+
@http2.on_content_call(@args, read)
|
238
|
+
end
|
239
|
+
|
240
|
+
nl = @sock.gets
|
241
|
+
if len == 0
|
242
|
+
if nl == "\n" || nl == "\r\n"
|
243
|
+
return "break"
|
244
|
+
else
|
245
|
+
raise "Dont know what to do :'-("
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
raise "Should have read newline but didnt: '#{nl}'." if nl != @nl
|
250
|
+
end
|
251
|
+
end
|