framed_rails 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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,155 @@
1
+ module Excon
2
+ module Errors
3
+
4
+ class Error < StandardError; end
5
+ class StubNotFound < StandardError; end
6
+ class InvalidStub < StandardError; end
7
+
8
+ class SocketError < Error
9
+ attr_reader :socket_error
10
+
11
+ def initialize(socket_error=Excon::Error.new)
12
+ if socket_error.message =~ /certificate verify failed/
13
+ super("Unable to verify certificate, please set `Excon.defaults[:ssl_ca_path] = path_to_certs`, `ENV['SSL_CERT_DIR'] = path_to_certs`, `Excon.defaults[:ssl_ca_file] = path_to_file`, `ENV['SSL_CERT_FILE'] = path_to_file`, `Excon.defaults[:ssl_verify_callback] = callback` (see OpenSSL::SSL::SSLContext#verify_callback), or `Excon.defaults[:ssl_verify_peer] = false` (less secure).")
14
+ else
15
+ super("#{socket_error.message} (#{socket_error.class})")
16
+ end
17
+ set_backtrace(socket_error.backtrace)
18
+ @socket_error = socket_error
19
+ end
20
+ end
21
+
22
+ class Timeout < Error; end
23
+
24
+ class ResponseParseError < Error; end
25
+
26
+ class ProxyParseError < Error; end
27
+
28
+ class ProxyConnectionError < Error; end
29
+
30
+ class HTTPStatusError < Error
31
+ attr_reader :request, :response
32
+
33
+ def initialize(msg, request = nil, response = nil)
34
+ super(msg)
35
+ @request = request
36
+ @response = response
37
+ end
38
+ end
39
+
40
+ # HTTP Error classes
41
+ class Informational < HTTPStatusError; end
42
+ class Success < HTTPStatusError; end
43
+ class Redirection < HTTPStatusError; end
44
+ class ClientError < HTTPStatusError; end
45
+ class ServerError < HTTPStatusError; end
46
+
47
+ class Continue < Informational; end # 100
48
+ class SwitchingProtocols < Informational; end # 101
49
+ class OK < Success; end # 200
50
+ class Created < Success; end # 201
51
+ class Accepted < Success; end # 202
52
+ class NonAuthoritativeInformation < Success; end # 203
53
+ class NoContent < Success; end # 204
54
+ class ResetContent < Success; end # 205
55
+ class PartialContent < Success; end # 206
56
+ class MultipleChoices < Redirection; end # 300
57
+ class MovedPermanently < Redirection; end # 301
58
+ class Found < Redirection; end # 302
59
+ class SeeOther < Redirection; end # 303
60
+ class NotModified < Redirection; end # 304
61
+ class UseProxy < Redirection; end # 305
62
+ class TemporaryRedirect < Redirection; end # 307
63
+ class BadRequest < ClientError; end # 400
64
+ class Unauthorized < ClientError; end # 401
65
+ class PaymentRequired < ClientError; end # 402
66
+ class Forbidden < ClientError; end # 403
67
+ class NotFound < ClientError; end # 404
68
+ class MethodNotAllowed < ClientError; end # 405
69
+ class NotAcceptable < ClientError; end # 406
70
+ class ProxyAuthenticationRequired < ClientError; end # 407
71
+ class RequestTimeout < ClientError; end # 408
72
+ class Conflict < ClientError; end # 409
73
+ class Gone < ClientError; end # 410
74
+ class LengthRequired < ClientError; end # 411
75
+ class PreconditionFailed < ClientError; end # 412
76
+ class RequestEntityTooLarge < ClientError; end # 413
77
+ class RequestURITooLong < ClientError; end # 414
78
+ class UnsupportedMediaType < ClientError; end # 415
79
+ class RequestedRangeNotSatisfiable < ClientError; end # 416
80
+ class ExpectationFailed < ClientError; end # 417
81
+ class UnprocessableEntity < ClientError; end # 422
82
+ class TooManyRequests < ClientError; end # 429
83
+ class InternalServerError < ServerError; end # 500
84
+ class NotImplemented < ServerError; end # 501
85
+ class BadGateway < ServerError; end # 502
86
+ class ServiceUnavailable < ServerError; end # 503
87
+ class GatewayTimeout < ServerError; end # 504
88
+
89
+ # Messages for nicer exceptions, from rfc2616
90
+ def self.status_error(request, response)
91
+ @errors ||= {
92
+ 100 => [Excon::Errors::Continue, 'Continue'],
93
+ 101 => [Excon::Errors::SwitchingProtocols, 'Switching Protocols'],
94
+ 200 => [Excon::Errors::OK, 'OK'],
95
+ 201 => [Excon::Errors::Created, 'Created'],
96
+ 202 => [Excon::Errors::Accepted, 'Accepted'],
97
+ 203 => [Excon::Errors::NonAuthoritativeInformation, 'Non-Authoritative Information'],
98
+ 204 => [Excon::Errors::NoContent, 'No Content'],
99
+ 205 => [Excon::Errors::ResetContent, 'Reset Content'],
100
+ 206 => [Excon::Errors::PartialContent, 'Partial Content'],
101
+ 300 => [Excon::Errors::MultipleChoices, 'Multiple Choices'],
102
+ 301 => [Excon::Errors::MovedPermanently, 'Moved Permanently'],
103
+ 302 => [Excon::Errors::Found, 'Found'],
104
+ 303 => [Excon::Errors::SeeOther, 'See Other'],
105
+ 304 => [Excon::Errors::NotModified, 'Not Modified'],
106
+ 305 => [Excon::Errors::UseProxy, 'Use Proxy'],
107
+ 307 => [Excon::Errors::TemporaryRedirect, 'Temporary Redirect'],
108
+ 400 => [Excon::Errors::BadRequest, 'Bad Request'],
109
+ 401 => [Excon::Errors::Unauthorized, 'Unauthorized'],
110
+ 402 => [Excon::Errors::PaymentRequired, 'Payment Required'],
111
+ 403 => [Excon::Errors::Forbidden, 'Forbidden'],
112
+ 404 => [Excon::Errors::NotFound, 'Not Found'],
113
+ 405 => [Excon::Errors::MethodNotAllowed, 'Method Not Allowed'],
114
+ 406 => [Excon::Errors::NotAcceptable, 'Not Acceptable'],
115
+ 407 => [Excon::Errors::ProxyAuthenticationRequired, 'Proxy Authentication Required'],
116
+ 408 => [Excon::Errors::RequestTimeout, 'Request Timeout'],
117
+ 409 => [Excon::Errors::Conflict, 'Conflict'],
118
+ 410 => [Excon::Errors::Gone, 'Gone'],
119
+ 411 => [Excon::Errors::LengthRequired, 'Length Required'],
120
+ 412 => [Excon::Errors::PreconditionFailed, 'Precondition Failed'],
121
+ 413 => [Excon::Errors::RequestEntityTooLarge, 'Request Entity Too Large'],
122
+ 414 => [Excon::Errors::RequestURITooLong, 'Request-URI Too Long'],
123
+ 415 => [Excon::Errors::UnsupportedMediaType, 'Unsupported Media Type'],
124
+ 416 => [Excon::Errors::RequestedRangeNotSatisfiable, 'Request Range Not Satisfiable'],
125
+ 417 => [Excon::Errors::ExpectationFailed, 'Expectation Failed'],
126
+ 422 => [Excon::Errors::UnprocessableEntity, 'Unprocessable Entity'],
127
+ 429 => [Excon::Errors::TooManyRequests, 'Too Many Requests'],
128
+ 500 => [Excon::Errors::InternalServerError, 'InternalServerError'],
129
+ 501 => [Excon::Errors::NotImplemented, 'Not Implemented'],
130
+ 502 => [Excon::Errors::BadGateway, 'Bad Gateway'],
131
+ 503 => [Excon::Errors::ServiceUnavailable, 'Service Unavailable'],
132
+ 504 => [Excon::Errors::GatewayTimeout, 'Gateway Timeout']
133
+ }
134
+
135
+ error_class, error_message = @errors[response[:status]] || [Excon::Errors::HTTPStatusError, 'Unknown']
136
+
137
+ message = StringIO.new
138
+ message.puts("Expected(#{request[:expects].inspect}) <=> Actual(#{response[:status]} #{error_message})")
139
+
140
+ if request[:debug_request]
141
+ message.puts('excon.error.request')
142
+ Excon::PrettyPrinter.pp(message, request)
143
+ end
144
+
145
+ if request[:debug_response]
146
+ message.puts('excon.error.response')
147
+ Excon::PrettyPrinter.pp(message, response.data)
148
+ end
149
+
150
+ message.rewind
151
+ error_class.new(message.read, request, response)
152
+ end
153
+
154
+ end
155
+ end
@@ -0,0 +1,33 @@
1
+ # TODO: Remove this monkey patch once ruby 1.9.3+ is the minimum supported version.
2
+ #
3
+ # This patch backports URI#hostname to ruby 1.9.2 and older.
4
+ # URI#hostname is used for IPv6 support in Excon.
5
+ #
6
+ # URI#hostname was added in stdlib in v1_9_3_0 in this commit:
7
+ # https://github.com/ruby/ruby/commit/5fd45a4b79dd26f9e7b6dc41142912df911e4d7d
8
+ #
9
+ # Addressable::URI is also an URI parser accepted in some parts of Excon.
10
+ # Addressable::URI#hostname was added in addressable-2.3.5+ in this commit:
11
+ # https://github.com/sporkmonger/addressable/commit/1b94abbec1f914d5f707c92a10efbb9e69aab65e
12
+ #
13
+ # Users who want to use Addressable::URI to parse URIs must upgrade to 2.3.5 or newer.
14
+ require 'uri'
15
+ unless URI("http://foo/bar").respond_to?(:hostname)
16
+ module URI
17
+ class Generic
18
+ # extract the host part of the URI and unwrap brackets for IPv6 addresses.
19
+ #
20
+ # This method is same as URI::Generic#host except
21
+ # brackets for IPv6 (and future IP) addresses are removed.
22
+ #
23
+ # u = URI("http://[::1]/bar")
24
+ # p u.hostname #=> "::1"
25
+ # p u.host #=> "[::1]"
26
+ #
27
+ def hostname
28
+ v = self.host
29
+ /\A\[(.*)\]\z/ =~ v ? $1 : v
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,83 @@
1
+ module Excon
2
+ class Headers < Hash
3
+
4
+ SENTINEL = {}
5
+
6
+ alias_method :raw_writer, :[]=
7
+ alias_method :raw_reader, :[]
8
+ if SENTINEL.respond_to?(:assoc)
9
+ alias_method :raw_assoc, :assoc
10
+ end
11
+ alias_method :raw_delete, :delete
12
+ alias_method :raw_fetch, :fetch
13
+ alias_method :raw_has_key?, :has_key?
14
+ alias_method :raw_include?, :include?
15
+ alias_method :raw_key?, :key?
16
+ alias_method :raw_member?, :member?
17
+ alias_method :raw_merge, :merge
18
+ alias_method :raw_merge!, :merge!
19
+ alias_method :raw_rehash, :rehash
20
+ alias_method :raw_store, :store
21
+ alias_method :raw_values_at, :values_at
22
+
23
+ def initialize
24
+ @downcased = {}
25
+ end
26
+
27
+ def [](key)
28
+ @downcased[key.to_s.downcase]
29
+ end
30
+
31
+ alias_method :[]=, :store
32
+ def []=(key, value)
33
+ raw_writer(key, value)
34
+ @downcased[key.to_s.downcase] = value
35
+ end
36
+
37
+ if SENTINEL.respond_to? :assoc
38
+ def assoc(obj)
39
+ @downcased.assoc(obj.downcase)
40
+ end
41
+ end
42
+
43
+ def delete(key, &proc)
44
+ raw_delete(key, &proc)
45
+ @downcased.delete(key.to_s.downcase, &proc)
46
+ end
47
+
48
+ def fetch(key, default = nil, &proc)
49
+ if proc
50
+ @downcased.fetch(key.to_s.downcase, &proc)
51
+ else
52
+ @downcased.fetch(key.to_s.downcase, default)
53
+ end
54
+ end
55
+
56
+ alias_method :has_key?, :key?
57
+ alias_method :has_key?, :member?
58
+ def has_key?(key)
59
+ raw_key?(key) || @downcased.has_key?(key.to_s.downcase)
60
+ end
61
+
62
+ def merge(other_hash)
63
+ self.dup.merge!(other_hash)
64
+ end
65
+
66
+ def merge!(other_hash)
67
+ other_hash.each do |key, value|
68
+ self[key] = value
69
+ end
70
+ raw_merge!(other_hash)
71
+ end
72
+
73
+ def rehash
74
+ @downcased.rehash
75
+ raw_rehash
76
+ end
77
+
78
+ def values_at(*keys)
79
+ @downcased.values_at(*keys.map {|key| key.to_s.downcase})
80
+ end
81
+
82
+ end
83
+ end
@@ -0,0 +1,24 @@
1
+ module Excon
2
+ module Middleware
3
+ class Base
4
+ def initialize(stack)
5
+ @stack = stack
6
+ end
7
+
8
+ def error_call(datum)
9
+ # do stuff
10
+ @stack.error_call(datum)
11
+ end
12
+
13
+ def request_call(datum)
14
+ # do stuff
15
+ @stack.request_call(datum)
16
+ end
17
+
18
+ def response_call(datum)
19
+ @stack.response_call(datum)
20
+ # do stuff
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,35 @@
1
+ module Excon
2
+ module Middleware
3
+ class Decompress < Excon::Middleware::Base
4
+ def request_call(datum)
5
+ unless datum.has_key?(:response_block)
6
+ key = datum[:headers].keys.detect {|k| k.to_s.casecmp('Accept-Encoding') == 0 } || 'Accept-Encoding'
7
+ if datum[:headers][key].to_s.empty?
8
+ datum[:headers][key] = 'deflate, gzip'
9
+ end
10
+ end
11
+ @stack.request_call(datum)
12
+ end
13
+
14
+ def response_call(datum)
15
+ unless datum.has_key?(:response_block)
16
+ if key = datum[:response][:headers].keys.detect {|k| k.casecmp('Content-Encoding') == 0 }
17
+ encodings = Utils.split_header_value(datum[:response][:headers][key])
18
+ if encoding = encodings.last
19
+ if encoding.casecmp('deflate') == 0
20
+ # assume inflate omits header
21
+ datum[:response][:body] = Zlib::Inflate.new(-Zlib::MAX_WBITS).inflate(datum[:response][:body])
22
+ encodings.pop
23
+ elsif encoding.casecmp('gzip') == 0 || encoding.casecmp('x-gzip') == 0
24
+ datum[:response][:body] = Zlib::GzipReader.new(StringIO.new(datum[:response][:body])).read
25
+ encodings.pop
26
+ end
27
+ datum[:response][:headers][key] = encodings.join(', ')
28
+ end
29
+ end
30
+ end
31
+ @stack.response_call(datum)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,11 @@
1
+ module Excon
2
+ module Middleware
3
+ class EscapePath < Excon::Middleware::Base
4
+ def request_call(datum)
5
+ # make sure path is encoded, prevent double encoding
6
+ datum[:path] = Excon::Utils.escape_uri(Excon::Utils.unescape_uri(datum[:path]))
7
+ @stack.request_call(datum)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ module Excon
2
+ module Middleware
3
+ class Expects < Excon::Middleware::Base
4
+ def response_call(datum)
5
+ if datum.has_key?(:expects) && ![*datum[:expects]].include?(datum[:response][:status])
6
+ raise(
7
+ Excon::Errors.status_error(
8
+ datum.reject {|key,value| key == :response},
9
+ Excon::Response.new(datum[:response])
10
+ )
11
+ )
12
+ else
13
+ @stack.response_call(datum)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,33 @@
1
+ module Excon
2
+ module Middleware
3
+ class Idempotent < Excon::Middleware::Base
4
+ def error_call(datum)
5
+ if datum[:idempotent]
6
+ if datum.has_key?(:request_block)
7
+ if datum[:request_block].respond_to?(:rewind)
8
+ datum[:request_block].rewind
9
+ else
10
+ Excon.display_warning('Excon requests with a :request_block must implement #rewind in order to be :idempotent.')
11
+ datum[:idempotent] = false
12
+ end
13
+ end
14
+ if datum.has_key?(:pipeline)
15
+ Excon.display_warning("Excon requests can not be :idempotent when pipelining.")
16
+ datum[:idempotent] = false
17
+ end
18
+ end
19
+
20
+ if datum[:idempotent] && [Excon::Errors::Timeout, Excon::Errors::SocketError,
21
+ Excon::Errors::HTTPStatusError].any? {|ex| datum[:error].kind_of?(ex) } && datum[:retries_remaining] > 1
22
+ # reduces remaining retries, reset connection, and restart request_call
23
+ datum[:retries_remaining] -= 1
24
+ connection = datum.delete(:connection)
25
+ datum.reject! {|key, _| !Excon::VALID_REQUEST_KEYS.include?(key) }
26
+ connection.request(datum)
27
+ else
28
+ @stack.error_call(datum)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,34 @@
1
+ module Excon
2
+ module Middleware
3
+ class Instrumentor < Excon::Middleware::Base
4
+ def error_call(datum)
5
+ if datum.has_key?(:instrumentor)
6
+ datum[:instrumentor].instrument("#{datum[:instrumentor_name]}.error", :error => datum[:error])
7
+ end
8
+ @stack.error_call(datum)
9
+ end
10
+
11
+ def request_call(datum)
12
+ if datum.has_key?(:instrumentor)
13
+ if datum[:retries_remaining] < datum[:retry_limit]
14
+ event_name = "#{datum[:instrumentor_name]}.retry"
15
+ else
16
+ event_name = "#{datum[:instrumentor_name]}.request"
17
+ end
18
+ datum[:instrumentor].instrument(event_name, datum) do
19
+ @stack.request_call(datum)
20
+ end
21
+ else
22
+ @stack.request_call(datum)
23
+ end
24
+ end
25
+
26
+ def response_call(datum)
27
+ if datum.has_key?(:instrumentor)
28
+ datum[:instrumentor].instrument("#{datum[:instrumentor_name]}.response", datum[:response])
29
+ end
30
+ @stack.response_call(datum)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,51 @@
1
+ module Excon
2
+ module Middleware
3
+ class Mock < Excon::Middleware::Base
4
+ def request_call(datum)
5
+ if datum[:mock]
6
+ # convert File/Tempfile body to string before matching:
7
+ if datum[:body].respond_to?(:read)
8
+ if datum[:body].respond_to?(:binmode)
9
+ datum[:body].binmode
10
+ end
11
+ if datum[:body].respond_to?(:rewind)
12
+ datum[:body].rewind
13
+ end
14
+ datum[:body] = datum[:body].read
15
+ elsif !datum[:body].nil? && !datum[:body].is_a?(String)
16
+ raise Excon::Errors::InvalidStub.new("Request body should be a string or an IO object. #{datum[:body].class} provided")
17
+ end
18
+
19
+ if stub = Excon.stub_for(datum)
20
+ datum[:response] = {
21
+ :body => '',
22
+ :headers => {},
23
+ :status => 200,
24
+ :remote_ip => '127.0.0.1'
25
+ }
26
+
27
+ stub_datum = case stub.last
28
+ when Proc
29
+ stub.last.call(datum)
30
+ else
31
+ stub.last
32
+ end
33
+
34
+ datum[:response].merge!(stub_datum.reject {|key,value| key == :headers})
35
+ if stub_datum.has_key?(:headers)
36
+ datum[:response][:headers].merge!(stub_datum[:headers])
37
+ end
38
+ else
39
+ # if we reach here no stubs matched
40
+ message = StringIO.new
41
+ message.puts('no stubs matched')
42
+ Excon::PrettyPrinter.pp(message, datum)
43
+ raise(Excon::Errors::StubNotFound.new(message.string))
44
+ end
45
+ end
46
+
47
+ @stack.request_call(datum)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,56 @@
1
+ module Excon
2
+ module Middleware
3
+ class RedirectFollower < Excon::Middleware::Base
4
+ def response_call(datum)
5
+ if datum.has_key?(:response)
6
+ case datum[:response][:status]
7
+ when 301, 302, 303, 307, 308
8
+ uri_parser = datum[:uri_parser] || Excon.defaults[:uri_parser]
9
+ _, location = datum[:response][:headers].detect do |key, value|
10
+ key.casecmp('Location') == 0
11
+ end
12
+ uri = uri_parser.parse(location)
13
+
14
+ # delete old/redirect response
15
+ response = datum.delete(:response)
16
+
17
+ params = datum.dup
18
+ params.delete(:connection)
19
+ params.delete(:password)
20
+ params.delete(:stack)
21
+ params.delete(:user)
22
+
23
+ if [301, 302, 303].include?(response[:status])
24
+ params[:method] = :get
25
+ params.delete(:body)
26
+ params[:headers].delete('Content-Length')
27
+ end
28
+ params[:headers] = datum[:headers].dup
29
+ params[:headers].delete('Authorization')
30
+ params[:headers].delete('Proxy-Connection')
31
+ params[:headers].delete('Proxy-Authorization')
32
+ params[:headers].delete('Host')
33
+ params.merge!(
34
+ :scheme => uri.scheme || datum[:scheme],
35
+ :host => uri.host || datum[:host],
36
+ :hostname => uri.hostname || datum[:hostname],
37
+ :port => uri.port || datum[:port],
38
+ :path => uri.path,
39
+ :query => uri.query
40
+ )
41
+
42
+ params.merge!(:user => Utils.unescape_uri(uri.user)) if uri.user
43
+ params.merge!(:password => Utils.unescape_uri(uri.password)) if uri.password
44
+
45
+ response = Excon::Connection.new(params).request
46
+ datum.merge!({:response => response.data})
47
+ else
48
+ @stack.response_call(datum)
49
+ end
50
+ else
51
+ @stack.response_call(datum)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,12 @@
1
+ module Excon
2
+ module Middleware
3
+ class ResponseParser < Excon::Middleware::Base
4
+ def response_call(datum)
5
+ unless datum.has_key?(:response)
6
+ datum = Excon::Response.parse(datum[:connection].send(:socket), datum)
7
+ end
8
+ @stack.response_call(datum)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,45 @@
1
+ module Excon
2
+ class PrettyPrinter
3
+ def self.pp(io, datum, indent=0)
4
+ datum = datum.dup
5
+
6
+ # reduce duplication/noise of output
7
+ unless datum.is_a?(Excon::Headers)
8
+ datum.delete(:connection)
9
+ datum.delete(:stack)
10
+
11
+ if datum.has_key?(:headers) && datum[:headers].has_key?('Authorization')
12
+ datum[:headers] = datum[:headers].dup
13
+ datum[:headers]['Authorization'] = REDACTED
14
+ end
15
+
16
+ if datum.has_key?(:password)
17
+ datum[:password] = REDACTED
18
+ end
19
+ end
20
+
21
+ indent += 2
22
+ max_key_length = datum.keys.map {|key| key.inspect.length}.max
23
+ datum.keys.sort_by {|key| key.to_s}.each do |key|
24
+ value = datum[key]
25
+ io.write("#{' ' * indent}#{key.inspect.ljust(max_key_length)} => ")
26
+ case value
27
+ when Array
28
+ io.puts("[")
29
+ value.each do |v|
30
+ io.puts("#{' ' * indent} #{v.inspect}")
31
+ end
32
+ io.write("#{' ' * indent}]")
33
+ when Hash
34
+ io.puts("{")
35
+ self.pp(io, value, indent)
36
+ io.write("#{' ' * indent}}")
37
+ else
38
+ io.write("#{value.inspect}")
39
+ end
40
+ io.puts
41
+ end
42
+ indent -= 2
43
+ end
44
+ end
45
+ end