framed_rails 0.1.0

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.
Files changed (41) hide show
  1. data/.gitignore +11 -0
  2. data/.ruby-version +1 -0
  3. data/CHANGELOG +1 -0
  4. data/Gemfile +3 -0
  5. data/LICENSE +1 -0
  6. data/README.md +107 -0
  7. data/framed_rails.gemspec +37 -0
  8. data/lib/framed/client.rb +34 -0
  9. data/lib/framed/emitters.rb +113 -0
  10. data/lib/framed/example.rb +17 -0
  11. data/lib/framed/exceptions.rb +13 -0
  12. data/lib/framed/okjson.rb +602 -0
  13. data/lib/framed/rails.rb +43 -0
  14. data/lib/framed/railtie.rb +9 -0
  15. data/lib/framed/utils.rb +54 -0
  16. data/lib/framed/version.rb +4 -0
  17. data/lib/framed_rails.rb +71 -0
  18. data/vendor/gems/excon-0.45.3/data/cacert.pem +3860 -0
  19. data/vendor/gems/excon-0.45.3/lib/excon/connection.rb +469 -0
  20. data/vendor/gems/excon-0.45.3/lib/excon/constants.rb +142 -0
  21. data/vendor/gems/excon-0.45.3/lib/excon/errors.rb +155 -0
  22. data/vendor/gems/excon-0.45.3/lib/excon/extensions/uri.rb +33 -0
  23. data/vendor/gems/excon-0.45.3/lib/excon/headers.rb +83 -0
  24. data/vendor/gems/excon-0.45.3/lib/excon/middlewares/base.rb +24 -0
  25. data/vendor/gems/excon-0.45.3/lib/excon/middlewares/decompress.rb +35 -0
  26. data/vendor/gems/excon-0.45.3/lib/excon/middlewares/escape_path.rb +11 -0
  27. data/vendor/gems/excon-0.45.3/lib/excon/middlewares/expects.rb +18 -0
  28. data/vendor/gems/excon-0.45.3/lib/excon/middlewares/idempotent.rb +33 -0
  29. data/vendor/gems/excon-0.45.3/lib/excon/middlewares/instrumentor.rb +34 -0
  30. data/vendor/gems/excon-0.45.3/lib/excon/middlewares/mock.rb +51 -0
  31. data/vendor/gems/excon-0.45.3/lib/excon/middlewares/redirect_follower.rb +56 -0
  32. data/vendor/gems/excon-0.45.3/lib/excon/middlewares/response_parser.rb +12 -0
  33. data/vendor/gems/excon-0.45.3/lib/excon/pretty_printer.rb +45 -0
  34. data/vendor/gems/excon-0.45.3/lib/excon/response.rb +212 -0
  35. data/vendor/gems/excon-0.45.3/lib/excon/socket.rb +310 -0
  36. data/vendor/gems/excon-0.45.3/lib/excon/ssl_socket.rb +151 -0
  37. data/vendor/gems/excon-0.45.3/lib/excon/standard_instrumentor.rb +27 -0
  38. data/vendor/gems/excon-0.45.3/lib/excon/unix_socket.rb +40 -0
  39. data/vendor/gems/excon-0.45.3/lib/excon/utils.rb +87 -0
  40. data/vendor/gems/excon-0.45.3/lib/excon.rb +234 -0
  41. metadata +91 -0
