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.
- checksums.yaml +4 -4
- data/.rubocop.yml +38 -93
- data/.travis.yml +5 -5
- data/.yardopts +2 -0
- data/CHANGES.md +21 -5
- data/Gemfile +12 -9
- data/Guardfile +3 -4
- data/LICENSE.txt +1 -1
- data/README.md +76 -53
- data/Rakefile +1 -1
- data/examples/parallel_requests_with_celluloid.rb +1 -1
- data/http.gemspec +6 -5
- data/lib/http.rb +0 -1
- data/lib/http/chainable.rb +54 -20
- data/lib/http/client.rb +14 -12
- data/lib/http/headers.rb +20 -17
- data/lib/http/mime_type/adapter.rb +1 -1
- data/lib/http/options.rb +1 -1
- data/lib/http/request.rb +23 -16
- data/lib/http/request/writer.rb +2 -7
- data/lib/http/response.rb +47 -76
- data/lib/http/response/body.rb +2 -3
- data/lib/http/response/status.rb +122 -0
- data/lib/http/response/status/reasons.rb +72 -0
- data/lib/http/version.rb +1 -1
- data/logo.png +0 -0
- data/spec/http/client_spec.rb +13 -47
- data/spec/http/content_type_spec.rb +15 -15
- data/spec/http/headers/mixin_spec.rb +1 -1
- data/spec/http/headers_spec.rb +42 -38
- data/spec/http/options/body_spec.rb +1 -1
- data/spec/http/options/form_spec.rb +1 -1
- data/spec/http/options/headers_spec.rb +2 -2
- data/spec/http/options/json_spec.rb +1 -1
- data/spec/http/options/merge_spec.rb +1 -1
- data/spec/http/options/new_spec.rb +2 -2
- data/spec/http/options/proxy_spec.rb +1 -1
- data/spec/http/options_spec.rb +1 -1
- data/spec/http/redirector_spec.rb +1 -1
- data/spec/http/request/writer_spec.rb +72 -24
- data/spec/http/request_spec.rb +31 -35
- data/spec/http/response/body_spec.rb +1 -1
- data/spec/http/response/status_spec.rb +139 -0
- data/spec/http/response_spec.rb +7 -7
- data/spec/http_spec.rb +41 -37
- data/spec/spec_helper.rb +2 -10
- data/spec/support/example_server.rb +14 -86
- data/spec/support/example_server/servlet.rb +102 -0
- metadata +46 -21
- data/lib/http/authorization_header.rb +0 -37
- data/lib/http/authorization_header/basic_auth.rb +0 -24
- data/lib/http/authorization_header/bearer_token.rb +0 -28
- data/lib/http/backports.rb +0 -2
- data/lib/http/backports/base64.rb +0 -6
- data/lib/http/backports/uri.rb +0 -131
- data/spec/http/authorization_header/basic_auth_spec.rb +0 -29
- data/spec/http/authorization_header/bearer_token_spec.rb +0 -36
- data/spec/http/authorization_header_spec.rb +0 -41
- data/spec/http/backports/base64_spec.rb +0 -13
- data/spec/http/backports/uri_spec.rb +0 -9
- data/spec/support/black_hole.rb +0 -5
- data/spec/support/create_certs.rb +0 -57
- data/spec/support/dummy_server.rb +0 -52
- data/spec/support/dummy_server/servlet.rb +0 -30
- data/spec/support/servers/config.rb +0 -13
- data/spec/support/servers/runner.rb +0 -17
data/lib/http/response.rb
CHANGED
@@ -1,119 +1,90 @@
|
|
1
|
-
require '
|
1
|
+
require 'forwardable'
|
2
|
+
|
2
3
|
require 'http/headers'
|
3
4
|
require 'http/content_type'
|
4
5
|
require 'http/mime_type'
|
6
|
+
require 'http/response/status'
|
5
7
|
|
6
8
|
module HTTP
|
7
9
|
class Response
|
10
|
+
extend Forwardable
|
11
|
+
|
8
12
|
include HTTP::Headers::Mixin
|
9
13
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
202 => 'Accepted',
|
17
|
-
203 => 'Non-Authoritative Information',
|
18
|
-
204 => 'No Content',
|
19
|
-
205 => 'Reset Content',
|
20
|
-
206 => 'Partial Content',
|
21
|
-
207 => 'Multi-Status',
|
22
|
-
226 => 'IM Used',
|
23
|
-
300 => 'Multiple Choices',
|
24
|
-
301 => 'Moved Permanently',
|
25
|
-
302 => 'Found',
|
26
|
-
303 => 'See Other',
|
27
|
-
304 => 'Not Modified',
|
28
|
-
305 => 'Use Proxy',
|
29
|
-
306 => 'Reserved',
|
30
|
-
307 => 'Temporary Redirect',
|
31
|
-
400 => 'Bad Request',
|
32
|
-
401 => 'Unauthorized',
|
33
|
-
402 => 'Payment Required',
|
34
|
-
403 => 'Forbidden',
|
35
|
-
404 => 'Not Found',
|
36
|
-
405 => 'Method Not Allowed',
|
37
|
-
406 => 'Not Acceptable',
|
38
|
-
407 => 'Proxy Authentication Required',
|
39
|
-
408 => 'Request Timeout',
|
40
|
-
409 => 'Conflict',
|
41
|
-
410 => 'Gone',
|
42
|
-
411 => 'Length Required',
|
43
|
-
412 => 'Precondition Failed',
|
44
|
-
413 => 'Request Entity Too Large',
|
45
|
-
414 => 'Request-URI Too Long',
|
46
|
-
415 => 'Unsupported Media Type',
|
47
|
-
416 => 'Requested Range Not Satisfiable',
|
48
|
-
417 => 'Expectation Failed',
|
49
|
-
418 => "I'm a Teapot",
|
50
|
-
422 => 'Unprocessable Entity',
|
51
|
-
423 => 'Locked',
|
52
|
-
424 => 'Failed Dependency',
|
53
|
-
426 => 'Upgrade Required',
|
54
|
-
500 => 'Internal Server Error',
|
55
|
-
501 => 'Not Implemented',
|
56
|
-
502 => 'Bad Gateway',
|
57
|
-
503 => 'Service Unavailable',
|
58
|
-
504 => 'Gateway Timeout',
|
59
|
-
505 => 'HTTP Version Not Supported',
|
60
|
-
506 => 'Variant Also Negotiates',
|
61
|
-
507 => 'Insufficient Storage',
|
62
|
-
510 => 'Not Extended'
|
63
|
-
}
|
64
|
-
STATUS_CODES.freeze
|
65
|
-
|
66
|
-
SYMBOL_TO_STATUS_CODE = Hash[STATUS_CODES.map { |code, msg| [msg.downcase.gsub(/\s|-/, '_').to_sym, code] }]
|
67
|
-
SYMBOL_TO_STATUS_CODE.freeze
|
14
|
+
# @deprecated Will be removed in 1.0.0
|
15
|
+
# Use Status::REASONS
|
16
|
+
STATUS_CODES = Status::REASONS
|
17
|
+
|
18
|
+
# @deprecated Will be removed in 1.0.0
|
19
|
+
SYMBOL_TO_STATUS_CODE = Hash[STATUS_CODES.map { |k, v| [v.downcase.gsub(/\s|-/, '_').to_sym, k] }].freeze
|
68
20
|
|
21
|
+
# @return [Status]
|
69
22
|
attr_reader :status
|
23
|
+
|
24
|
+
# @return [Body]
|
70
25
|
attr_reader :body
|
71
|
-
attr_reader :uri
|
72
26
|
|
73
|
-
#
|
74
|
-
|
75
|
-
alias_method :status_code, :status
|
27
|
+
# @return [URI, nil]
|
28
|
+
attr_reader :uri
|
76
29
|
|
77
30
|
def initialize(status, version, headers, body, uri = nil) # rubocop:disable ParameterLists
|
78
|
-
@
|
31
|
+
@version, @body, @uri = version, body, uri
|
32
|
+
|
33
|
+
@status = HTTP::Response::Status.new status
|
79
34
|
@headers = HTTP::Headers.coerce(headers || {})
|
80
35
|
end
|
81
36
|
|
82
|
-
#
|
83
|
-
|
84
|
-
|
85
|
-
|
37
|
+
# @!method reason
|
38
|
+
# @return (see HTTP::Response::Status#reason)
|
39
|
+
def_delegator :status, :reason
|
40
|
+
|
41
|
+
# @!method code
|
42
|
+
# @return (see HTTP::Response::Status#code)
|
43
|
+
def_delegator :status, :code
|
44
|
+
|
45
|
+
# @deprecated Will be removed in 1.0.0
|
46
|
+
alias_method :status_code, :code
|
47
|
+
|
48
|
+
# @!method to_s
|
49
|
+
# (see HTTP::Response::Body#to_s)
|
50
|
+
def_delegator :body, :to_s
|
51
|
+
alias_method :to_str, :to_s
|
52
|
+
|
53
|
+
# @!method readpartial
|
54
|
+
# (see HTTP::Response::Body#readpartial)
|
55
|
+
def_delegator :body, :readpartial
|
86
56
|
|
87
57
|
# Returns an Array ala Rack: `[status, headers, body]`
|
58
|
+
#
|
59
|
+
# @return [Array(Fixnum, Hash, String)]
|
88
60
|
def to_a
|
89
|
-
[status, headers.to_h, body.to_s]
|
61
|
+
[status.to_i, headers.to_h, body.to_s]
|
90
62
|
end
|
91
63
|
|
92
|
-
# Return the response body as a string
|
93
|
-
def to_s
|
94
|
-
body.to_s
|
95
|
-
end
|
96
|
-
alias_method :to_str, :to_s
|
97
|
-
|
98
64
|
# Flushes body and returns self-reference
|
65
|
+
#
|
66
|
+
# @return [Response]
|
99
67
|
def flush
|
100
68
|
body.to_s
|
101
69
|
self
|
102
70
|
end
|
103
71
|
|
104
72
|
# Parsed Content-Type header
|
73
|
+
#
|
105
74
|
# @return [HTTP::ContentType]
|
106
75
|
def content_type
|
107
76
|
@content_type ||= ContentType.parse headers['Content-Type']
|
108
77
|
end
|
109
78
|
|
110
79
|
# MIME type of response (if any)
|
80
|
+
#
|
111
81
|
# @return [String, nil]
|
112
82
|
def mime_type
|
113
83
|
@mime_type ||= content_type.mime_type
|
114
84
|
end
|
115
85
|
|
116
86
|
# Charset of response (if any)
|
87
|
+
#
|
117
88
|
# @return [String, nil]
|
118
89
|
def charset
|
119
90
|
@charset ||= content_type.charset
|
@@ -131,7 +102,7 @@ module HTTP
|
|
131
102
|
|
132
103
|
# Inspect a response
|
133
104
|
def inspect
|
134
|
-
"#<#{self.class}/#{@version} #{
|
105
|
+
"#<#{self.class}/#{@version} #{code} #{reason} #{headers.inspect}>"
|
135
106
|
end
|
136
107
|
end
|
137
108
|
end
|
data/lib/http/response/body.rb
CHANGED
@@ -15,8 +15,7 @@ module HTTP
|
|
15
15
|
@contents = nil
|
16
16
|
end
|
17
17
|
|
18
|
-
#
|
19
|
-
# @see HTTP::Client#readpartial
|
18
|
+
# (see HTTP::Client#readpartial)
|
20
19
|
def readpartial(*args)
|
21
20
|
stream!
|
22
21
|
@client.readpartial(*args)
|
@@ -29,7 +28,7 @@ module HTTP
|
|
29
28
|
end
|
30
29
|
end
|
31
30
|
|
32
|
-
#
|
31
|
+
# @return [String] eagerly consume the entire body as a string
|
33
32
|
def to_s
|
34
33
|
return @contents if @contents
|
35
34
|
fail StateError, 'body is being streamed' unless @streaming.nil?
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
|
3
|
+
require 'http/response/status/reasons'
|
4
|
+
|
5
|
+
module HTTP
|
6
|
+
class Response
|
7
|
+
class Status < ::Delegator
|
8
|
+
class << self
|
9
|
+
# Coerces given value to Status.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
#
|
13
|
+
# Status.coerce(:bad_request) # => Status.new(400)
|
14
|
+
# Status.coerce("400") # => Status.new(400)
|
15
|
+
# Status.coerce(true) # => raises HTTP::Error
|
16
|
+
#
|
17
|
+
# @raise [Error] if coercion is impossible
|
18
|
+
# @param [Symbol, #to_i] object
|
19
|
+
# @return [Status]
|
20
|
+
def coerce(object)
|
21
|
+
code = case
|
22
|
+
when object.is_a?(String) then SYMBOL_CODES[symbolize object]
|
23
|
+
when object.is_a?(Symbol) then SYMBOL_CODES[object]
|
24
|
+
when object.is_a?(Numeric) then object.to_i
|
25
|
+
else nil
|
26
|
+
end
|
27
|
+
|
28
|
+
return new code if code
|
29
|
+
|
30
|
+
fail Error, "Can't coerce #{object.class}(#{object}) to #{self}"
|
31
|
+
end
|
32
|
+
alias_method :[], :coerce
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
# Symbolizes given string
|
37
|
+
#
|
38
|
+
# @example
|
39
|
+
#
|
40
|
+
# symbolize "Bad Request" # => :bad_request
|
41
|
+
# symbolize "Request-URI Too Long" # => :request_uri_too_long
|
42
|
+
# symbolize "I'm a Teapot" # => :im_a_teapot
|
43
|
+
#
|
44
|
+
# @param [#to_s] str
|
45
|
+
# @return [Symbol]
|
46
|
+
def symbolize(str)
|
47
|
+
str.to_s.downcase.gsub(/-/, ' ').gsub(/[^a-z ]/, '').gsub(/\s+/, '_').to_sym
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Code to Symbol map
|
52
|
+
#
|
53
|
+
# @example Usage
|
54
|
+
#
|
55
|
+
# SYMBOLS[400] # => :bad_request
|
56
|
+
# SYMBOLS[414] # => :request_uri_too_long
|
57
|
+
# SYMBOLS[418] # => :im_a_teapot
|
58
|
+
#
|
59
|
+
# @return [Hash<Fixnum => Symbol>]
|
60
|
+
SYMBOLS = Hash[REASONS.map { |k, v| [k, symbolize(v)] }].freeze
|
61
|
+
|
62
|
+
# Reversed {SYMBOLS} map.
|
63
|
+
#
|
64
|
+
# @example Usage
|
65
|
+
#
|
66
|
+
# SYMBOL_CODES[:bad_request] # => 400
|
67
|
+
# SYMBOL_CODES[:request_uri_too_long] # => 414
|
68
|
+
# SYMBOL_CODES[:im_a_teapot] # => 418
|
69
|
+
#
|
70
|
+
# @return [Hash<Symbol => Fixnum>]
|
71
|
+
SYMBOL_CODES = Hash[SYMBOLS.map { |k, v| [v, k] }].freeze
|
72
|
+
|
73
|
+
# @return [Fixnum] status code
|
74
|
+
attr_reader :code
|
75
|
+
|
76
|
+
if RUBY_VERSION < '1.9.0'
|
77
|
+
# @param [#to_i] code
|
78
|
+
def initialize(code)
|
79
|
+
super __setobj__ code
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# @see REASONS
|
84
|
+
# @return [String, nil] status message
|
85
|
+
def reason
|
86
|
+
REASONS[code]
|
87
|
+
end
|
88
|
+
|
89
|
+
# Symbolized {#reason}
|
90
|
+
#
|
91
|
+
# @return [nil] unless code is well-known (see REASONS)
|
92
|
+
# @return [Symbol]
|
93
|
+
def symbolize
|
94
|
+
SYMBOLS[code]
|
95
|
+
end
|
96
|
+
|
97
|
+
# Printable version of HTTP Status, surrounded by quote marks,
|
98
|
+
# with special characters escaped.
|
99
|
+
#
|
100
|
+
# (see String#inspect)
|
101
|
+
def inspect
|
102
|
+
"#{code} #{reason}".inspect
|
103
|
+
end
|
104
|
+
|
105
|
+
SYMBOLS.each do |code, symbol|
|
106
|
+
class_eval <<-RUBY, __FILE__, __LINE__
|
107
|
+
def #{symbol}? # def bad_request?
|
108
|
+
#{code} == code # 400 == code
|
109
|
+
end # end
|
110
|
+
RUBY
|
111
|
+
end
|
112
|
+
|
113
|
+
def __setobj__(obj)
|
114
|
+
@code = obj.to_i
|
115
|
+
end
|
116
|
+
|
117
|
+
def __getobj__
|
118
|
+
@code
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
|
3
|
+
module HTTP
|
4
|
+
class Response
|
5
|
+
class Status < ::Delegator
|
6
|
+
# Code to Reason map
|
7
|
+
#
|
8
|
+
# @example Usage
|
9
|
+
#
|
10
|
+
# REASONS[400] # => "Bad Request"
|
11
|
+
# REASONS[414] # => "Request-URI Too Long"
|
12
|
+
# REASONS[418] # => "I'm a Teapot"
|
13
|
+
#
|
14
|
+
# @return [Hash<Fixnum => String>]
|
15
|
+
REASONS = {
|
16
|
+
100 => 'Continue',
|
17
|
+
101 => 'Switching Protocols',
|
18
|
+
102 => 'Processing',
|
19
|
+
200 => 'OK',
|
20
|
+
201 => 'Created',
|
21
|
+
202 => 'Accepted',
|
22
|
+
203 => 'Non-Authoritative Information',
|
23
|
+
204 => 'No Content',
|
24
|
+
205 => 'Reset Content',
|
25
|
+
206 => 'Partial Content',
|
26
|
+
207 => 'Multi-Status',
|
27
|
+
226 => 'IM Used',
|
28
|
+
300 => 'Multiple Choices',
|
29
|
+
301 => 'Moved Permanently',
|
30
|
+
302 => 'Found',
|
31
|
+
303 => 'See Other',
|
32
|
+
304 => 'Not Modified',
|
33
|
+
305 => 'Use Proxy',
|
34
|
+
306 => 'Reserved',
|
35
|
+
307 => 'Temporary Redirect',
|
36
|
+
308 => 'Permanent Redirect',
|
37
|
+
400 => 'Bad Request',
|
38
|
+
401 => 'Unauthorized',
|
39
|
+
402 => 'Payment Required',
|
40
|
+
403 => 'Forbidden',
|
41
|
+
404 => 'Not Found',
|
42
|
+
405 => 'Method Not Allowed',
|
43
|
+
406 => 'Not Acceptable',
|
44
|
+
407 => 'Proxy Authentication Required',
|
45
|
+
408 => 'Request Timeout',
|
46
|
+
409 => 'Conflict',
|
47
|
+
410 => 'Gone',
|
48
|
+
411 => 'Length Required',
|
49
|
+
412 => 'Precondition Failed',
|
50
|
+
413 => 'Request Entity Too Large',
|
51
|
+
414 => 'Request-URI Too Long',
|
52
|
+
415 => 'Unsupported Media Type',
|
53
|
+
416 => 'Requested Range Not Satisfiable',
|
54
|
+
417 => 'Expectation Failed',
|
55
|
+
418 => "I'm a Teapot",
|
56
|
+
422 => 'Unprocessable Entity',
|
57
|
+
423 => 'Locked',
|
58
|
+
424 => 'Failed Dependency',
|
59
|
+
426 => 'Upgrade Required',
|
60
|
+
500 => 'Internal Server Error',
|
61
|
+
501 => 'Not Implemented',
|
62
|
+
502 => 'Bad Gateway',
|
63
|
+
503 => 'Service Unavailable',
|
64
|
+
504 => 'Gateway Timeout',
|
65
|
+
505 => 'HTTP Version Not Supported',
|
66
|
+
506 => 'Variant Also Negotiates',
|
67
|
+
507 => 'Insufficient Storage',
|
68
|
+
510 => 'Not Extended'
|
69
|
+
}.each { |_, v| v.freeze }.freeze
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/lib/http/version.rb
CHANGED
data/logo.png
CHANGED
Binary file
|
data/spec/http/client_spec.rb
CHANGED
@@ -1,9 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'support/dummy_server'
|
3
2
|
|
4
|
-
describe HTTP::Client do
|
5
|
-
let(:test_endpoint)
|
6
|
-
run_server(:dummy_ssl) { DummyServer.new(:ssl => true) }
|
3
|
+
RSpec.describe HTTP::Client do
|
4
|
+
let(:test_endpoint) { "http://#{ExampleServer::ADDR}" }
|
7
5
|
|
8
6
|
StubbedClient = Class.new(HTTP::Client) do
|
9
7
|
def perform(request, options)
|
@@ -53,7 +51,7 @@ describe HTTP::Client do
|
|
53
51
|
'http://example.com/' => redirect_response('/')
|
54
52
|
)
|
55
53
|
|
56
|
-
expect { client.get('http://example.com/') }
|
54
|
+
expect { client.get('http://example.com/') }
|
57
55
|
.to raise_error(HTTP::Redirector::EndlessRedirectError)
|
58
56
|
end
|
59
57
|
|
@@ -68,7 +66,7 @@ describe HTTP::Client do
|
|
68
66
|
'http://example.com/6' => simple_response('OK')
|
69
67
|
)
|
70
68
|
|
71
|
-
expect { client.get('http://example.com/') }
|
69
|
+
expect { client.get('http://example.com/') }
|
72
70
|
.to raise_error(HTTP::Redirector::TooManyRedirectsError)
|
73
71
|
end
|
74
72
|
end
|
@@ -79,7 +77,7 @@ describe HTTP::Client do
|
|
79
77
|
|
80
78
|
it 'accepts params within the provided URL' do
|
81
79
|
expect(HTTP::Request).to receive(:new) do |_, uri|
|
82
|
-
expect(CGI.parse uri.query).to eq('foo' => %w
|
80
|
+
expect(CGI.parse uri.query).to eq('foo' => %w(bar))
|
83
81
|
end
|
84
82
|
|
85
83
|
client.get('http://example.com/?foo=bar')
|
@@ -87,7 +85,7 @@ describe HTTP::Client do
|
|
87
85
|
|
88
86
|
it 'combines GET params from the URI with the passed in params' do
|
89
87
|
expect(HTTP::Request).to receive(:new) do |_, uri|
|
90
|
-
expect(CGI.parse uri.query).to eq('foo' => %w
|
88
|
+
expect(CGI.parse uri.query).to eq('foo' => %w(bar), 'baz' => %w(quux))
|
91
89
|
end
|
92
90
|
|
93
91
|
client.get('http://example.com/?foo=bar', :params => {:baz => 'quux'})
|
@@ -111,7 +109,7 @@ describe HTTP::Client do
|
|
111
109
|
|
112
110
|
it 'does not corrupts index-less arrays' do
|
113
111
|
expect(HTTP::Request).to receive(:new) do |_, uri|
|
114
|
-
expect(CGI.parse uri.query).to eq 'a[]' => %w
|
112
|
+
expect(CGI.parse uri.query).to eq 'a[]' => %w(b c), 'd' => %w(e)
|
115
113
|
end
|
116
114
|
|
117
115
|
client.get('http://example.com/?a[]=b&a[]=c', :params => {:d => 'e'})
|
@@ -146,43 +144,11 @@ describe HTTP::Client do
|
|
146
144
|
end
|
147
145
|
end
|
148
146
|
|
149
|
-
describe 'SSL' do
|
150
|
-
let(:client) do
|
151
|
-
described_class.new(
|
152
|
-
:ssl_context => OpenSSL::SSL::SSLContext.new.tap do |context|
|
153
|
-
context.options = OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options]
|
154
|
-
|
155
|
-
context.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
156
|
-
context.ca_file = File.join(certs_dir, 'ca.crt')
|
157
|
-
context.cert = OpenSSL::X509::Certificate.new(
|
158
|
-
File.read(File.join(certs_dir, 'client.crt'))
|
159
|
-
)
|
160
|
-
context.key = OpenSSL::PKey::RSA.new(
|
161
|
-
File.read(File.join(certs_dir, 'client.key'))
|
162
|
-
)
|
163
|
-
context
|
164
|
-
end
|
165
|
-
)
|
166
|
-
end
|
167
|
-
|
168
|
-
it 'works via SSL' do
|
169
|
-
response = client.get(dummy_ssl.endpoint)
|
170
|
-
expect(response.body.to_s).to eq('<!doctype html>')
|
171
|
-
end
|
172
|
-
|
173
|
-
context 'with a mismatch host' do
|
174
|
-
it 'errors' do
|
175
|
-
expect { client.get(dummy_ssl.endpoint.gsub('127.0.0.1', 'localhost')) }
|
176
|
-
.to raise_error(OpenSSL::SSL::SSLError, /does not match/)
|
177
|
-
end
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
147
|
describe '#perform' do
|
182
148
|
let(:client) { described_class.new }
|
183
149
|
|
184
150
|
it 'calls finish_response before actual performance' do
|
185
|
-
TCPSocket.
|
151
|
+
allow(TCPSocket).to receive(:open) { throw :halt }
|
186
152
|
expect(client).to receive(:finish_response)
|
187
153
|
catch(:halt) { client.head test_endpoint }
|
188
154
|
end
|
@@ -278,12 +244,12 @@ describe HTTP::Client do
|
|
278
244
|
RESPONSE
|
279
245
|
]
|
280
246
|
|
281
|
-
socket_spy.
|
282
|
-
socket_spy.
|
283
|
-
socket_spy.
|
284
|
-
socket_spy.
|
247
|
+
allow(socket_spy).to receive(:close) { nil }
|
248
|
+
allow(socket_spy).to receive(:closed?) { true }
|
249
|
+
allow(socket_spy).to receive(:readpartial) { chunks.shift }
|
250
|
+
allow(socket_spy).to receive(:<<) { nil }
|
285
251
|
|
286
|
-
TCPSocket.
|
252
|
+
allow(TCPSocket).to receive(:open) { socket_spy }
|
287
253
|
end
|
288
254
|
|
289
255
|
it 'properly reads body' do
|