http 0.6.4 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of http might be problematic. Click here for more details.

Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +38 -93
  3. data/.travis.yml +5 -5
  4. data/.yardopts +2 -0
  5. data/CHANGES.md +21 -5
  6. data/Gemfile +12 -9
  7. data/Guardfile +3 -4
  8. data/LICENSE.txt +1 -1
  9. data/README.md +76 -53
  10. data/Rakefile +1 -1
  11. data/examples/parallel_requests_with_celluloid.rb +1 -1
  12. data/http.gemspec +6 -5
  13. data/lib/http.rb +0 -1
  14. data/lib/http/chainable.rb +54 -20
  15. data/lib/http/client.rb +14 -12
  16. data/lib/http/headers.rb +20 -17
  17. data/lib/http/mime_type/adapter.rb +1 -1
  18. data/lib/http/options.rb +1 -1
  19. data/lib/http/request.rb +23 -16
  20. data/lib/http/request/writer.rb +2 -7
  21. data/lib/http/response.rb +47 -76
  22. data/lib/http/response/body.rb +2 -3
  23. data/lib/http/response/status.rb +122 -0
  24. data/lib/http/response/status/reasons.rb +72 -0
  25. data/lib/http/version.rb +1 -1
  26. data/logo.png +0 -0
  27. data/spec/http/client_spec.rb +13 -47
  28. data/spec/http/content_type_spec.rb +15 -15
  29. data/spec/http/headers/mixin_spec.rb +1 -1
  30. data/spec/http/headers_spec.rb +42 -38
  31. data/spec/http/options/body_spec.rb +1 -1
  32. data/spec/http/options/form_spec.rb +1 -1
  33. data/spec/http/options/headers_spec.rb +2 -2
  34. data/spec/http/options/json_spec.rb +1 -1
  35. data/spec/http/options/merge_spec.rb +1 -1
  36. data/spec/http/options/new_spec.rb +2 -2
  37. data/spec/http/options/proxy_spec.rb +1 -1
  38. data/spec/http/options_spec.rb +1 -1
  39. data/spec/http/redirector_spec.rb +1 -1
  40. data/spec/http/request/writer_spec.rb +72 -24
  41. data/spec/http/request_spec.rb +31 -35
  42. data/spec/http/response/body_spec.rb +1 -1
  43. data/spec/http/response/status_spec.rb +139 -0
  44. data/spec/http/response_spec.rb +7 -7
  45. data/spec/http_spec.rb +41 -37
  46. data/spec/spec_helper.rb +2 -10
  47. data/spec/support/example_server.rb +14 -86
  48. data/spec/support/example_server/servlet.rb +102 -0
  49. metadata +46 -21
  50. data/lib/http/authorization_header.rb +0 -37
  51. data/lib/http/authorization_header/basic_auth.rb +0 -24
  52. data/lib/http/authorization_header/bearer_token.rb +0 -28
  53. data/lib/http/backports.rb +0 -2
  54. data/lib/http/backports/base64.rb +0 -6
  55. data/lib/http/backports/uri.rb +0 -131
  56. data/spec/http/authorization_header/basic_auth_spec.rb +0 -29
  57. data/spec/http/authorization_header/bearer_token_spec.rb +0 -36
  58. data/spec/http/authorization_header_spec.rb +0 -41
  59. data/spec/http/backports/base64_spec.rb +0 -13
  60. data/spec/http/backports/uri_spec.rb +0 -9
  61. data/spec/support/black_hole.rb +0 -5
  62. data/spec/support/create_certs.rb +0 -57
  63. data/spec/support/dummy_server.rb +0 -52
  64. data/spec/support/dummy_server/servlet.rb +0 -30
  65. data/spec/support/servers/config.rb +0 -13
  66. data/spec/support/servers/runner.rb +0 -17
