http2 0.0.17 → 0.0.18
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/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,
|