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,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe HTTP::Request do
3
+ RSpec.describe HTTP::Request do
4
4
  let(:headers) { {:accept => 'text/html'} }
5
5
  let(:request_uri) { 'http://example.com/' }
6
6
 
@@ -19,6 +19,17 @@ describe HTTP::Request do
19
19
  expect(request.scheme).to eq(:http)
20
20
  end
21
21
 
22
+ it 'provides a #verb accessor' do
23
+ expect(subject.verb).to eq(:get)
24
+ end
25
+
26
+ it 'provides a #__method__ method that outputs a deprecation warning and delegates to Object#method' do
27
+ warning = capture_warning do
28
+ expect(subject.__method__(:verb)).to eq(subject.method(:verb))
29
+ end
30
+ expect(warning).to match(/\[DEPRECATION\] HTTP::Request#__method__ is deprecated\. Use #method instead\.$/)
31
+ end
32
+
22
33
  it 'sets given headers' do
23
34
  expect(subject['Accept']).to eq('text/html')
24
35
  end
@@ -54,21 +65,6 @@ describe HTTP::Request do
54
65
  end
55
66
  end
56
67
 
57
- it 'provides a #verb accessor' do
58
- expect(subject.verb).to eq(:get)
59
- end
60
-
61
- it 'provides a #method accessor that outputs a deprecation warning and returns the verb' do
62
- warning = capture_warning do
63
- expect(subject.method).to eq(subject.verb)
64
- end
65
- expect(warning).to match(/\[DEPRECATION\] HTTP::Request#method is deprecated\. Use #verb instead\. For Object#method, use #__method__\.$/)
66
- end
67
-
68
- it 'provides a #__method__ method that delegates to Object#method' do
69
- expect(subject.__method__(:verb)).to be_a(Method)
70
- end
71
-
72
68
  describe '#redirect' do
73
69
  let(:headers) { {:accept => 'text/html'} }
74
70
  let(:proxy) { {:proxy_username => 'douglas', :proxy_password => 'adams'} }
@@ -77,11 +73,11 @@ describe HTTP::Request do
77
73
 
78
74
  subject(:redirected) { request.redirect 'http://blog.example.com/' }
79
75
 
80
- its(:uri) { should eq URI.parse 'http://blog.example.com/' }
76
+ its(:uri) { is_expected.to eq URI.parse 'http://blog.example.com/' }
81
77
 
82
- its(:verb) { should eq request.verb }
83
- its(:body) { should eq request.body }
84
- its(:proxy) { should eq request.proxy }
78
+ its(:verb) { is_expected.to eq request.verb }
79
+ its(:body) { is_expected.to eq request.body }
80
+ its(:proxy) { is_expected.to eq request.proxy }
85
81
 
86
82
  it 'presets new Host header' do
87
83
  expect(redirected['Host']).to eq 'blog.example.com'
@@ -90,11 +86,11 @@ describe HTTP::Request do
90
86
  context 'with schema-less absolute URL given' do
91
87
  subject(:redirected) { request.redirect '//another.example.com/blog' }
92
88
 
93
- its(:uri) { should eq URI.parse 'http://another.example.com/blog' }
89
+ its(:uri) { is_expected.to eq URI.parse 'http://another.example.com/blog' }
94
90
 
95
- its(:verb) { should eq request.verb }
96
- its(:body) { should eq request.body }
97
- its(:proxy) { should eq request.proxy }
91
+ its(:verb) { is_expected.to eq request.verb }
92
+ its(:body) { is_expected.to eq request.body }
93
+ its(:proxy) { is_expected.to eq request.proxy }
98
94
 
99
95
  it 'presets new Host header' do
100
96
  expect(redirected['Host']).to eq 'another.example.com'
@@ -104,11 +100,11 @@ describe HTTP::Request do
104
100
  context 'with relative URL given' do
105
101
  subject(:redirected) { request.redirect '/blog' }
106
102
 
107
- its(:uri) { should eq URI.parse 'http://example.com/blog' }
103
+ its(:uri) { is_expected.to eq URI.parse 'http://example.com/blog' }
108
104
 
109
- its(:verb) { should eq request.verb }
110
- its(:body) { should eq request.body }
111
- its(:proxy) { should eq request.proxy }
105
+ its(:verb) { is_expected.to eq request.verb }
106
+ its(:body) { is_expected.to eq request.body }
107
+ its(:proxy) { is_expected.to eq request.proxy }
112
108
 
113
109
  it 'keeps Host header' do
114
110
  expect(redirected['Host']).to eq 'example.com'
@@ -116,18 +112,18 @@ describe HTTP::Request do
116
112
 
117
113
  context 'with original URI having non-standard port' do
118
114
  let(:request) { HTTP::Request.new(:post, 'http://example.com:8080/', headers, proxy, body) }
119
- its(:uri) { should eq URI.parse 'http://example.com:8080/blog' }
115
+ its(:uri) { is_expected.to eq URI.parse 'http://example.com:8080/blog' }
120
116
  end
121
117
  end
122
118
 
123
119
  context 'with relative URL that misses leading slash given' do
124
120
  subject(:redirected) { request.redirect 'blog' }
125
121
 
126
- its(:uri) { should eq URI.parse 'http://example.com/blog' }
122
+ its(:uri) { is_expected.to eq URI.parse 'http://example.com/blog' }
127
123
 
128
- its(:verb) { should eq request.verb }
129
- its(:body) { should eq request.body }
130
- its(:proxy) { should eq request.proxy }
124
+ its(:verb) { is_expected.to eq request.verb }
125
+ its(:body) { is_expected.to eq request.body }
126
+ its(:proxy) { is_expected.to eq request.proxy }
131
127
 
132
128
  it 'keeps Host header' do
133
129
  expect(redirected['Host']).to eq 'example.com'
@@ -135,13 +131,13 @@ describe HTTP::Request do
135
131
 
136
132
  context 'with original URI having non-standard port' do
137
133
  let(:request) { HTTP::Request.new(:post, 'http://example.com:8080/', headers, proxy, body) }
138
- its(:uri) { should eq URI.parse 'http://example.com:8080/blog' }
134
+ its(:uri) { is_expected.to eq URI.parse 'http://example.com:8080/blog' }
139
135
  end
140
136
  end
141
137
 
142
138
  context 'with new verb given' do
143
139
  subject { request.redirect 'http://blog.example.com/', :get }
144
- its(:verb) { should be :get }
140
+ its(:verb) { is_expected.to be :get }
145
141
  end
146
142
  end
147
143
  end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe HTTP::Response::Body do
3
+ RSpec.describe HTTP::Response::Body do
4
4
  let(:client) { double }
5
5
  let(:chunks) { ['Hello, ', 'World!'] }
6
6
 
@@ -0,0 +1,139 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe HTTP::Response::Status do
4
+ describe '.new' do
5
+ it 'fails if given value does not respond to #to_i' do
6
+ expect { described_class.new double }.to raise_error
7
+ end
8
+
9
+ it 'accepts any object that responds to #to_i' do
10
+ expect { described_class.new double :to_i => 200 }.to_not raise_error
11
+ end
12
+ end
13
+
14
+ describe '#code' do
15
+ subject { described_class.new('200.0').code }
16
+ it { is_expected.to eq 200 }
17
+ it { is_expected.to be_a Fixnum }
18
+ end
19
+
20
+ describe '#reason' do
21
+ subject { described_class.new(code).reason }
22
+
23
+ context 'with unknown code' do
24
+ let(:code) { 1024 }
25
+ it { is_expected.to be_nil }
26
+ end
27
+
28
+ described_class::REASONS.each do |code, reason|
29
+ class_eval <<-RUBY
30
+ context 'with well-known code: #{code}' do
31
+ let(:code) { #{code} }
32
+ it { is_expected.to eq #{reason.inspect} }
33
+ it { is_expected.to be_frozen }
34
+ end
35
+ RUBY
36
+ end
37
+ end
38
+
39
+ describe '#symbolize' do
40
+ subject { described_class.new(code).symbolize }
41
+
42
+ context 'with unknown code' do
43
+ let(:code) { 1024 }
44
+ it { is_expected.to be_nil }
45
+ end
46
+
47
+ described_class::SYMBOLS.each do |code, symbol|
48
+ class_eval <<-RUBY
49
+ context 'with well-known code: #{code}' do
50
+ let(:code) { #{code} }
51
+ it { is_expected.to be #{symbol.inspect} }
52
+ end
53
+ RUBY
54
+ end
55
+ end
56
+
57
+ describe '#inspect' do
58
+ it 'returns quoted code and reason phrase' do
59
+ status = described_class.new 200
60
+ expect(status.inspect).to eq '"200 OK"'
61
+ end
62
+ end
63
+
64
+ # testing edge cases only
65
+ describe '::SYMBOLS' do
66
+ subject { described_class::SYMBOLS }
67
+
68
+ # "OK"
69
+ its([200]) { is_expected.to be :ok }
70
+
71
+ # "Bad Request"
72
+ its([400]) { is_expected.to be :bad_request }
73
+
74
+ # "Request-URI Too Long"
75
+ its([414]) { is_expected.to be :request_uri_too_long }
76
+
77
+ # "I'm a Teapot"
78
+ its([418]) { is_expected.to be :im_a_teapot }
79
+ end
80
+
81
+ described_class::SYMBOLS.each do |code, symbol|
82
+ class_eval <<-RUBY
83
+ describe '##{symbol}?' do
84
+ subject { status.#{symbol}? }
85
+
86
+ context 'when code is #{code}' do
87
+ let(:status) { described_class.new #{code} }
88
+ it { is_expected.to be true }
89
+ end
90
+
91
+ context 'when code is higher than #{code}' do
92
+ let(:status) { described_class.new #{code + 1} }
93
+ it { is_expected.to be false }
94
+ end
95
+
96
+ context 'when code is lower than #{code}' do
97
+ let(:status) { described_class.new #{code - 1} }
98
+ it { is_expected.to be false }
99
+ end
100
+ end
101
+ RUBY
102
+ end
103
+
104
+ describe '.coerce' do
105
+ context 'with String' do
106
+ it 'coerces reasons' do
107
+ expect(described_class.coerce 'Bad request').to eq described_class.new 400
108
+ end
109
+
110
+ it 'fails when reason is unknown' do
111
+ expect { described_class.coerce 'foobar' }.to raise_error HTTP::Error
112
+ end
113
+ end
114
+
115
+ context 'with Symbol' do
116
+ it 'coerces symbolized reasons' do
117
+ expect(described_class.coerce :bad_request).to eq described_class.new 400
118
+ end
119
+
120
+ it 'fails when symbolized reason is unknown' do
121
+ expect { described_class.coerce :foobar }.to raise_error HTTP::Error
122
+ end
123
+ end
124
+
125
+ context 'with Numeric' do
126
+ it 'coerces as Fixnum code' do
127
+ expect(described_class.coerce 200.1).to eq described_class.new 200
128
+ end
129
+ end
130
+
131
+ it 'fails if coercion failed' do
132
+ expect { described_class.coerce true }.to raise_error HTTP::Error
133
+ end
134
+
135
+ it 'is aliased as `.[]`' do
136
+ expect(described_class.method :coerce).to eq described_class.method :[]
137
+ end
138
+ end
139
+ end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe HTTP::Response do
3
+ RSpec.describe HTTP::Response do
4
4
  it 'includes HTTP::Headers::Mixin' do
5
5
  expect(described_class).to include HTTP::Headers::Mixin
6
6
  end
@@ -20,17 +20,17 @@ describe HTTP::Response do
20
20
 
21
21
  context 'without Content-Type header' do
22
22
  let(:headers) { {} }
23
- it { should be_nil }
23
+ it { is_expected.to be_nil }
24
24
  end
25
25
 
26
26
  context 'with Content-Type: text/html' do
27
27
  let(:headers) { {'Content-Type' => 'text/html'} }
28
- it { should eq 'text/html' }
28
+ it { is_expected.to eq 'text/html' }
29
29
  end
30
30
 
31
31
  context 'with Content-Type: text/html; charset=utf-8' do
32
32
  let(:headers) { {'Content-Type' => 'text/html; charset=utf-8'} }
33
- it { should eq 'text/html' }
33
+ it { is_expected.to eq 'text/html' }
34
34
  end
35
35
  end
36
36
 
@@ -39,17 +39,17 @@ describe HTTP::Response do
39
39
 
40
40
  context 'without Content-Type header' do
41
41
  let(:headers) { {} }
42
- it { should be_nil }
42
+ it { is_expected.to be_nil }
43
43
  end
44
44
 
45
45
  context 'with Content-Type: text/html' do
46
46
  let(:headers) { {'Content-Type' => 'text/html'} }
47
- it { should be_nil }
47
+ it { is_expected.to be_nil }
48
48
  end
49
49
 
50
50
  context 'with Content-Type: text/html; charset=utf-8' do
51
51
  let(:headers) { {'Content-Type' => 'text/html; charset=utf-8'} }
52
- it { should eq 'utf-8' }
52
+ it { is_expected.to eq 'utf-8' }
53
53
  end
54
54
  end
55
55
 
@@ -1,38 +1,38 @@
1
1
  require 'spec_helper'
2
2
  require 'json'
3
3
 
4
- describe HTTP do
5
- let(:test_endpoint) { "http://127.0.0.1:#{ExampleService::PORT}/" }
4
+ RSpec.describe HTTP do
5
+ let(:test_endpoint) { "http://#{ExampleServer::ADDR}" }
6
6
 
7
7
  context 'getting resources' do
8
- it 'should be easy' do
8
+ it 'is easy' do
9
9
  response = HTTP.get test_endpoint
10
10
  expect(response.to_s).to match(/<!doctype html>/)
11
11
  end
12
12
 
13
13
  context 'with URI instance' do
14
- it 'should be easy' do
15
- response = HTTP.get URI(test_endpoint)
14
+ it 'is easy' do
15
+ response = HTTP.get URI test_endpoint
16
16
  expect(response.to_s).to match(/<!doctype html>/)
17
17
  end
18
18
  end
19
19
 
20
20
  context 'with query string parameters' do
21
21
  it 'is easy' do
22
- response = HTTP.get "#{test_endpoint}params", :params => {:foo => 'bar'}
22
+ response = HTTP.get "#{test_endpoint}/params", :params => {:foo => 'bar'}
23
23
  expect(response.to_s).to match(/Params!/)
24
24
  end
25
25
  end
26
26
 
27
27
  context 'with query string parameters in the URI and opts hash' do
28
28
  it 'includes both' do
29
- response = HTTP.get "#{test_endpoint}multiple-params?foo=bar", :params => {:baz => 'quux'}
29
+ response = HTTP.get "#{test_endpoint}/multiple-params?foo=bar", :params => {:baz => 'quux'}
30
30
  expect(response.to_s).to match(/More Params!/)
31
31
  end
32
32
  end
33
33
 
34
34
  context 'with headers' do
35
- it 'should be easy' do
35
+ it 'is easy' do
36
36
  response = HTTP.accept('application/json').get test_endpoint
37
37
  expect(response.to_s.include?('json')).to be true
38
38
  end
@@ -40,14 +40,14 @@ describe HTTP do
40
40
  end
41
41
 
42
42
  context 'with http proxy address and port' do
43
- it 'should proxy the request' do
43
+ it 'proxies the request' do
44
44
  response = HTTP.via('127.0.0.1', 8080).get test_endpoint
45
45
  expect(response.headers['X-Proxied']).to eq 'true'
46
46
  end
47
47
  end
48
48
 
49
49
  context 'with http proxy address, port username and password' do
50
- it 'should proxy the request' do
50
+ it 'proxies the request' do
51
51
  response = HTTP.via('127.0.0.1', 8081, 'username', 'password').get test_endpoint
52
52
  expect(response.headers['X-Proxied']).to eq 'true'
53
53
  end
@@ -66,40 +66,40 @@ describe HTTP do
66
66
  end
67
67
 
68
68
  context 'without proxy port' do
69
- it 'should raise an argument error' do
69
+ it 'raises an argument error' do
70
70
  expect { HTTP.via('127.0.0.1') }.to raise_error HTTP::RequestError
71
71
  end
72
72
  end
73
73
 
74
- context 'posting to resources' do
75
- it 'should be easy to post forms' do
76
- response = HTTP.post "#{test_endpoint}form", :form => {:example => 'testing-form'}
74
+ context 'posting forms to resources' do
75
+ it 'is easy' do
76
+ response = HTTP.post "#{test_endpoint}/form", :form => {:example => 'testing-form'}
77
77
  expect(response.to_s).to eq('passed :)')
78
78
  end
79
79
  end
80
80
 
81
81
  context 'posting with an explicit body' do
82
- it 'should be easy to post' do
83
- response = HTTP.post "#{test_endpoint}body", :body => 'testing-body'
82
+ it 'is easy' do
83
+ response = HTTP.post "#{test_endpoint}/body", :body => 'testing-body'
84
84
  expect(response.to_s).to eq('passed :)')
85
85
  end
86
86
  end
87
87
 
88
88
  context 'with redirects' do
89
- it 'should be easy for 301' do
90
- response = HTTP.with_follow(true).get("#{test_endpoint}redirect-301")
89
+ it 'is easy for 301' do
90
+ response = HTTP.with_follow(true).get("#{test_endpoint}/redirect-301")
91
91
  expect(response.to_s).to match(/<!doctype html>/)
92
92
  end
93
93
 
94
- it 'should be easy for 302' do
95
- response = HTTP.with_follow(true).get("#{test_endpoint}redirect-302")
94
+ it 'is easy for 302' do
95
+ response = HTTP.with_follow(true).get("#{test_endpoint}/redirect-302")
96
96
  expect(response.to_s).to match(/<!doctype html>/)
97
97
  end
98
98
 
99
99
  end
100
100
 
101
101
  context 'head requests' do
102
- it 'should be easy' do
102
+ it 'is easy' do
103
103
  response = HTTP.head test_endpoint
104
104
  expect(response.status).to eq(200)
105
105
  expect(response['content-type']).to match(/html/)
@@ -107,30 +107,34 @@ describe HTTP do
107
107
  end
108
108
 
109
109
  describe '.auth' do
110
- context 'with no arguments' do
111
- specify { expect { HTTP.auth }.to raise_error }
110
+ it 'sets Authorization header to the given value' do
111
+ client = HTTP.auth 'abc'
112
+ expect(client.default_headers[:authorization]).to eq 'abc'
112
113
  end
113
114
 
114
- context 'with one argument' do
115
- it 'returns branch with Authorization header as is' do
116
- expect(HTTP).to receive(:with) \
117
- .with :authorization => 'foobar'
115
+ it 'accepts any #to_s object' do
116
+ client = HTTP.auth double :to_s => 'abc'
117
+ expect(client.default_headers[:authorization]).to eq 'abc'
118
+ end
119
+ end
118
120
 
119
- HTTP.auth :foobar
120
- end
121
+ describe '.basic_auth' do
122
+ it 'fails when options is not a Hash' do
123
+ expect { HTTP.basic_auth '[FOOBAR]' }.to raise_error
121
124
  end
122
125
 
123
- context 'with two arguments' do
124
- it 'builds value with AuthorizationHeader builder' do
125
- expect(HTTP::AuthorizationHeader).to receive(:build) \
126
- .with(:bearer, :token => 'token')
126
+ it 'fails when :pass is not given' do
127
+ expect { HTTP.basic_auth :user => '[USER]' }.to raise_error
128
+ end
127
129
 
128
- HTTP.auth :bearer, :token => 'token'
129
- end
130
+ it 'fails when :user is not given' do
131
+ expect { HTTP.basic_auth :pass => '[PASS]' }.to raise_error
130
132
  end
131
133
 
132
- context 'with more than two arguments' do
133
- specify { expect { HTTP.auth 1, 2, 3 }.to raise_error }
134
+ it 'sets Authorization header with proper BasicAuth value' do
135
+ client = HTTP.basic_auth :user => 'foo', :pass => 'bar'
136
+ expect(client.default_headers[:authorization])
137
+ .to match(/^Basic [A-Za-z0-9+\/]+=*$/)
134
138
  end
135
139
  end
136
140
  end