skylight 0.0.5 → 0.0.6
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/lib/skylight.rb +1 -4
- data/lib/skylight/json_proto.rb +3 -1
- data/lib/skylight/middleware.rb +28 -6
- data/lib/skylight/railtie.rb +2 -4
- data/lib/skylight/version.rb +1 -1
- data/lib/skylight/worker.rb +28 -25
- metadata +3 -16
- data/lib/skylight/vendor/excon.rb +0 -160
- data/lib/skylight/vendor/excon/cacert.pem +0 -3367
- data/lib/skylight/vendor/excon/connection.rb +0 -438
- data/lib/skylight/vendor/excon/constants.rb +0 -50
- data/lib/skylight/vendor/excon/errors.rb +0 -140
- data/lib/skylight/vendor/excon/middlewares/base.rb +0 -23
- data/lib/skylight/vendor/excon/middlewares/expects.rb +0 -22
- data/lib/skylight/vendor/excon/middlewares/instrumentor.rb +0 -31
- data/lib/skylight/vendor/excon/middlewares/mock.rb +0 -88
- data/lib/skylight/vendor/excon/response.rb +0 -68
- data/lib/skylight/vendor/excon/socket.rb +0 -206
- data/lib/skylight/vendor/excon/ssl_socket.rb +0 -100
- data/lib/skylight/vendor/excon/standard_instrumentor.rb +0 -19
@@ -1,140 +0,0 @@
|
|
1
|
-
module Skylight
|
2
|
-
module Vendor
|
3
|
-
module Excon
|
4
|
-
module Errors
|
5
|
-
|
6
|
-
class Error < StandardError; end
|
7
|
-
class StubNotFound < StandardError; end
|
8
|
-
|
9
|
-
class SocketError < Error
|
10
|
-
attr_reader :socket_error
|
11
|
-
|
12
|
-
def initialize(socket_error=nil)
|
13
|
-
if socket_error.message =~ /certificate verify failed/
|
14
|
-
super('Unable to verify certificate, please set `Excon.defaults[:ssl_ca_path] = path_to_certs`, `Excon.defaults[:ssl_ca_file] = path_to_file`, or `Excon.defaults[:ssl_verify_peer] = false` (less secure).')
|
15
|
-
else
|
16
|
-
super("#{socket_error.message} (#{socket_error.class})")
|
17
|
-
end
|
18
|
-
set_backtrace(socket_error.backtrace)
|
19
|
-
@socket_error = socket_error
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
class Timeout < Error; end
|
24
|
-
|
25
|
-
class ProxyParseError < Error; end
|
26
|
-
|
27
|
-
class ProxyConnectionError < Error; end
|
28
|
-
|
29
|
-
class HTTPStatusError < Error
|
30
|
-
attr_reader :request, :response
|
31
|
-
|
32
|
-
def initialize(msg, request = nil, response = nil)
|
33
|
-
super(msg)
|
34
|
-
@request = request
|
35
|
-
@response = response
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
class Continue < HTTPStatusError; end # 100
|
40
|
-
class SwitchingProtocols < HTTPStatusError; end # 101
|
41
|
-
class OK < HTTPStatusError; end # 200
|
42
|
-
class Created < HTTPStatusError; end # 201
|
43
|
-
class Accepted < HTTPStatusError; end # 202
|
44
|
-
class NonAuthoritativeInformation < HTTPStatusError; end # 203
|
45
|
-
class NoContent < HTTPStatusError; end # 204
|
46
|
-
class ResetContent < HTTPStatusError; end # 205
|
47
|
-
class PartialContent < HTTPStatusError; end # 206
|
48
|
-
class MultipleChoices < HTTPStatusError; end # 300
|
49
|
-
class MovedPermanently < HTTPStatusError; end # 301
|
50
|
-
class Found < HTTPStatusError; end # 302
|
51
|
-
class SeeOther < HTTPStatusError; end # 303
|
52
|
-
class NotModified < HTTPStatusError; end # 304
|
53
|
-
class UseProxy < HTTPStatusError; end # 305
|
54
|
-
class TemporaryRedirect < HTTPStatusError; end # 307
|
55
|
-
class BadRequest < HTTPStatusError; end # 400
|
56
|
-
class Unauthorized < HTTPStatusError; end # 401
|
57
|
-
class PaymentRequired < HTTPStatusError; end # 402
|
58
|
-
class Forbidden < HTTPStatusError; end # 403
|
59
|
-
class NotFound < HTTPStatusError; end # 404
|
60
|
-
class MethodNotAllowed < HTTPStatusError; end # 405
|
61
|
-
class NotAcceptable < HTTPStatusError; end # 406
|
62
|
-
class ProxyAuthenticationRequired < HTTPStatusError; end # 407
|
63
|
-
class RequestTimeout < HTTPStatusError; end # 408
|
64
|
-
class Conflict < HTTPStatusError; end # 409
|
65
|
-
class Gone < HTTPStatusError; end # 410
|
66
|
-
class LengthRequired < HTTPStatusError; end # 411
|
67
|
-
class PreconditionFailed < HTTPStatusError; end # 412
|
68
|
-
class RequestEntityTooLarge < HTTPStatusError; end # 413
|
69
|
-
class RequestURITooLong < HTTPStatusError; end # 414
|
70
|
-
class UnsupportedMediaType < HTTPStatusError; end # 415
|
71
|
-
class RequestedRangeNotSatisfiable < HTTPStatusError; end # 416
|
72
|
-
class ExpectationFailed < HTTPStatusError; end # 417
|
73
|
-
class UnprocessableEntity < HTTPStatusError; end # 422
|
74
|
-
class InternalServerError < HTTPStatusError; end # 500
|
75
|
-
class NotImplemented < HTTPStatusError; end # 501
|
76
|
-
class BadGateway < HTTPStatusError; end # 502
|
77
|
-
class ServiceUnavailable < HTTPStatusError; end # 503
|
78
|
-
class GatewayTimeout < HTTPStatusError; end # 504
|
79
|
-
|
80
|
-
# Messages for nicer exceptions, from rfc2616
|
81
|
-
def self.status_error(request, response)
|
82
|
-
@errors ||= {
|
83
|
-
100 => [Excon::Errors::Continue, 'Continue'],
|
84
|
-
101 => [Excon::Errors::SwitchingProtocols, 'Switching Protocols'],
|
85
|
-
200 => [Excon::Errors::OK, 'OK'],
|
86
|
-
201 => [Excon::Errors::Created, 'Created'],
|
87
|
-
202 => [Excon::Errors::Accepted, 'Accepted'],
|
88
|
-
203 => [Excon::Errors::NonAuthoritativeInformation, 'Non-Authoritative Information'],
|
89
|
-
204 => [Excon::Errors::NoContent, 'No Content'],
|
90
|
-
205 => [Excon::Errors::ResetContent, 'Reset Content'],
|
91
|
-
206 => [Excon::Errors::PartialContent, 'Partial Content'],
|
92
|
-
300 => [Excon::Errors::MultipleChoices, 'Multiple Choices'],
|
93
|
-
301 => [Excon::Errors::MovedPermanently, 'Moved Permanently'],
|
94
|
-
302 => [Excon::Errors::Found, 'Found'],
|
95
|
-
303 => [Excon::Errors::SeeOther, 'See Other'],
|
96
|
-
304 => [Excon::Errors::NotModified, 'Not Modified'],
|
97
|
-
305 => [Excon::Errors::UseProxy, 'Use Proxy'],
|
98
|
-
307 => [Excon::Errors::TemporaryRedirect, 'Temporary Redirect'],
|
99
|
-
400 => [Excon::Errors::BadRequest, 'Bad Request'],
|
100
|
-
401 => [Excon::Errors::Unauthorized, 'Unauthorized'],
|
101
|
-
402 => [Excon::Errors::PaymentRequired, 'Payment Required'],
|
102
|
-
403 => [Excon::Errors::Forbidden, 'Forbidden'],
|
103
|
-
404 => [Excon::Errors::NotFound, 'Not Found'],
|
104
|
-
405 => [Excon::Errors::MethodNotAllowed, 'Method Not Allowed'],
|
105
|
-
406 => [Excon::Errors::NotAcceptable, 'Not Acceptable'],
|
106
|
-
407 => [Excon::Errors::ProxyAuthenticationRequired, 'Proxy Authentication Required'],
|
107
|
-
408 => [Excon::Errors::RequestTimeout, 'Request Timeout'],
|
108
|
-
409 => [Excon::Errors::Conflict, 'Conflict'],
|
109
|
-
410 => [Excon::Errors::Gone, 'Gone'],
|
110
|
-
411 => [Excon::Errors::LengthRequired, 'Length Required'],
|
111
|
-
412 => [Excon::Errors::PreconditionFailed, 'Precondition Failed'],
|
112
|
-
413 => [Excon::Errors::RequestEntityTooLarge, 'Request Entity Too Large'],
|
113
|
-
414 => [Excon::Errors::RequestURITooLong, 'Request-URI Too Long'],
|
114
|
-
415 => [Excon::Errors::UnsupportedMediaType, 'Unsupported Media Type'],
|
115
|
-
416 => [Excon::Errors::RequestedRangeNotSatisfiable, 'Request Range Not Satisfiable'],
|
116
|
-
417 => [Excon::Errors::ExpectationFailed, 'Expectation Failed'],
|
117
|
-
422 => [Excon::Errors::UnprocessableEntity, 'Unprocessable Entity'],
|
118
|
-
500 => [Excon::Errors::InternalServerError, 'InternalServerError'],
|
119
|
-
501 => [Excon::Errors::NotImplemented, 'Not Implemented'],
|
120
|
-
502 => [Excon::Errors::BadGateway, 'Bad Gateway'],
|
121
|
-
503 => [Excon::Errors::ServiceUnavailable, 'Service Unavailable'],
|
122
|
-
504 => [Excon::Errors::GatewayTimeout, 'Gateway Timeout']
|
123
|
-
}
|
124
|
-
|
125
|
-
error, message = @errors[response[:status]] || [Excon::Errors::HTTPStatusError, 'Unknown']
|
126
|
-
|
127
|
-
# scrub authorization
|
128
|
-
request = request.dup
|
129
|
-
request.reject! {|key, value| [:connection, :stack].include?(key)}
|
130
|
-
if request.has_key?(:headers) && request[:headers].has_key?('Authorization')
|
131
|
-
request[:headers] = request[:headers].dup
|
132
|
-
request[:headers]['Authorization'] = REDACTED
|
133
|
-
end
|
134
|
-
error.new("Expected(#{request[:expects].inspect}) <=> Actual(#{response[:status]} #{message})\n request => #{request.inspect}\n response => #{response.inspect}", request, response)
|
135
|
-
end
|
136
|
-
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
module Skylight
|
2
|
-
module Vendor
|
3
|
-
module Excon
|
4
|
-
module Middleware
|
5
|
-
class Base
|
6
|
-
def initialize(stack)
|
7
|
-
@stack = stack
|
8
|
-
end
|
9
|
-
|
10
|
-
def request_call(datum)
|
11
|
-
# do stuff
|
12
|
-
@stack.request_call(datum)
|
13
|
-
end
|
14
|
-
|
15
|
-
def response_call(datum)
|
16
|
-
@stack.response_call(datum)
|
17
|
-
# do stuff
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
module Skylight
|
2
|
-
module Vendor
|
3
|
-
module Excon
|
4
|
-
module Middleware
|
5
|
-
class Expects < Excon::Middleware::Base
|
6
|
-
def response_call(datum)
|
7
|
-
if datum.has_key?(:expects) && ![*datum[:expects]].include?(datum[:response][:status])
|
8
|
-
raise(
|
9
|
-
Excon::Errors.status_error(
|
10
|
-
datum.reject {|key,value| key == :response},
|
11
|
-
datum[:response]
|
12
|
-
)
|
13
|
-
)
|
14
|
-
else
|
15
|
-
@stack.response_call(datum)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
module Skylight
|
2
|
-
module Vendor
|
3
|
-
module Excon
|
4
|
-
module Middleware
|
5
|
-
class Instrumentor < Excon::Middleware::Base
|
6
|
-
def request_call(datum)
|
7
|
-
if datum.has_key?(:instrumentor)
|
8
|
-
if datum[:retries_remaining] < datum[:retry_limit]
|
9
|
-
event_name = "#{datum[:instrumentor_name]}.retry"
|
10
|
-
else
|
11
|
-
event_name = "#{datum[:instrumentor_name]}.request"
|
12
|
-
end
|
13
|
-
datum[:instrumentor].instrument(event_name, datum) do
|
14
|
-
@stack.request_call(datum)
|
15
|
-
end
|
16
|
-
else
|
17
|
-
@stack.request_call(datum)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def response_call(datum)
|
22
|
-
if datum.has_key?(:instrumentor)
|
23
|
-
datum[:instrumentor].instrument("#{datum[:instrumentor_name]}.response", datum[:response])
|
24
|
-
end
|
25
|
-
@stack.response_call(datum)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
@@ -1,88 +0,0 @@
|
|
1
|
-
module Skylight
|
2
|
-
module Vendor
|
3
|
-
module Excon
|
4
|
-
module Middleware
|
5
|
-
class Mock < Excon::Middleware::Base
|
6
|
-
def request_call(datum)
|
7
|
-
if datum[:mock]
|
8
|
-
# convert File/Tempfile body to string before matching:
|
9
|
-
unless datum[:body].nil? || datum[:body].is_a?(String)
|
10
|
-
if datum[:body].respond_to?(:binmode)
|
11
|
-
datum[:body].binmode
|
12
|
-
end
|
13
|
-
if datum[:body].respond_to?(:rewind)
|
14
|
-
datum[:body].rewind
|
15
|
-
end
|
16
|
-
datum[:body] = datum[:body].read
|
17
|
-
end
|
18
|
-
|
19
|
-
datum[:captures] = {:headers => {}} # setup data to hold captures
|
20
|
-
Excon.stubs.each do |stub, response|
|
21
|
-
headers_match = !stub.has_key?(:headers) || stub[:headers].keys.all? do |key|
|
22
|
-
case value = stub[:headers][key]
|
23
|
-
when Regexp
|
24
|
-
if match = value.match(datum[:headers][key])
|
25
|
-
datum[:captures][:headers][key] = match.captures
|
26
|
-
end
|
27
|
-
match
|
28
|
-
else
|
29
|
-
value == datum[:headers][key]
|
30
|
-
end
|
31
|
-
end
|
32
|
-
non_headers_match = (stub.keys - [:headers]).all? do |key|
|
33
|
-
case value = stub[key]
|
34
|
-
when Regexp
|
35
|
-
if match = value.match(datum[key])
|
36
|
-
datum[:captures][key] = match.captures
|
37
|
-
end
|
38
|
-
match
|
39
|
-
else
|
40
|
-
value == datum[key]
|
41
|
-
end
|
42
|
-
end
|
43
|
-
if headers_match && non_headers_match
|
44
|
-
datum[:response] = {
|
45
|
-
:body => '',
|
46
|
-
:headers => {},
|
47
|
-
:status => 200,
|
48
|
-
:remote_ip => '127.0.0.1'
|
49
|
-
}
|
50
|
-
|
51
|
-
stub_datum = case response
|
52
|
-
when Proc
|
53
|
-
response.call(datum)
|
54
|
-
else
|
55
|
-
response
|
56
|
-
end
|
57
|
-
|
58
|
-
datum[:response].merge!(stub_datum.reject {|key,value| key == :headers})
|
59
|
-
if stub_datum.has_key?(:headers)
|
60
|
-
datum[:response][:headers].merge!(stub_datum[:headers])
|
61
|
-
end
|
62
|
-
|
63
|
-
if datum[:expects] && ![*datum[:expects]].include?(datum[:response][:status])
|
64
|
-
# don't pass stuff into a block if there was an error
|
65
|
-
elsif datum.has_key?(:response_block) && datum[:response].has_key?(:body)
|
66
|
-
body = datum[:response].delete(:body)
|
67
|
-
content_length = remaining = body.bytesize
|
68
|
-
i = 0
|
69
|
-
while i < body.length
|
70
|
-
datum[:response_block].call(body[i, datum[:chunk_size]], [remaining - datum[:chunk_size], 0].max, content_length)
|
71
|
-
remaining -= datum[:chunk_size]
|
72
|
-
i += datum[:chunk_size]
|
73
|
-
end
|
74
|
-
end
|
75
|
-
return @stack.request_call(datum)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
# if we reach here no stubs matched
|
79
|
-
raise(Excon::Errors::StubNotFound.new('no stubs matched ' << datum.inspect))
|
80
|
-
else
|
81
|
-
@stack.request_call(datum)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
@@ -1,68 +0,0 @@
|
|
1
|
-
module Skylight
|
2
|
-
module Vendor
|
3
|
-
module Excon
|
4
|
-
class Response
|
5
|
-
|
6
|
-
attr_accessor :data
|
7
|
-
|
8
|
-
# backwards compatability reader/writers
|
9
|
-
def body=(new_body)
|
10
|
-
@data[:body] = new_body
|
11
|
-
end
|
12
|
-
def body
|
13
|
-
@data[:body]
|
14
|
-
end
|
15
|
-
def headers=(new_headers)
|
16
|
-
@data[:headers] = new_headers
|
17
|
-
end
|
18
|
-
def headers
|
19
|
-
@data[:headers]
|
20
|
-
end
|
21
|
-
def status=(new_status)
|
22
|
-
@data[:status] = new_status
|
23
|
-
end
|
24
|
-
def status
|
25
|
-
@data[:status]
|
26
|
-
end
|
27
|
-
def remote_ip=(new_remote_ip)
|
28
|
-
@data[:remote_ip] = new_remote_ip
|
29
|
-
end
|
30
|
-
def remote_ip
|
31
|
-
@data[:remote_ip]
|
32
|
-
end
|
33
|
-
|
34
|
-
def initialize(params={})
|
35
|
-
@data = {
|
36
|
-
:body => '',
|
37
|
-
:headers => {}
|
38
|
-
}.merge(params)
|
39
|
-
@body = @data[:body]
|
40
|
-
@headers = @data[:headers]
|
41
|
-
@status = @data[:status]
|
42
|
-
@remote_ip = @data[:remote_ip]
|
43
|
-
end
|
44
|
-
|
45
|
-
def [](key)
|
46
|
-
@data[key]
|
47
|
-
end
|
48
|
-
|
49
|
-
def params
|
50
|
-
$stderr.puts("Excon::Response#params is deprecated use Excon::Response#data instead (#{caller.first})")
|
51
|
-
data
|
52
|
-
end
|
53
|
-
|
54
|
-
# Retrieve a specific header value. Header names are treated case-insensitively.
|
55
|
-
# @param [String] name Header name
|
56
|
-
def get_header(name)
|
57
|
-
headers.each do |key,value|
|
58
|
-
if key.casecmp(name) == 0
|
59
|
-
return value
|
60
|
-
end
|
61
|
-
end
|
62
|
-
nil
|
63
|
-
end
|
64
|
-
|
65
|
-
end # class Response
|
66
|
-
end # module Excon
|
67
|
-
end
|
68
|
-
end
|
@@ -1,206 +0,0 @@
|
|
1
|
-
module Skylight
|
2
|
-
module Vendor
|
3
|
-
module Excon
|
4
|
-
class Socket
|
5
|
-
|
6
|
-
extend Forwardable
|
7
|
-
|
8
|
-
attr_accessor :data
|
9
|
-
|
10
|
-
def params
|
11
|
-
$stderr.puts("Excon::Socket#params is deprecated use Excon::Socket#data instead (#{caller.first})")
|
12
|
-
@data
|
13
|
-
end
|
14
|
-
def params=(new_params)
|
15
|
-
$stderr.puts("Excon::Socket#params= is deprecated use Excon::Socket#data= instead (#{caller.first})")
|
16
|
-
@data = new_params
|
17
|
-
end
|
18
|
-
|
19
|
-
attr_reader :remote_ip
|
20
|
-
|
21
|
-
def_delegators(:@socket, :close, :close)
|
22
|
-
def_delegators(:@socket, :readline, :readline)
|
23
|
-
|
24
|
-
def initialize(data = {})
|
25
|
-
@data = data
|
26
|
-
@read_buffer = ''
|
27
|
-
@eof = false
|
28
|
-
|
29
|
-
@data[:family] ||= ::Socket::Constants::AF_UNSPEC
|
30
|
-
if @data[:proxy]
|
31
|
-
@data[:proxy][:family] ||= ::Socket::Constants::AF_UNSPEC
|
32
|
-
end
|
33
|
-
|
34
|
-
connect
|
35
|
-
end
|
36
|
-
|
37
|
-
def connect
|
38
|
-
@socket = nil
|
39
|
-
exception = nil
|
40
|
-
|
41
|
-
addrinfo = if @data[:proxy]
|
42
|
-
::Socket.getaddrinfo(@data[:proxy][:host], @data[:proxy][:port], @data[:proxy][:family], ::Socket::Constants::SOCK_STREAM)
|
43
|
-
else
|
44
|
-
::Socket.getaddrinfo(@data[:host], @data[:port], @data[:family], ::Socket::Constants::SOCK_STREAM)
|
45
|
-
end
|
46
|
-
|
47
|
-
addrinfo.each do |_, port, _, ip, a_family, s_type|
|
48
|
-
@remote_ip = ip
|
49
|
-
|
50
|
-
# nonblocking connect
|
51
|
-
begin
|
52
|
-
sockaddr = ::Socket.sockaddr_in(port, ip)
|
53
|
-
|
54
|
-
socket = ::Socket.new(a_family, s_type, 0)
|
55
|
-
|
56
|
-
if @data[:nonblock]
|
57
|
-
socket.connect_nonblock(sockaddr)
|
58
|
-
else
|
59
|
-
begin
|
60
|
-
Timeout.timeout(@data[:connect_timeout]) do
|
61
|
-
socket.connect(sockaddr)
|
62
|
-
end
|
63
|
-
rescue Timeout::Error
|
64
|
-
raise Excon::Errors::Timeout.new('connect timeout reached')
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
@socket = socket
|
69
|
-
break
|
70
|
-
rescue Errno::EINPROGRESS
|
71
|
-
unless IO.select(nil, [socket], nil, @data[:connect_timeout])
|
72
|
-
raise(Excon::Errors::Timeout.new("connect timeout reached"))
|
73
|
-
end
|
74
|
-
begin
|
75
|
-
socket.connect_nonblock(sockaddr)
|
76
|
-
|
77
|
-
@socket = socket
|
78
|
-
break
|
79
|
-
rescue Errno::EISCONN
|
80
|
-
@socket = socket
|
81
|
-
break
|
82
|
-
rescue SystemCallError => exception
|
83
|
-
socket.close
|
84
|
-
next
|
85
|
-
end
|
86
|
-
rescue SystemCallError => exception
|
87
|
-
socket.close
|
88
|
-
next
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
unless @socket
|
93
|
-
# this will be our last encountered exception
|
94
|
-
raise exception
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
def read(max_length=nil)
|
99
|
-
if @eof
|
100
|
-
return nil
|
101
|
-
elsif @data[:nonblock]
|
102
|
-
begin
|
103
|
-
if max_length
|
104
|
-
until @read_buffer.length >= max_length
|
105
|
-
@read_buffer << @socket.read_nonblock(max_length - @read_buffer.length)
|
106
|
-
end
|
107
|
-
else
|
108
|
-
while true
|
109
|
-
@read_buffer << @socket.read_nonblock(@data[:chunk_size])
|
110
|
-
end
|
111
|
-
end
|
112
|
-
rescue OpenSSL::SSL::SSLError => error
|
113
|
-
if error.message == 'read would block'
|
114
|
-
if IO.select([@socket], nil, nil, @data[:read_timeout])
|
115
|
-
retry
|
116
|
-
else
|
117
|
-
raise(Excon::Errors::Timeout.new("read timeout reached"))
|
118
|
-
end
|
119
|
-
else
|
120
|
-
raise(error)
|
121
|
-
end
|
122
|
-
rescue Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitReadable
|
123
|
-
if IO.select([@socket], nil, nil, @data[:read_timeout])
|
124
|
-
retry
|
125
|
-
else
|
126
|
-
raise(Excon::Errors::Timeout.new("read timeout reached"))
|
127
|
-
end
|
128
|
-
rescue EOFError
|
129
|
-
@eof = true
|
130
|
-
end
|
131
|
-
if max_length
|
132
|
-
@read_buffer.slice!(0, max_length)
|
133
|
-
else
|
134
|
-
# read until EOFError, so return everything
|
135
|
-
@read_buffer.slice!(0, @read_buffer.length)
|
136
|
-
end
|
137
|
-
else
|
138
|
-
begin
|
139
|
-
Timeout.timeout(@data[:read_timeout]) do
|
140
|
-
@socket.read(max_length)
|
141
|
-
end
|
142
|
-
rescue Timeout::Error
|
143
|
-
raise Excon::Errors::Timeout.new('read timeout reached')
|
144
|
-
end
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
def write(data)
|
149
|
-
if @data[:nonblock]
|
150
|
-
# We normally return from the return in the else block below, but
|
151
|
-
# we guard that data is still something in case we get weird
|
152
|
-
# values and String#[] returns nil. (This behavior has been observed
|
153
|
-
# in the wild, so this is a simple defensive mechanism)
|
154
|
-
while data
|
155
|
-
begin
|
156
|
-
# I wish that this API accepted a start position, then we wouldn't
|
157
|
-
# have to slice data when there is a short write.
|
158
|
-
written = @socket.write_nonblock(data)
|
159
|
-
rescue OpenSSL::SSL::SSLError => error
|
160
|
-
if error.message == 'write would block'
|
161
|
-
if IO.select(nil, [@socket], nil, @data[:write_timeout])
|
162
|
-
retry
|
163
|
-
else
|
164
|
-
raise(Excon::Errors::Timeout.new("write timeout reached"))
|
165
|
-
end
|
166
|
-
else
|
167
|
-
raise(error)
|
168
|
-
end
|
169
|
-
rescue Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitWritable
|
170
|
-
if IO.select(nil, [@socket], nil, @data[:write_timeout])
|
171
|
-
retry
|
172
|
-
else
|
173
|
-
raise(Excon::Errors::Timeout.new("write timeout reached"))
|
174
|
-
end
|
175
|
-
else
|
176
|
-
# Fast, common case.
|
177
|
-
# The >= seems weird, why would it have written MORE than we
|
178
|
-
# requested. But we're getting some weird behavior when @socket
|
179
|
-
# is an OpenSSL socket, where it seems like it's saying it wrote
|
180
|
-
# more (perhaps due to SSL packet overhead?).
|
181
|
-
#
|
182
|
-
# Pretty weird, but this is a simple defensive mechanism.
|
183
|
-
return if written >= data.size
|
184
|
-
|
185
|
-
# This takes advantage of the fact that most ruby implementations
|
186
|
-
# have Copy-On-Write strings. Thusly why requesting a subrange
|
187
|
-
# of data, we actually don't copy data because the new string
|
188
|
-
# simply references a subrange of the original.
|
189
|
-
data = data[written, data.size]
|
190
|
-
end
|
191
|
-
end
|
192
|
-
else
|
193
|
-
begin
|
194
|
-
Timeout.timeout(@data[:write_timeout]) do
|
195
|
-
@socket.write(data)
|
196
|
-
end
|
197
|
-
rescue Timeout::Error
|
198
|
-
Excon::Errors::Timeout.new('write timeout reached')
|
199
|
-
end
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
|
-
end
|
204
|
-
end
|
205
|
-
end
|
206
|
-
end
|