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,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