@@ -1,2 +0,0 @@
1
- require 'http/backports/uri' if RUBY_VERSION < '1.9.3'
2
- require 'http/backports/base64' if RUBY_VERSION < '1.9.0'
@@ -1,6 +0,0 @@
1
- module Base64
2
- # :nodoc:
3
- def self.strict_encode64(data)
4
- encode64(data).gsub(/\n/, '')
5
- end
6
- end
@@ -1,131 +0,0 @@
1
- # Taken from Ruby 1.9's uri/common.rb
2
- # By Akira Yamada <akira@ruby-lang.org>
3
- # License:
4
- # You can redistribute it and/or modify it under the same term as Ruby.
5
-
6
- require 'uri'
7
-
8
- # Backport Ruby 1.9's form encoding/decoding functionality
9
- module URI
10
- TBLENCWWWCOMP_ = {} # :nodoc:
11
- 256.times do |i|
12
- TBLENCWWWCOMP_[i.chr] = format('%%%02X', i)
13
- end
14
- TBLENCWWWCOMP_[' '] = '+'
15
- TBLENCWWWCOMP_.freeze
16
- TBLDECWWWCOMP_ = {} # :nodoc:
17
- 256.times do |i|
18
- h, l = i >> 4, i & 15
19
- TBLDECWWWCOMP_[format('%%%X%X', h, l)] = i.chr
20
- TBLDECWWWCOMP_[format('%%%x%X', h, l)] = i.chr
21
- TBLDECWWWCOMP_[format('%%%X%x', h, l)] = i.chr
22
- TBLDECWWWCOMP_[format('%%%x%x', h, l)] = i.chr
23
- end
24
- TBLDECWWWCOMP_['+'] = ' '
25
- TBLDECWWWCOMP_.freeze
26
-
27
- # Encode given +str+ to URL-encoded form data.
28
- #
29
- # This method doesn't convert *, -, ., 0-9, A-Z, _, a-z, but does convert SP
30
- # (ASCII space) to + and converts others to %XX.
31
- #
32
- # This is an implementation of
33
- # http://www.w3.org/TR/html5/association-of-controls-and-forms.html#url-encoded-form-data
34
- #
35
- # See URI.decode_www_form_component, URI.encode_www_form
36
- def self.encode_www_form_component(str)
37
- str.to_s.gsub(/[^*\-.0-9A-Z_a-z]/) { |chr| TBLENCWWWCOMP_[chr] }
38
- end
39
-
40
- # Decode given +str+ of URL-encoded form data.
41
- #
42
- # This decods + to SP.
43
- #
44
- # See URI.encode_www_form_component, URI.decode_www_form
45
- def self.decode_www_form_component(str)
46
- fail(ArgumentError, "invalid %-encoding (#{str})") unless /\A[^%]*(?:%\h\h[^%]*)*\z/ =~ str
47
- str.gsub(/\+|%\h\h/) { |chr| TBLDECWWWCOMP_[chr] }
48
- end
49
-
50
- # Generate URL-encoded form data from given +enum+.
51
- #
52
- # This generates application/x-www-form-urlencoded data defined in HTML5
53
- # from given an Enumerable object.
54
- #
55
- # This internally uses URI.encode_www_form_component(str).
56
- #
57
- # This method doesn't convert the encoding of given items, so convert them
58
- # before call this method if you want to send data as other than original
59
- # encoding or mixed encoding data. (Strings which are encoded in an HTML5
60
- # ASCII incompatible encoding are converted to UTF-8.)
61
- #
62
- # This method doesn't handle files. When you send a file, use
63
- # multipart/form-data.
64
- #
65
- # This is an implementation of
66
- # http://www.w3.org/TR/html5/forms.html#url-encoded-form-data
67
- #
68
- # URI.encode_www_form([["q", "ruby"], ["lang", "en"]])
69
- # #=> "q=ruby&lang=en"
70
- # URI.encode_www_form("q" => "ruby", "lang" => "en")
71
- # #=> "q=ruby&lang=en"
72
- # URI.encode_www_form("q" => ["ruby", "perl"], "lang" => "en")
73
- # #=> "q=ruby&q=perl&lang=en"
74
- # URI.encode_www_form([["q", "ruby"], ["q", "perl"], ["lang", "en"]])
75
- # #=> "q=ruby&q=perl&lang=en"
76
- #
77
- # See URI.encode_www_form_component, URI.decode_www_form
78
- def self.encode_www_form(enum)
79
- enum.map do |k, v|
80
- if v.nil?
81
- encode_www_form_component(k)
82
- elsif v.respond_to?(:to_ary)
83
- v.to_ary.map do |w|
84
- next unless w
85
-
86
- str = encode_www_form_component(k)
87
- str << '='
88
- str << encode_www_form_component(w)
89
- end.join('&')
90
- else
91
- str = encode_www_form_component(k)
92
- str << '='
93
- str << encode_www_form_component(v)
94
- end
95
- end.join('&')
96
- end
97
-
98
- WFKV_ = '(?:[^%#=;&]*(?:%\h\h[^%#=;&]*)*)' # :nodoc:
99
-
100
- # Decode URL-encoded form data from given +str+.
101
- #
102
- # This decodes application/x-www-form-urlencoded data
103
- # and returns array of key-value array.
104
- # This internally uses URI.decode_www_form_component.
105
- #
106
- # _charset_ hack is not supported now because the mapping from given charset
107
- # to Ruby's encoding is not clear yet.
108
- # see also http://www.w3.org/TR/html5/syntax.html#character-encodings-0
109
- #
110
- # This refers http://www.w3.org/TR/html5/forms.html#url-encoded-form-data
111
- #
112
- # ary = URI.decode_www_form("a=1&a=2&b=3")
113
- # p ary #=> [['a', '1'], ['a', '2'], ['b', '3']]
114
- # p ary.assoc('a').last #=> '1'
115
- # p ary.assoc('b').last #=> '3'
116
- # p ary.rassoc('a').last #=> '2'
117
- # p Hash[ary] # => {"a"=>"2", "b"=>"3"}
118
- #
119
- # See URI.decode_www_form_component, URI.encode_www_form
120
- def self.decode_www_form(str)
121
- return [] if str.empty?
122
- unless /\A#{WFKV_}=#{WFKV_}(?:[;&]#{WFKV_}=#{WFKV_})*\z/o =~ str
123
- fail(ArgumentError, "invalid data of application/x-www-form-urlencoded (#{str})")
124
- end
125
- ary = []
126
- $&.scan(/([^=;&]+)=([^;&]*)/) do
127
- ary << [decode_www_form_component(Regexp.last_match[1]), decode_www_form_component(Regexp.last_match[2])]
128
- end
129
- ary
130
- end
131
- end
@@ -1,29 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe HTTP::AuthorizationHeader::BasicAuth do
4
- describe '.new' do
5
- it 'fails when options is not a Hash' do
6
- expect { described_class.new '[FOOBAR]' }.to raise_error
7
- end
8
-
9
- it 'fails when :pass is not given' do
10
- expect { described_class.new :user => '[USER]' }.to raise_error
11
- end
12
-
13
- it 'fails when :user is not given' do
14
- expect { described_class.new :pass => '[PASS]' }.to raise_error
15
- end
16
- end
17
-
18
- describe '#to_s' do
19
- let(:user) { 'foo' }
20
- let(:pass) { 'bar' * 100 }
21
- let(:user_n_pass) { user + ':' + pass }
22
- let(:builder) { described_class.new :user => user, :pass => pass }
23
-
24
- subject { builder.to_s }
25
-
26
- it { should eq "Basic #{Base64.strict_encode64 user_n_pass}" }
27
- it { should match(/^Basic [^\s]+$/) }
28
- end
29
- end
@@ -1,36 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe HTTP::AuthorizationHeader::BearerToken do
4
- describe '.new' do
5
- it 'fails when options is not a Hash' do
6
- expect { described_class.new '[TOKEN]' }.to raise_error
7
- end
8
-
9
- it 'fails when :token is not given' do
10
- expect { described_class.new :encode => true }.to raise_error
11
- end
12
- end
13
-
14
- describe '#to_s' do
15
- let(:token) { 'foobar' * 100 }
16
- let(:builder) { described_class.new options.merge :token => token }
17
-
18
- subject { builder.to_s }
19
-
20
- context 'when :encode => true' do
21
- let(:options) { {:encode => true} }
22
- it { should eq "Bearer #{Base64.strict_encode64 token}" }
23
- it { should match(/^Bearer [^\s]+$/) }
24
- end
25
-
26
- context 'when :encode => false' do
27
- let(:options) { {:encode => false} }
28
- it { should eq "Bearer #{token}" }
29
- end
30
-
31
- context 'when :encode not specified' do
32
- let(:options) { {} }
33
- it { should eq "Bearer #{token}" }
34
- end
35
- end
36
- end
@@ -1,41 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe HTTP::AuthorizationHeader do
4
- describe '.build' do
5
- context 'with unkown type' do
6
- let(:type) { :foobar }
7
- let(:opts) { {:foo => :bar} }
8
-
9
- it 'fails' do
10
- expect { described_class.build type, opts }.to raise_error
11
- end
12
- end
13
-
14
- context 'with :basic type' do
15
- let(:type) { :basic }
16
- let(:opts) { {:user => 'user', :pass => 'pass'} }
17
-
18
- it 'passes options to BasicAuth' do
19
- expect(described_class::BasicAuth).to receive(:new).with(opts)
20
- described_class.build type, opts
21
- end
22
- end
23
-
24
- context 'with :bearer type' do
25
- let(:type) { :bearer }
26
- let(:opts) { {:token => 'token', :encode => true} }
27
-
28
- it 'passes options to BearerToken' do
29
- expect(described_class::BearerToken).to receive(:new).with(opts)
30
- described_class.build type, opts
31
- end
32
- end
33
- end
34
-
35
- describe '.register' do
36
- it 'registers given klass in builders registry' do
37
- described_class.register :dummy, Class.new { def initialize(*); end }
38
- expect { described_class.build(:dummy, 'foobar') }.to_not raise_error
39
- end
40
- end
41
- end
@@ -1,13 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Base64 do
4
- specify { expect(Base64).to respond_to :strict_encode64 }
5
-
6
- describe '.strict_encode64' do
7
- let(:long_string) { (0...256).map { ('a'..'z').to_a[rand(26)] }.join }
8
-
9
- it 'returns a String without whitespaces' do
10
- expect(Base64.strict_encode64 long_string).to_not match(/\s/)
11
- end
12
- end
13
- end
@@ -1,9 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe URI do
4
- describe '.encode_www_form' do
5
- it 'properly encodes arrays' do
6
- expect(URI.encode_www_form :a => [:b, :c]).to eq 'a=b&a=c'
7
- end
8
- end
9
- end
@@ -1,5 +0,0 @@
1
- module BlackHole
2
- def self.method_missing(*)
3
- self
4
- end
5
- end
@@ -1,57 +0,0 @@
1
- require 'fileutils'
2
- require 'certificate_authority'
3
-
4
- FileUtils.mkdir_p(certs_dir)
5
-
6
- #
7
- # Certificate Authority
8
- #
9
-
10
- ca = CertificateAuthority::Certificate.new
11
-
12
- ca.subject.common_name = 'honestachmed.com'
13
- ca.serial_number.number = 1
14
- ca.key_material.generate_key
15
- ca.signing_entity = true
16
-
17
- ca.sign! 'extensions' => {'keyUsage' => {'usage' => %w[critical keyCertSign]}}
18
-
19
- ca_cert_path = File.join(certs_dir, 'ca.crt')
20
- ca_key_path = File.join(certs_dir, 'ca.key')
21
-
22
- File.write ca_cert_path, ca.to_pem
23
- File.write ca_key_path, ca.key_material.private_key.to_pem
24
-
25
- #
26
- # Server Certificate
27
- #
28
-
29
- server_cert = CertificateAuthority::Certificate.new
30
- server_cert.subject.common_name = '127.0.0.1'
31
- server_cert.serial_number.number = 1
32
- server_cert.key_material.generate_key
33
- server_cert.parent = ca
34
- server_cert.sign!
35
-
36
- server_cert_path = File.join(certs_dir, 'server.crt')
37
- server_key_path = File.join(certs_dir, 'server.key')
38
-
39
- File.write server_cert_path, server_cert.to_pem
40
- File.write server_key_path, server_cert.key_material.private_key.to_pem
41
-
42
- #
43
- # Client Certificate
44
- #
45
-
46
- client_cert = CertificateAuthority::Certificate.new
47
- client_cert.subject.common_name = '127.0.0.1'
48
- client_cert.serial_number.number = 1
49
- client_cert.key_material.generate_key
50
- client_cert.parent = ca
51
- client_cert.sign!
52
-
53
- client_cert_path = File.join(certs_dir, 'client.crt')
54
- client_key_path = File.join(certs_dir, 'client.key')
55
-
56
- File.write client_cert_path, client_cert.to_pem
57
- File.write client_key_path, client_cert.key_material.private_key.to_pem
@@ -1,52 +0,0 @@
1
- require 'webrick'
2
- require 'webrick/ssl'
3
-
4
- require 'support/black_hole'
5
- require 'support/dummy_server/servlet'
6
- require 'support/servers/config'
7
- require 'support/servers/runner'
8
-
9
- class DummyServer < WEBrick::HTTPServer
10
- include ServerConfig
11
-
12
- CONFIG = {
13
- :BindAddress => '127.0.0.1',
14
- :Port => 0,
15
- :AccessLog => BlackHole,
16
- :Logger => BlackHole
17
- }.freeze
18
-
19
- def initialize(options = {})
20
- if options[:ssl]
21
- override_config = {
22
- :SSLEnable => true,
23
- :SSLStartImmediately => true
24
- }
25
- else
26
- override_config = {}
27
- end
28
-
29
- super CONFIG.merge(override_config)
30
-
31
- mount('/', Servlet)
32
- end
33
-
34
- def endpoint
35
- "#{ssl? ? 'https' : 'http'}://#{addr}:#{port}"
36
- end
37
-
38
- def ssl_context
39
- @ssl_context ||= begin
40
- context = OpenSSL::SSL::SSLContext.new
41
- context.verify_mode = OpenSSL::SSL::VERIFY_PEER
42
- context.key = OpenSSL::PKey::RSA.new(
43
- File.read(File.join(certs_dir, 'server.key'))
44
- )
45
- context.cert = OpenSSL::X509::Certificate.new(
46
- File.read(File.join(certs_dir, 'server.crt'))
47
- )
48
- context.ca_file = File.join(certs_dir, 'ca.crt')
49
- context
50
- end
51
- end
52
- end
@@ -1,30 +0,0 @@
1
- class DummyServer < WEBrick::HTTPServer
2
- class Servlet < WEBrick::HTTPServlet::AbstractServlet
3
- def not_found(_req, res)
4
- res.status = 404
5
- res.body = 'Not Found'
6
- end
7
-
8
- def self.handlers
9
- @handlers ||= {}
10
- end
11
-
12
- %w[get post head].each do |method|
13
- class_eval <<-RUBY, __FILE__, __LINE__
14
- def self.#{method}(path, &block)
15
- handlers["#{method}:\#{path}"] = block
16
- end
17
- def do_#{method.upcase}(req, res)
18
- handler = self.class.handlers["#{method}:\#{req.path}"]
19
- return instance_exec(req, res, &handler) if handler
20
- not_found
21
- end
22
- RUBY
23
- end
24
-
25
- get '/' do |_req, res|
26
- res.status = 200
27
- res.body = '<!doctype html>'
28
- end
29
- end
30
- end
@@ -1,13 +0,0 @@
1
- module ServerConfig
2
- def ssl?
3
- !!config[:SSLEnable]
4
- end
5
-
6
- def addr
7
- config[:BindAddress]
8
- end
9
-
10
- def port
11
- config[:Port]
12
- end
13
- end
@@ -1,17 +0,0 @@
1
- module ServerRunner
2
- def run_server(name, &block)
3
- let! name do
4
- server = block.call
5
-
6
- Thread.new { server.start }
7
-
8
- server
9
- end
10
-
11
- after do
12
- send(name).shutdown
13
- end
14
- end
15
- end
16
-
17
- RSpec.configure { |c| c.extend ServerRunner }