@@ -0,0 +1,212 @@
1
+ module Excon
2
+ class Response
3
+
4
+ attr_accessor :data
5
+
6
+ # backwards compatability reader/writers
7
+ def body=(new_body)
8
+ @data[:body] = new_body
9
+ end
10
+ def body
11
+ @data[:body]
12
+ end
13
+ def headers=(new_headers)
14
+ @data[:headers] = new_headers
15
+ end
16
+ def headers
17
+ @data[:headers]
18
+ end
19
+ def status=(new_status)
20
+ @data[:status] = new_status
21
+ end
22
+ def status
23
+ @data[:status]
24
+ end
25
+ def status_line
26
+ @data[:status_line]
27
+ end
28
+ def status_line=(new_status_line)
29
+ @data[:status_line] = new_status_line
30
+ end
31
+ def reason_phrase=(new_reason_phrase)
32
+ @data[:reason_phrase] = new_reason_phrase
33
+ end
34
+ def reason_phrase
35
+ @data[:reason_phrase]
36
+ end
37
+ def remote_ip=(new_remote_ip)
38
+ @data[:remote_ip] = new_remote_ip
39
+ end
40
+ def remote_ip
41
+ @data[:remote_ip]
42
+ end
43
+ def local_port
44
+ @data[:local_port]
45
+ end
46
+ def local_address
47
+ @data[:local_address]
48
+ end
49
+
50
+ def self.parse(socket, datum)
51
+ # this will discard any trailing lines from the previous response if any.
52
+ begin
53
+ line = socket.readline
54
+ end until status = line[9, 3].to_i
55
+
56
+ reason_phrase = line[13..-3] # -3 strips the trailing "\r\n"
57
+
58
+ datum[:response] = {
59
+ :body => '',
60
+ :headers => Excon::Headers.new,
61
+ :status => status,
62
+ :status_line => line,
63
+ :reason_phrase => reason_phrase
64
+ }
65
+
66
+ unix_proxy = datum[:proxy] ? datum[:proxy][:scheme] == UNIX : false
67
+ unless datum[:scheme] == UNIX || unix_proxy
68
+ datum[:response].merge!(
69
+ :remote_ip => socket.remote_ip,
70
+ :local_port => socket.local_port,
71
+ :local_address => socket.local_address
72
+ )
73
+ end
74
+
75
+ parse_headers(socket, datum)
76
+
77
+ unless (['HEAD', 'CONNECT'].include?(datum[:method].to_s.upcase)) || NO_ENTITY.include?(datum[:response][:status])
78
+
79
+ if key = datum[:response][:headers].keys.detect {|k| k.casecmp('Transfer-Encoding') == 0 }
80
+ encodings = Utils.split_header_value(datum[:response][:headers][key])
81
+ if (encoding = encodings.last) && encoding.casecmp('chunked') == 0
82
+ transfer_encoding_chunked = true
83
+ if encodings.length == 1
84
+ datum[:response][:headers].delete(key)
85
+ else
86
+ datum[:response][:headers][key] = encodings[0...-1].join(', ')
87
+ end
88
+ end
89
+ end
90
+
91
+ # use :response_block unless :expects would fail
92
+ if response_block = datum[:response_block]
93
+ if datum[:middlewares].include?(Excon::Middleware::Expects) && datum[:expects] &&
94
+ !Array(datum[:expects]).include?(datum[:response][:status])
95
+ response_block = nil
96
+ end
97
+ end
98
+
99
+ if transfer_encoding_chunked
100
+ if response_block
101
+ while (chunk_size = socket.readline.chomp!.to_i(16)) > 0
102
+ while chunk_size > 0
103
+ chunk = socket.read(chunk_size)
104
+ chunk_size -= chunk.bytesize
105
+ response_block.call(chunk, nil, nil)
106
+ end
107
+ new_line_size = 2 # 2 == "\r\n".length
108
+ while new_line_size > 0
109
+ new_line_size -= socket.read(new_line_size).length
110
+ end
111
+ end
112
+ else
113
+ while (chunk_size = socket.readline.chomp!.to_i(16)) > 0
114
+ while chunk_size > 0
115
+ chunk = socket.read(chunk_size)
116
+ chunk_size -= chunk.bytesize
117
+ datum[:response][:body] << chunk
118
+ end
119
+ new_line_size = 2 # 2 == "\r\n".length
120
+ while new_line_size > 0
121
+ new_line_size -= socket.read(new_line_size).length
122
+ end
123
+ end
124
+ end
125
+ parse_headers(socket, datum) # merge trailers into headers
126
+ else
127
+ if key = datum[:response][:headers].keys.detect {|k| k.casecmp('Content-Length') == 0 }
128
+ content_length = datum[:response][:headers][key].to_i
129
+ end
130
+
131
+ if remaining = content_length
132
+ if response_block
133
+ while remaining > 0
134
+ chunk = socket.read([datum[:chunk_size], remaining].min)
135
+ response_block.call(chunk, [remaining - chunk.bytesize, 0].max, content_length)
136
+ remaining -= chunk.bytesize
137
+ end
138
+ else
139
+ while remaining > 0
140
+ chunk = socket.read([datum[:chunk_size], remaining].min)
141
+ datum[:response][:body] << chunk
142
+ remaining -= chunk.bytesize
143
+ end
144
+ end
145
+ else
146
+ if response_block
147
+ while chunk = socket.read(datum[:chunk_size])
148
+ response_block.call(chunk, nil, nil)
149
+ end
150
+ else
151
+ while chunk = socket.read(datum[:chunk_size])
152
+ datum[:response][:body] << chunk
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
158
+ datum
159
+ end
160
+
161
+ def self.parse_headers(socket, datum)
162
+ last_key = nil
163
+ until (data = socket.readline.chomp!).empty?
164
+ if !data.lstrip!.nil?
165
+ raise Excon::Errors::ResponseParseError, 'malformed header' unless last_key
166
+ # append to last_key's last value
167
+ datum[:response][:headers][last_key] << ' ' << data.rstrip
168
+ else
169
+ key, value = data.split(':', 2)
170
+ raise Excon::Errors::ResponseParseError, 'malformed header' unless value
171
+ # add key/value or append value to existing values
172
+ datum[:response][:headers][key] = ([datum[:response][:headers][key]] << value.strip).compact.join(', ')
173
+ last_key = key
174
+ end
175
+ end
176
+ end
177
+
178
+ def initialize(params={})
179
+ @data = {
180
+ :body => ''
181
+ }.merge(params)
182
+ @data[:headers] = Excon::Headers.new.merge!(params[:headers] || {})
183
+
184
+ @body = @data[:body]
185
+ @headers = @data[:headers]
186
+ @status = @data[:status]
187
+ @remote_ip = @data[:remote_ip]
188
+ @local_port = @data[:local_port]
189
+ @local_address = @data[:local_address]
190
+ end
191
+
192
+ def [](key)
193
+ @data[key]
194
+ end
195
+
196
+ def params
197
+ Excon.display_warning('Excon::Response#params is deprecated use Excon::Response#data instead.')
198
+ data
199
+ end
200
+
201
+ def pp
202
+ Excon::PrettyPrinter.pp($stdout, @data)
203
+ end
204
+
205
+ # Retrieve a specific header value. Header names are treated case-insensitively.
206
+ # @param [String] name Header name
207
+ def get_header(name)
208
+ headers[name]
209
+ end
210
+
211
+ end # class Response
212
+ end # module Excon
@@ -0,0 +1,310 @@
1
+ module Excon
2
+ class Socket
3
+ include Utils
4
+
5
+ extend Forwardable
6
+
7
+ attr_accessor :data
8
+
9
+ def params
10
+ Excon.display_warning('Excon::Socket#params is deprecated use Excon::Socket#data instead.')
11
+ @data
12
+ end
13
+
14
+ def params=(new_params)
15
+ Excon.display_warning('Excon::Socket#params= is deprecated use Excon::Socket#data= instead.')
16
+ @data = new_params
17
+ end
18
+
19
+ attr_reader :remote_ip
20
+
21
+ def_delegators(:@socket, :close)
22
+
23
+ def initialize(data = {})
24
+ @data = data
25
+ @nonblock = data[:nonblock]
26
+ @read_buffer = ''
27
+ @eof = false
28
+ connect
29
+ end
30
+
31
+ def read(max_length = nil)
32
+ if @eof
33
+ return max_length ? nil : ''
34
+ elsif @nonblock
35
+ read_nonblock(max_length)
36
+ else
37
+ read_block(max_length)
38
+ end
39
+ end
40
+
41
+ def readline
42
+ return legacy_readline if RUBY_VERSION.to_f <= 1.8_7
43
+ buffer = ''
44
+ begin
45
+ buffer << @socket.read_nonblock(1) while buffer[-1] != "\n"
46
+ buffer
47
+ rescue Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitReadable
48
+ if timeout_reached('read')
49
+ raise_timeout_error('read')
50
+ else
51
+ retry
52
+ end
53
+ rescue OpenSSL::SSL::SSLError => e
54
+ if e.message == 'read would block'
55
+ if timeout_reached('read')
56
+ raise_timeout_error('read')
57
+ else
58
+ retry
59
+ end
60
+ else
61
+ raise(error)
62
+ end
63
+ end
64
+ end
65
+
66
+ def legacy_readline
67
+ begin
68
+ Timeout.timeout(@data[:read_timeout]) do
69
+ @socket.readline
70
+ end
71
+ rescue Timeout::Error
72
+ raise Excon::Errors::Timeout.new('read timeout reached')
73
+ end
74
+ end
75
+
76
+ def write(data)
77
+ if @nonblock
78
+ write_nonblock(data)
79
+ else
80
+ write_block(data)
81
+ end
82
+ end
83
+
84
+ def local_address
85
+ unpacked_sockaddr[1]
86
+ end
87
+
88
+ def local_port
89
+ unpacked_sockaddr[0]
90
+ end
91
+
92
+ private
93
+
94
+ def connect
95
+ @socket = nil
96
+ exception = nil
97
+
98
+ if @data[:proxy]
99
+ family = @data[:proxy][:family] || ::Socket::Constants::AF_UNSPEC
100
+ args = [@data[:proxy][:hostname], @data[:proxy][:port], family, ::Socket::Constants::SOCK_STREAM]
101
+ else
102
+ family = @data[:family] || ::Socket::Constants::AF_UNSPEC
103
+ args = [@data[:hostname], @data[:port], family, ::Socket::Constants::SOCK_STREAM]
104
+ end
105
+ if RUBY_VERSION >= '1.9.2' && defined?(RUBY_ENGINE) && RUBY_ENGINE == 'ruby'
106
+ args << nil << nil << false # no reverse lookup
107
+ end
108
+ addrinfo = ::Socket.getaddrinfo(*args)
109
+
110
+ addrinfo.each do |_, port, _, ip, a_family, s_type|
111
+ @remote_ip = ip
112
+
113
+ # already succeeded on previous addrinfo
114
+ if @socket
115
+ break
116
+ end
117
+
118
+ # nonblocking connect
119
+ begin
120
+ sockaddr = ::Socket.sockaddr_in(port, ip)
121
+
122
+ socket = ::Socket.new(a_family, s_type, 0)
123
+
124
+ if @data[:reuseaddr]
125
+ socket.setsockopt(::Socket::Constants::SOL_SOCKET, ::Socket::Constants::SO_REUSEADDR, true)
126
+ if defined?(::Socket::Constants::SO_REUSEPORT)
127
+ socket.setsockopt(::Socket::Constants::SOL_SOCKET, ::Socket::Constants::SO_REUSEPORT, true)
128
+ end
129
+ end
130
+
131
+ if @nonblock
132
+ socket.connect_nonblock(sockaddr)
133
+ else
134
+ socket.connect(sockaddr)
135
+ end
136
+ @socket = socket
137
+ rescue Errno::EINPROGRESS
138
+ unless IO.select(nil, [socket], nil, @data[:connect_timeout])
139
+ raise(Excon::Errors::Timeout.new('connect timeout reached'))
140
+ end
141
+ begin
142
+ socket.connect_nonblock(sockaddr)
143
+ @socket = socket
144
+ rescue Errno::EISCONN
145
+ @socket = socket
146
+ rescue SystemCallError => exception
147
+ socket.close rescue nil
148
+ end
149
+ rescue SystemCallError => exception
150
+ socket.close rescue nil if socket
151
+ end
152
+ end
153
+
154
+ # this will be our last encountered exception
155
+ fail exception unless @socket
156
+
157
+ if @data[:tcp_nodelay]
158
+ @socket.setsockopt(::Socket::IPPROTO_TCP,
159
+ ::Socket::TCP_NODELAY,
160
+ true)
161
+ end
162
+ end
163
+
164
+ def read_nonblock(max_length)
165
+ begin
166
+ if max_length
167
+ until @read_buffer.length >= max_length
168
+ @read_buffer << @socket.read_nonblock(max_length - @read_buffer.length)
169
+ end
170
+ else
171
+ loop do
172
+ @read_buffer << @socket.read_nonblock(@data[:chunk_size])
173
+ end
174
+ end
175
+ rescue OpenSSL::SSL::SSLError => error
176
+ if error.message == 'read would block'
177
+ if timeout_reached('read')
178
+ raise_timeout_error('read')
179
+ else
180
+ retry
181
+ end
182
+ else
183
+ raise(error)
184
+ end
185
+ rescue Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitReadable
186
+ if @read_buffer.empty?
187
+ # if we didn't read anything, try again...
188
+ if timeout_reached('read')
189
+ raise_timeout_error('read')
190
+ else
191
+ retry
192
+ end
193
+ end
194
+ rescue EOFError
195
+ @eof = true
196
+ end
197
+
198
+ if max_length
199
+ if @read_buffer.empty?
200
+ nil # EOF met at beginning
201
+ else
202
+ @read_buffer.slice!(0, max_length)
203
+ end
204
+ else
205
+ # read until EOFError, so return everything
206
+ @read_buffer.slice!(0, @read_buffer.length)
207
+ end
208
+ end
209
+
210
+ def read_block(max_length)
211
+ @socket.read(max_length)
212
+ rescue OpenSSL::SSL::SSLError => error
213
+ if error.message == 'read would block'
214
+ if timeout_reached('read')
215
+ raise_timeout_error('read')
216
+ else
217
+ retry
218
+ end
219
+ else
220
+ raise(error)
221
+ end
222
+ rescue Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitReadable
223
+ if @read_buffer.empty?
224
+ if timeout_reached('read')
225
+ raise_timeout_error('read')
226
+ else
227
+ retry
228
+ end
229
+ end
230
+ rescue EOFError
231
+ @eof = true
232
+ end
233
+
234
+ def write_nonblock(data)
235
+ if FORCE_ENC
236
+ data.force_encoding('BINARY')
237
+ end
238
+ loop do
239
+ written = nil
240
+ begin
241
+ # I wish that this API accepted a start position, then we wouldn't
242
+ # have to slice data when there is a short write.
243
+ written = @socket.write_nonblock(data)
244
+ rescue Errno::EFAULT
245
+ if OpenSSL.const_defined?(:OPENSSL_LIBRARY_VERSION) && OpenSSL::OPENSSL_LIBRARY_VERSION.split(' ')[1] == '1.0.2'
246
+ msg = "The version of OpenSSL this ruby is built against (1.0.2) has a vulnerability
247
+ which causes a fault. For more, see https://github.com/excon/excon/issues/467"
248
+ raise SecurityError.new(msg)
249
+ else
250
+ raise error
251
+ end
252
+ rescue OpenSSL::SSL::SSLError, Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitWritable => error
253
+ if error.is_a?(OpenSSL::SSL::SSLError) && error.message != 'write would block'
254
+ raise error
255
+ else
256
+ if timeout_reached('write')
257
+ raise_timeout_error('write')
258
+ else
259
+ retry
260
+ end
261
+ end
262
+ end
263
+
264
+ # Fast, common case.
265
+ break if written == data.size
266
+
267
+ # This takes advantage of the fact that most ruby implementations
268
+ # have Copy-On-Write strings. Thusly why requesting a subrange
269
+ # of data, we actually don't copy data because the new string
270
+ # simply references a subrange of the original.
271
+ data = data[written, data.size]
272
+ end
273
+ end
274
+
275
+ def write_block(data)
276
+ @socket.write(data)
277
+ rescue OpenSSL::SSL::SSLError, Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitWritable => error
278
+ if error.is_a?(OpenSSL::SSL::SSLError) && error.message != 'write would block'
279
+ raise error
280
+ else
281
+ if timeout_reached('write')
282
+ raise_timeout_error('write')
283
+ else
284
+ retry
285
+ end
286
+ end
287
+ end
288
+
289
+ def timeout_reached(type)
290
+ if type == 'read'
291
+ args = [[@socket], nil, nil, @data[:read_timeout]]
292
+ else
293
+ args = [nil, [@socket], nil, @data[:write_timeout]]
294
+ end
295
+ IO.select(*args) ? nil : true
296
+ end
297
+
298
+ def raise_timeout_error(type)
299
+ fail Excon::Errors::Timeout.new("#{type} timeout reached")
300
+ end
301
+
302
+ def unpacked_sockaddr
303
+ @unpacked_sockaddr ||= ::Socket.unpack_sockaddr_in(@socket.to_io.getsockname)
304
+ rescue ArgumentError => e
305
+ unless e.message == 'not an AF_INET/AF_INET6 sockaddr'
306
+ raise
307
+ end
308
+ end
309
+ end
310
+ end
@@ -0,0 +1,151 @@
1
+ module Excon
2
+ class SSLSocket < Socket
3
+ HAVE_NONBLOCK = [:connect_nonblock, :read_nonblock, :write_nonblock].all? do |m|
4
+ OpenSSL::SSL::SSLSocket.public_method_defined?(m)
5
+ end
6
+
7
+ def initialize(data = {})
8
+ super
9
+
10
+ # create ssl context
11
+ ssl_context = OpenSSL::SSL::SSLContext.new
12
+
13
+ # disable less secure options, when supported
14
+ ssl_context_options = OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options]
15
+ if defined?(OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS)
16
+ ssl_context_options &= ~OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS
17
+ end
18
+
19
+ if defined?(OpenSSL::SSL::OP_NO_COMPRESSION)
20
+ ssl_context_options |= OpenSSL::SSL::OP_NO_COMPRESSION
21
+ end
22
+ ssl_context.options = ssl_context_options
23
+
24
+ ssl_context.ciphers = @data[:ciphers]
25
+ if @data[:ssl_version]
26
+ ssl_context.ssl_version = @data[:ssl_version]
27
+ end
28
+
29
+ if @data[:ssl_verify_peer]
30
+ # turn verification on
31
+ ssl_context.verify_mode = OpenSSL::SSL::VERIFY_PEER
32
+
33
+ if ca_file = @data[:ssl_ca_file] || ENV['SSL_CERT_FILE']
34
+ ssl_context.ca_file = ca_file
35
+ end
36
+ if ca_path = @data[:ssl_ca_path] || ENV['SSL_CERT_DIR']
37
+ ssl_context.ca_path = ca_path
38
+ end
39
+ if cert_store = @data[:ssl_cert_store]
40
+ ssl_context.cert_store = cert_store
41
+ end
42
+
43
+ # no defaults, fallback to bundled
44
+ unless ca_file || ca_path || cert_store
45
+ ssl_context.cert_store = OpenSSL::X509::Store.new
46
+ ssl_context.cert_store.set_default_paths
47
+
48
+ # workaround issue #257 (JRUBY-6970)
49
+ ca_file = DEFAULT_CA_FILE
50
+ ca_file.gsub!(/^jar:/, '') if ca_file =~ /^jar:file:\//
51
+
52
+ begin
53
+ ssl_context.cert_store.add_file(ca_file)
54
+ rescue
55
+ Excon.display_warning("Excon unable to add file to cert store, ignoring: #{ca_file}\n[#{$!.class}] #{$!.message}")
56
+ end
57
+ end
58
+
59
+ if verify_callback = @data[:ssl_verify_callback]
60
+ ssl_context.verify_callback = verify_callback
61
+ end
62
+ else
63
+ # turn verification off
64
+ ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
65
+ end
66
+
67
+ # maintain existing API
68
+ certificate_path = @data[:client_cert] || @data[:certificate_path]
69
+ private_key_path = @data[:client_key] || @data[:private_key_path]
70
+ private_key_pass = @data[:client_key_pass] || @data[:private_key_pass]
71
+
72
+ if certificate_path && private_key_path
73
+ ssl_context.cert = OpenSSL::X509::Certificate.new(File.read(certificate_path))
74
+ if OpenSSL::PKey.respond_to? :read
75
+ ssl_context.key = OpenSSL::PKey.read(File.read(private_key_path), private_key_pass)
76
+ else
77
+ ssl_context.key = OpenSSL::PKey::RSA.new(File.read(private_key_path), private_key_pass)
78
+ end
79
+ elsif @data.key?(:certificate) && @data.key?(:private_key)
80
+ ssl_context.cert = OpenSSL::X509::Certificate.new(@data[:certificate])
81
+ if OpenSSL::PKey.respond_to? :read
82
+ ssl_context.key = OpenSSL::PKey.read(@data[:private_key], private_key_pass)
83
+ else
84
+ ssl_context.key = OpenSSL::PKey::RSA.new(@data[:private_key], private_key_pass)
85
+ end
86
+ end
87
+
88
+ if @data[:proxy]
89
+ request = 'CONNECT ' << @data[:host] << port_string(@data.merge(:omit_default_port => false)) << Excon::HTTP_1_1
90
+ request << 'Host: ' << @data[:host] << port_string(@data) << Excon::CR_NL
91
+
92
+ if @data[:proxy][:password] || @data[:proxy][:user]
93
+ auth = ['' << @data[:proxy][:user].to_s << ':' << @data[:proxy][:password].to_s].pack('m').delete(Excon::CR_NL)
94
+ request << 'Proxy-Authorization: Basic ' << auth << Excon::CR_NL
95
+ end
96
+
97
+ request << 'Proxy-Connection: Keep-Alive' << Excon::CR_NL
98
+
99
+ request << Excon::CR_NL
100
+
101
+ # write out the proxy setup request
102
+ @socket.write(request)
103
+
104
+ # eat the proxy's connection response
105
+ Excon::Response.parse(self, :expects => 200, :method => 'CONNECT')
106
+ end
107
+
108
+ # convert Socket to OpenSSL::SSL::SSLSocket
109
+ @socket = OpenSSL::SSL::SSLSocket.new(@socket, ssl_context)
110
+ @socket.sync_close = true
111
+
112
+ # Server Name Indication (SNI) RFC 3546
113
+ if @socket.respond_to?(:hostname=)
114
+ @socket.hostname = @data[:host]
115
+ end
116
+
117
+ begin
118
+ if @nonblock
119
+ begin
120
+ @socket.connect_nonblock
121
+ rescue Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitReadable
122
+ IO.select([@socket])
123
+ retry
124
+ rescue IO::WaitWritable
125
+ IO.select(nil, [@socket])
126
+ retry
127
+ end
128
+ else
129
+ @socket.connect
130
+ end
131
+ rescue Errno::ETIMEDOUT, Timeout::Error
132
+ raise Excon::Errors::Timeout.new('connect timeout reached')
133
+ end
134
+
135
+ # verify connection
136
+ if @data[:ssl_verify_peer]
137
+ @socket.post_connection_check(@data[:ssl_verify_peer_host] || @data[:host])
138
+ end
139
+
140
+ @socket
141
+ end
142
+
143
+ private
144
+
145
+ def connect
146
+ # backwards compatability for things lacking nonblock
147
+ @nonblock = HAVE_NONBLOCK && @nonblock
148
+ super
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,27 @@
1
+ module Excon
2
+ class StandardInstrumentor
3
+ def self.instrument(name, params = {}, &block)
4
+ params = params.dup
5
+
6
+ # reduce duplication/noise of output
7
+ params.delete(:connection)
8
+ params.delete(:stack)
9
+
10
+ if params.has_key?(:headers) && params[:headers].has_key?('Authorization')
11
+ params[:headers] = params[:headers].dup
12
+ params[:headers]['Authorization'] = REDACTED
13
+ end
14
+
15
+ if params.has_key?(:password)
16
+ params[:password] = REDACTED
17
+ end
18
+
19
+ $stderr.puts(name)
20
+ Excon::PrettyPrinter.pp($stderr, params)
21
+
22
+ if block_given?
23
+ yield
24
+ end
25
+ end
26
+ end
27
+ end