skylight 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|