http2 0.0.17 → 0.0.18
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/http2.gemspec +3 -3
- data/include/errors.rb +5 -0
- data/include/response.rb +25 -0
- data/lib/http2.rb +37 -20
- data/spec/http2_spec.rb +7 -1
- metadata +37 -17
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.18
|
data/http2.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "http2"
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.18"
|
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 = "2013-06-
|
12
|
+
s.date = "2013-06-28"
|
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 = [
|
@@ -36,7 +36,7 @@ Gem::Specification.new do |s|
|
|
36
36
|
s.homepage = "http://github.com/kaspernj/http2"
|
37
37
|
s.licenses = ["MIT"]
|
38
38
|
s.require_paths = ["lib"]
|
39
|
-
s.rubygems_version = "1.8.
|
39
|
+
s.rubygems_version = "1.8.23"
|
40
40
|
s.summary = "A lightweight framework for doing http-connections in Ruby. Supports cookies, keep-alive, compressing and much more."
|
41
41
|
|
42
42
|
if s.respond_to? :specification_version then
|
data/include/errors.rb
CHANGED
data/include/response.rb
CHANGED
@@ -8,6 +8,7 @@ class Http2::Response
|
|
8
8
|
@args = args
|
9
9
|
@args[:headers] = {} if !@args.key?(:headers)
|
10
10
|
@args[:body] = "" if !@args.key?(:body)
|
11
|
+
@debug = @args[:debug]
|
11
12
|
end
|
12
13
|
|
13
14
|
#Returns headers given from the host for the result.
|
@@ -73,4 +74,28 @@ class Http2::Response
|
|
73
74
|
raise "URL could not be detected." if !@args[:request_args][:url]
|
74
75
|
return @args[:request_args][:url]
|
75
76
|
end
|
77
|
+
|
78
|
+
# Checks the data that has been sat on the object and raises various exceptions, if it does not validate somehow.
|
79
|
+
def validate!
|
80
|
+
puts "Http2: Validating response length." if @debug
|
81
|
+
validate_body_versus_content_length!
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
# Checks that the length of the body is the same as the given content-length if given.
|
87
|
+
def validate_body_versus_content_length!
|
88
|
+
unless self.header?("content-length")
|
89
|
+
puts "Http2: No content length given - skipping length validation." if @debug
|
90
|
+
return nil
|
91
|
+
end
|
92
|
+
|
93
|
+
content_length = self.header("content-length").to_i
|
94
|
+
body_length = @args[:body].to_s.bytesize
|
95
|
+
|
96
|
+
puts "Http2: Body length: #{body_length}" if @debug
|
97
|
+
puts "Http2: Content length: #{content_length}" if @debug
|
98
|
+
|
99
|
+
raise "Body does not match the given content-length: '#{body_length}', '#{content_length}'." if body_length != content_length
|
100
|
+
end
|
76
101
|
end
|
data/lib/http2.rb
CHANGED
@@ -388,7 +388,7 @@ class Http2
|
|
388
388
|
header_str << praw
|
389
389
|
header_str << @nl
|
390
390
|
|
391
|
-
puts "Header str: #{header_str}" if @debug
|
391
|
+
puts "Http2: Header str: #{header_str}" if @debug
|
392
392
|
|
393
393
|
self.write(header_str)
|
394
394
|
return self.read_response(args)
|
@@ -469,7 +469,7 @@ class Http2
|
|
469
469
|
|
470
470
|
|
471
471
|
#Debug.
|
472
|
-
print "Headerstr: #{header_str}\n" if @debug
|
472
|
+
print "Http2: Headerstr: #{header_str}\n" if @debug
|
473
473
|
|
474
474
|
|
475
475
|
#Write and return.
|
@@ -534,14 +534,15 @@ class Http2
|
|
534
534
|
# res = http.read_response
|
535
535
|
def read_response(args = {})
|
536
536
|
@mode = "headers"
|
537
|
-
@
|
538
|
-
|
537
|
+
@transfer_encoding = nil
|
538
|
+
@resp = Http2::Response.new(:request_args => args, :debug => @debug)
|
539
539
|
rec_count = 0
|
540
540
|
|
541
541
|
loop do
|
542
542
|
begin
|
543
543
|
if @length and @length > 0 and @mode == "body"
|
544
544
|
line = @sock.read(@length)
|
545
|
+
raise "Expected to get #{@length} of bytes but got #{line.bytesize}" if @length != line.bytesize
|
545
546
|
else
|
546
547
|
line = @sock.gets
|
547
548
|
end
|
@@ -553,7 +554,7 @@ class Http2
|
|
553
554
|
raise Errno::ECONNABORTED, "Server closed the connection before being able to read anything (KeepAliveMax: '#{@keepalive_max}', Connection: '#{@connection}', PID: '#{Process.pid}')."
|
554
555
|
end
|
555
556
|
|
556
|
-
|
557
|
+
puts "<#{@mode}>: '#{line}'" if @debug
|
557
558
|
rescue Errno::ECONNRESET => e
|
558
559
|
if rec_count > 0
|
559
560
|
print "Http2: The connection was reset while reading - breaking gently...\n" if @debug
|
@@ -567,7 +568,8 @@ class Http2
|
|
567
568
|
break if line.to_s == ""
|
568
569
|
|
569
570
|
if @mode == "headers" and line == @nl
|
570
|
-
|
571
|
+
puts "Http2: Changing mode to body!" if @debug
|
572
|
+
raise "No headers was given at all? Possibly corrupt state after last request?" if @resp.headers.empty?
|
571
573
|
break if @length == 0
|
572
574
|
@mode = "body"
|
573
575
|
self.on_content_call(args, @nl)
|
@@ -584,6 +586,12 @@ class Http2
|
|
584
586
|
end
|
585
587
|
|
586
588
|
|
589
|
+
#Release variables.
|
590
|
+
resp = @resp
|
591
|
+
@resp = nil
|
592
|
+
@mode = nil
|
593
|
+
|
594
|
+
|
587
595
|
#Check if we should reconnect based on keep-alive-max.
|
588
596
|
if @keepalive_max == 1 or @connection == "close"
|
589
597
|
@sock.close if !@sock.closed?
|
@@ -591,30 +599,31 @@ class Http2
|
|
591
599
|
end
|
592
600
|
|
593
601
|
|
602
|
+
|
603
|
+
# Validate that the response is as it should be.
|
604
|
+
puts "Http2: Validating response." if @debug
|
605
|
+
resp.validate!
|
606
|
+
|
607
|
+
|
594
608
|
#Check if the content is gzip-encoded - if so: decode it!
|
595
609
|
if @encoding == "gzip"
|
596
610
|
require "zlib"
|
597
|
-
require "iconv"
|
598
611
|
require "stringio"
|
599
|
-
io = StringIO.new(
|
612
|
+
io = StringIO.new(resp.args[:body])
|
600
613
|
gz = Zlib::GzipReader.new(io)
|
601
614
|
untrusted_str = gz.read
|
602
615
|
|
603
616
|
begin
|
604
|
-
valid_string = ic.encode("
|
617
|
+
valid_string = ic.encode("UTF-8")
|
605
618
|
rescue
|
606
|
-
|
607
|
-
valid_string = ic.iconv(untrusted_str + " ")[0..-2]
|
619
|
+
valid_string = untrusted_str.force_encoding("UTF-8").encode("UTF-8", :invalid => :replace, :replace => "").encode("UTF-8")
|
608
620
|
end
|
609
621
|
|
610
|
-
|
622
|
+
resp.args[:body] = valid_string
|
611
623
|
end
|
612
624
|
|
613
625
|
|
614
|
-
|
615
|
-
resp = @resp
|
616
|
-
@resp = nil
|
617
|
-
@mode = nil
|
626
|
+
|
618
627
|
|
619
628
|
raise "No status-code was received from the server. Headers: '#{resp.headers}' Body: '#{resp.args[:body]}'." if !resp.args[:code]
|
620
629
|
|
@@ -628,7 +637,7 @@ class Http2
|
|
628
637
|
args[:ssl] = true if uri.scheme == "https"
|
629
638
|
args[:port] = uri.port if uri.port
|
630
639
|
|
631
|
-
|
640
|
+
puts "Http2: Redirecting from location-header to '#{url}'." if @debug
|
632
641
|
|
633
642
|
if !args[:host] or args[:host] == @args[:host]
|
634
643
|
return self.get(url)
|
@@ -644,6 +653,10 @@ class Http2
|
|
644
653
|
err = Http2::Errors::Noaccess.new(resp.body)
|
645
654
|
err.response = resp
|
646
655
|
raise err
|
656
|
+
elsif @raise_errors && resp.args[:code].to_i == 404
|
657
|
+
err = Http2::Errors::Notfound.new(resp.body)
|
658
|
+
err.response = resp
|
659
|
+
raise err
|
647
660
|
else
|
648
661
|
autostate_register(resp) if @args[:autostate]
|
649
662
|
|
@@ -688,13 +701,16 @@ class Http2
|
|
688
701
|
|
689
702
|
@ctype = ctype
|
690
703
|
@resp.args[:contenttype] = @ctype
|
704
|
+
elsif key == "transfer-encoding"
|
705
|
+
@transfer_encoding = match[2].to_s.downcase.strip
|
691
706
|
end
|
692
707
|
|
693
708
|
if key != "transfer-encoding" and key != "content-length" and key != "connection" and key != "keep-alive"
|
694
709
|
self.on_content_call(args, line)
|
695
710
|
end
|
696
711
|
|
697
|
-
|
712
|
+
puts "Http2: Parsed header: #{match[1]}: #{match[2]}" if @debug
|
713
|
+
@resp.headers[key] = [] unless @resp.headers.key?(key)
|
698
714
|
@resp.headers[key] << match[2]
|
699
715
|
elsif match = line.match(/^HTTP\/([\d\.]+)\s+(\d+)\s+(.+)$/)
|
700
716
|
@resp.args[:code] = match[2]
|
@@ -710,7 +726,7 @@ class Http2
|
|
710
726
|
if @resp.args[:http_version] = "1.1"
|
711
727
|
return "break" if @length == 0
|
712
728
|
|
713
|
-
if @
|
729
|
+
if @transfer_encoding == "chunked"
|
714
730
|
len = line.strip.hex
|
715
731
|
|
716
732
|
if len > 0
|
@@ -731,9 +747,10 @@ class Http2
|
|
731
747
|
|
732
748
|
raise "Should have read newline but didnt: '#{nl}'." if nl != @nl
|
733
749
|
else
|
750
|
+
puts "Http2: Adding #{line.to_s.bytesize} to the body." if @debug
|
734
751
|
@resp.args[:body] << line.to_s
|
735
752
|
self.on_content_call(args, line)
|
736
|
-
return "break" if @resp.header?("content-length")
|
753
|
+
return "break" if @resp.header?("content-length") && @resp.args[:body].length >= @resp.header("content-length").to_i
|
737
754
|
end
|
738
755
|
else
|
739
756
|
raise "Dont know how to read HTTP version: '#{@resp.args[:http_version]}'."
|
data/spec/http2_spec.rb
CHANGED
@@ -26,7 +26,7 @@ describe "Http2" do
|
|
26
26
|
require "json"
|
27
27
|
|
28
28
|
#Test posting keep-alive and advanced post-data.
|
29
|
-
Http2.new(:host => "www.partyworm.dk") do |http|
|
29
|
+
Http2.new(:host => "www.partyworm.dk", :debug => false) do |http|
|
30
30
|
0.upto(5) do
|
31
31
|
resp = http.get("multipart_test.php")
|
32
32
|
|
@@ -110,4 +110,10 @@ describe "Http2" do
|
|
110
110
|
isgd = Http2.isgdlink("https://github.com/kaspernj/http2")
|
111
111
|
raise "Expected isgd-var to be valid but it wasnt: '#{isgd}'." if !isgd.match(/^http:\/\/is\.gd\/([A-z\d]+)$/)
|
112
112
|
end
|
113
|
+
|
114
|
+
it "should raise exception when something is not found" do
|
115
|
+
expect{
|
116
|
+
res = Http2.new(:host => "www.partyworm.dk").get("something_that_does_not_exist.php")
|
117
|
+
}.to raise_error
|
118
|
+
end
|
113
119
|
end
|
metadata
CHANGED
@@ -1,60 +1,80 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: http2
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.17
|
5
4
|
prerelease:
|
5
|
+
version: 0.0.18
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Kasper Johansen
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-06-
|
12
|
+
date: 2013-06-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
|
16
|
-
requirement: &9884720 !ruby/object:Gem::Requirement
|
15
|
+
version_requirements: !ruby/object:Gem::Requirement
|
17
16
|
none: false
|
18
17
|
requirements:
|
19
18
|
- - ~>
|
20
19
|
- !ruby/object:Gem::Version
|
21
20
|
version: 2.8.0
|
21
|
+
name: rspec
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
|
24
|
+
requirement: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 2.8.0
|
25
30
|
- !ruby/object:Gem::Dependency
|
26
|
-
|
27
|
-
requirement: &9883900 !ruby/object:Gem::Requirement
|
31
|
+
version_requirements: !ruby/object:Gem::Requirement
|
28
32
|
none: false
|
29
33
|
requirements:
|
30
34
|
- - ~>
|
31
35
|
- !ruby/object:Gem::Version
|
32
36
|
version: '3.12'
|
37
|
+
name: rdoc
|
33
38
|
type: :development
|
34
39
|
prerelease: false
|
35
|
-
|
40
|
+
requirement: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '3.12'
|
36
46
|
- !ruby/object:Gem::Dependency
|
37
|
-
|
38
|
-
requirement: &9882980 !ruby/object:Gem::Requirement
|
47
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
48
|
none: false
|
40
49
|
requirements:
|
41
50
|
- - ! '>='
|
42
51
|
- !ruby/object:Gem::Version
|
43
52
|
version: 1.0.0
|
53
|
+
name: bundler
|
44
54
|
type: :development
|
45
55
|
prerelease: false
|
46
|
-
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.0.0
|
47
62
|
- !ruby/object:Gem::Dependency
|
48
|
-
|
49
|
-
requirement: &9881920 !ruby/object:Gem::Requirement
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
64
|
none: false
|
51
65
|
requirements:
|
52
66
|
- - ~>
|
53
67
|
- !ruby/object:Gem::Version
|
54
68
|
version: 1.8.4
|
69
|
+
name: jeweler
|
55
70
|
type: :development
|
56
71
|
prerelease: false
|
57
|
-
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 1.8.4
|
58
78
|
description: A lightweight framework for doing http-connections in Ruby. Supports
|
59
79
|
cookies, keep-alive, compressing and much more.
|
60
80
|
email: k@spernj.org
|
@@ -91,10 +111,10 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
91
111
|
requirements:
|
92
112
|
- - ! '>='
|
93
113
|
- !ruby/object:Gem::Version
|
94
|
-
version: '0'
|
95
114
|
segments:
|
96
115
|
- 0
|
97
|
-
hash:
|
116
|
+
hash: 3868289279396036379
|
117
|
+
version: '0'
|
98
118
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
99
119
|
none: false
|
100
120
|
requirements:
|
@@ -103,7 +123,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
103
123
|
version: '0'
|
104
124
|
requirements: []
|
105
125
|
rubyforge_project:
|
106
|
-
rubygems_version: 1.8.
|
126
|
+
rubygems_version: 1.8.23
|
107
127
|
signing_key:
|
108
128
|
specification_version: 3
|
109
129
|
summary: A lightweight framework for doing http-connections in Ruby. Supports cookies,
|