sealights-rspec-agent 2.0.4 → 2.0.5

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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/agent/config.rb +6 -6
  3. data/agent/dependencies/faraday-0.17.0/LICENSE.md +20 -0
  4. data/agent/dependencies/faraday-0.17.0/README.md +384 -0
  5. data/agent/dependencies/faraday-0.17.0/lib/faraday.rb +248 -0
  6. data/agent/dependencies/faraday-0.17.0/lib/faraday/adapter.rb +55 -0
  7. data/agent/dependencies/faraday-0.17.0/lib/faraday/adapter/em_http.rb +243 -0
  8. data/agent/dependencies/faraday-0.17.0/lib/faraday/adapter/em_synchrony.rb +106 -0
  9. data/agent/dependencies/faraday-0.17.0/lib/faraday/adapter/em_synchrony/parallel_manager.rb +66 -0
  10. data/agent/dependencies/faraday-0.17.0/lib/faraday/adapter/excon.rb +82 -0
  11. data/agent/dependencies/faraday-0.17.0/lib/faraday/adapter/httpclient.rb +128 -0
  12. data/agent/dependencies/faraday-0.17.0/lib/faraday/adapter/net_http.rb +152 -0
  13. data/agent/dependencies/faraday-0.17.0/lib/faraday/adapter/net_http_persistent.rb +68 -0
  14. data/agent/dependencies/faraday-0.17.0/lib/faraday/adapter/patron.rb +95 -0
  15. data/agent/dependencies/faraday-0.17.0/lib/faraday/adapter/rack.rb +58 -0
  16. data/agent/dependencies/faraday-0.17.0/lib/faraday/adapter/sl_em_http_ssl_patch.rb +56 -0
  17. data/agent/dependencies/faraday-0.17.0/lib/faraday/adapter/test.rb +213 -0
  18. data/agent/dependencies/faraday-0.17.0/lib/faraday/adapter/typhoeus.rb +12 -0
  19. data/agent/dependencies/faraday-0.17.0/lib/faraday/autoload.rb +84 -0
  20. data/agent/dependencies/faraday-0.17.0/lib/faraday/connection.rb +484 -0
  21. data/agent/dependencies/faraday-0.17.0/lib/faraday/error.rb +66 -0
  22. data/agent/dependencies/faraday-0.17.0/lib/faraday/middleware.rb +37 -0
  23. data/agent/dependencies/faraday-0.17.0/lib/faraday/options.rb +373 -0
  24. data/agent/dependencies/faraday-0.17.0/lib/faraday/parameters.rb +198 -0
  25. data/agent/dependencies/faraday-0.17.0/lib/faraday/rack_builder.rb +237 -0
  26. data/agent/dependencies/faraday-0.17.0/lib/faraday/request.rb +114 -0
  27. data/agent/dependencies/faraday-0.17.0/lib/faraday/request/authorization.rb +41 -0
  28. data/agent/dependencies/faraday-0.17.0/lib/faraday/request/basic_authentication.rb +13 -0
  29. data/agent/dependencies/faraday-0.17.0/lib/faraday/request/instrumentation.rb +36 -0
  30. data/agent/dependencies/faraday-0.17.0/lib/faraday/request/multipart.rb +68 -0
  31. data/agent/dependencies/faraday-0.17.0/lib/faraday/request/retry.rb +212 -0
  32. data/agent/dependencies/faraday-0.17.0/lib/faraday/request/token_authentication.rb +15 -0
  33. data/agent/dependencies/faraday-0.17.0/lib/faraday/request/url_encoded.rb +36 -0
  34. data/agent/dependencies/faraday-0.17.0/lib/faraday/response.rb +97 -0
  35. data/agent/dependencies/faraday-0.17.0/lib/faraday/response/logger.rb +80 -0
  36. data/agent/dependencies/faraday-0.17.0/lib/faraday/response/raise_error.rb +21 -0
  37. data/agent/dependencies/faraday-0.17.0/lib/faraday/upload_io.rb +67 -0
  38. data/agent/dependencies/faraday-0.17.0/lib/faraday/utils.rb +326 -0
  39. data/agent/dependencies/jwt-2.2.1/AUTHORS +84 -0
  40. data/agent/dependencies/jwt-2.2.1/Appraisals +14 -0
  41. data/agent/dependencies/jwt-2.2.1/CHANGELOG.md +570 -0
  42. data/agent/dependencies/jwt-2.2.1/Gemfile +3 -0
  43. data/agent/dependencies/jwt-2.2.1/LICENSE +7 -0
  44. data/agent/dependencies/jwt-2.2.1/README.md +489 -0
  45. data/agent/dependencies/jwt-2.2.1/Rakefile +11 -0
  46. data/agent/dependencies/jwt-2.2.1/lib/jwt.rb +30 -0
  47. data/agent/dependencies/jwt-2.2.1/lib/jwt/algos/ecdsa.rb +35 -0
  48. data/agent/dependencies/jwt-2.2.1/lib/jwt/algos/eddsa.rb +23 -0
  49. data/agent/dependencies/jwt-2.2.1/lib/jwt/algos/hmac.rb +33 -0
  50. data/agent/dependencies/jwt-2.2.1/lib/jwt/algos/ps.rb +43 -0
  51. data/agent/dependencies/jwt-2.2.1/lib/jwt/algos/rsa.rb +19 -0
  52. data/agent/dependencies/jwt-2.2.1/lib/jwt/algos/unsupported.rb +16 -0
  53. data/agent/dependencies/jwt-2.2.1/lib/jwt/base64.rb +19 -0
  54. data/agent/dependencies/jwt-2.2.1/lib/jwt/claims_validator.rb +33 -0
  55. data/agent/dependencies/jwt-2.2.1/lib/jwt/decode.rb +100 -0
  56. data/agent/dependencies/jwt-2.2.1/lib/jwt/default_options.rb +15 -0
  57. data/agent/dependencies/jwt-2.2.1/lib/jwt/encode.rb +68 -0
  58. data/agent/dependencies/jwt-2.2.1/lib/jwt/error.rb +20 -0
  59. data/agent/dependencies/jwt-2.2.1/lib/jwt/json.rb +18 -0
  60. data/agent/dependencies/jwt-2.2.1/lib/jwt/jwk.rb +31 -0
  61. data/agent/dependencies/jwt-2.2.1/lib/jwt/jwk/key_finder.rb +57 -0
  62. data/agent/dependencies/jwt-2.2.1/lib/jwt/jwk/rsa.rb +47 -0
  63. data/agent/dependencies/jwt-2.2.1/lib/jwt/security_utils.rb +57 -0
  64. data/agent/dependencies/jwt-2.2.1/lib/jwt/signature.rb +52 -0
  65. data/agent/dependencies/jwt-2.2.1/lib/jwt/verify.rb +98 -0
  66. data/agent/dependencies/jwt-2.2.1/lib/jwt/version.rb +24 -0
  67. data/agent/dependencies/jwt-2.2.1/ruby-jwt.gemspec +34 -0
  68. data/agent/dependencies/multipart-post-2.1.1/Gemfile +6 -0
  69. data/agent/dependencies/multipart-post-2.1.1/History.txt +64 -0
  70. data/agent/dependencies/multipart-post-2.1.1/LICENSE +21 -0
  71. data/agent/dependencies/multipart-post-2.1.1/Manifest.txt +9 -0
  72. data/agent/dependencies/multipart-post-2.1.1/README.md +127 -0
  73. data/agent/dependencies/multipart-post-2.1.1/Rakefile +6 -0
  74. data/agent/dependencies/multipart-post-2.1.1/lib/composite_io.rb +108 -0
  75. data/agent/dependencies/multipart-post-2.1.1/lib/multipart_post.rb +9 -0
  76. data/agent/dependencies/multipart-post-2.1.1/lib/multipartable.rb +48 -0
  77. data/agent/dependencies/multipart-post-2.1.1/lib/net/http/post/multipart.rb +28 -0
  78. data/agent/dependencies/multipart-post-2.1.1/lib/parts.rb +126 -0
  79. data/agent/dependencies/multipart-post-2.1.1/multipart-post.gemspec +23 -0
  80. data/agent/http_client.rb +46 -0
  81. data/agent/listener.rb +1 -1
  82. data/agent/sealights-rspec-agent.rb +2 -2
  83. data/agent/tia.rb +5 -1
  84. metadata +80 -3
  85. data/agent/rest-client-wrapper.rb +0 -27
@@ -0,0 +1,41 @@
1
+ module SLFaraday
2
+ class Request::Authorization < SLFaraday::Middleware
3
+ KEY = "Authorization".freeze unless defined? KEY
4
+
5
+ # Public
6
+ def self.header(type, token)
7
+ case token
8
+ when String, Symbol
9
+ "#{type} #{token}"
10
+ when Hash
11
+ build_hash(type.to_s, token)
12
+ else
13
+ raise ArgumentError, "Can't build an Authorization #{type} header from #{token.inspect}"
14
+ end
15
+ end
16
+
17
+ # Internal
18
+ def self.build_hash(type, hash)
19
+ comma = ", "
20
+ values = []
21
+ hash.each do |key, value|
22
+ values << "#{key}=#{value.to_s.inspect}"
23
+ end
24
+ "#{type} #{values * comma}"
25
+ end
26
+
27
+ def initialize(app, type, token)
28
+ @header_value = self.class.header(type, token)
29
+ super(app)
30
+ end
31
+
32
+ # Public
33
+ def call(env)
34
+ unless env.request_headers[KEY]
35
+ env.request_headers[KEY] = @header_value
36
+ end
37
+ @app.call(env)
38
+ end
39
+ end
40
+ end
41
+
@@ -0,0 +1,13 @@
1
+ require 'base64'
2
+
3
+ module SLFaraday
4
+ class Request::BasicAuthentication < Request.load_middleware(:authorization)
5
+ # Public
6
+ def self.header(login, pass)
7
+ value = Base64.encode64([login, pass].join(':'))
8
+ value.gsub!("\n", '')
9
+ super(:Basic, value)
10
+ end
11
+ end
12
+ end
13
+
@@ -0,0 +1,36 @@
1
+ module SLFaraday
2
+ class Request::Instrumentation < SLFaraday::Middleware
3
+ class Options < SLFaraday::Options.new(:name, :instrumenter)
4
+ def name
5
+ self[:name] ||= 'request.faraday'
6
+ end
7
+
8
+ def instrumenter
9
+ self[:instrumenter] ||= ActiveSupport::Notifications
10
+ end
11
+ end
12
+
13
+ # Public: Instruments requests using Active Support.
14
+ #
15
+ # Measures time spent only for synchronous requests.
16
+ #
17
+ # Examples
18
+ #
19
+ # ActiveSupport::Notifications.subscribe('request.faraday') do |name, starts, ends, _, env|
20
+ # url = env[:url]
21
+ # http_method = env[:method].to_s.upcase
22
+ # duration = ends - starts
23
+ # $stderr.puts '[%s] %s %s (%.3f s)' % [url.host, http_method, url.request_uri, duration]
24
+ # end
25
+ def initialize(app, options = nil)
26
+ super(app)
27
+ @name, @instrumenter = Options.from(options).values_at(:name, :instrumenter)
28
+ end
29
+
30
+ def call(env)
31
+ @instrumenter.instrument(@name, env) do
32
+ @app.call(env)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,68 @@
1
+ require File.expand_path("../url_encoded", __FILE__)
2
+ require 'securerandom'
3
+
4
+ module SLFaraday
5
+ class Request::Multipart < Request::UrlEncoded
6
+ self.mime_type = 'multipart/form-data'.freeze
7
+ DEFAULT_BOUNDARY_PREFIX = "-----------RubyMultipartPost".freeze unless defined? DEFAULT_BOUNDARY_PREFIX
8
+
9
+ def call(env)
10
+ match_content_type(env) do |params|
11
+ env.request.boundary ||= unique_boundary
12
+ env.request_headers[CONTENT_TYPE] += "; boundary=#{env.request.boundary}"
13
+ env.body = create_multipart(env, params)
14
+ end
15
+ @app.call env
16
+ end
17
+
18
+ def process_request?(env)
19
+ type = request_type(env)
20
+ env.body.respond_to?(:each_key) and !env.body.empty? and (
21
+ (type.empty? and has_multipart?(env.body)) or
22
+ type == self.class.mime_type
23
+ )
24
+ end
25
+
26
+ def has_multipart?(obj)
27
+ # string is an enum in 1.8, returning list of itself
28
+ if obj.respond_to?(:each) && !obj.is_a?(String)
29
+ (obj.respond_to?(:values) ? obj.values : obj).each do |val|
30
+ return true if (val.respond_to?(:content_type) || has_multipart?(val))
31
+ end
32
+ end
33
+ false
34
+ end
35
+
36
+ def create_multipart(env, params)
37
+ boundary = env.request.boundary
38
+ parts = process_params(params) do |key, value|
39
+ SLFaraday::Parts::Part.new(boundary, key, value)
40
+ end
41
+ parts << SLFaraday::Parts::EpiloguePart.new(boundary)
42
+
43
+ body = SLFaraday::CompositeReadIO.new(parts)
44
+ env.request_headers[SLFaraday::Env::ContentLength] = body.length.to_s
45
+ return body
46
+ end
47
+
48
+ def unique_boundary
49
+ "#{DEFAULT_BOUNDARY_PREFIX}-#{SecureRandom.hex}"
50
+ end
51
+
52
+ def process_params(params, prefix = nil, pieces = nil, &block)
53
+ params.inject(pieces || []) do |all, (key, value)|
54
+ key = "#{prefix}[#{key}]" if prefix
55
+
56
+ case value
57
+ when Array
58
+ values = value.inject([]) { |a,v| a << [nil, v] }
59
+ process_params(values, key, all, &block)
60
+ when Hash
61
+ process_params(value, key, all, &block)
62
+ else
63
+ all << block.call(key, value)
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,212 @@
1
+ require 'date'
2
+
3
+ module SLFaraday
4
+ # Catches exceptions and retries each request a limited number of times.
5
+ #
6
+ # By default, it retries 2 times and handles only timeout exceptions. It can
7
+ # be configured with an arbitrary number of retries, a list of exceptions to
8
+ # handle, a retry interval, a percentage of randomness to add to the retry
9
+ # interval, and a backoff factor.
10
+ #
11
+ # Examples
12
+ #
13
+ # Faraday.new do |conn|
14
+ # conn.request :retry, max: 2, interval: 0.05,
15
+ # interval_randomness: 0.5, backoff_factor: 2,
16
+ # exceptions: [CustomException, 'Timeout::Error']
17
+ # conn.adapter ...
18
+ # end
19
+ #
20
+ # This example will result in a first interval that is random between 0.05 and 0.075 and a second
21
+ # interval that is random between 0.1 and 0.15
22
+ #
23
+ class Request::Retry < SLFaraday::Middleware
24
+
25
+ DEFAULT_EXCEPTIONS = [Errno::ETIMEDOUT, 'Timeout::Error', Error::TimeoutError, SLFaraday::Error::RetriableResponse].freeze
26
+ IDEMPOTENT_METHODS = [:delete, :get, :head, :options, :put]
27
+
28
+ class Options < SLFaraday::Options.new(:max, :interval, :max_interval, :interval_randomness,
29
+ :backoff_factor, :exceptions, :methods, :retry_if, :retry_block,
30
+ :retry_statuses)
31
+
32
+ DEFAULT_CHECK = lambda { |env,exception| false }
33
+
34
+ def self.from(value)
35
+ if Integer === value
36
+ new(value)
37
+ else
38
+ super(value)
39
+ end
40
+ end
41
+
42
+ def max
43
+ (self[:max] ||= 2).to_i
44
+ end
45
+
46
+ def interval
47
+ (self[:interval] ||= 0).to_f
48
+ end
49
+
50
+ def max_interval
51
+ (self[:max_interval] ||= Float::MAX).to_f
52
+ end
53
+
54
+ def interval_randomness
55
+ (self[:interval_randomness] ||= 0).to_f
56
+ end
57
+
58
+ def backoff_factor
59
+ (self[:backoff_factor] ||= 1).to_f
60
+ end
61
+
62
+ def exceptions
63
+ Array(self[:exceptions] ||= DEFAULT_EXCEPTIONS)
64
+ end
65
+
66
+ def methods
67
+ Array(self[:methods] ||= IDEMPOTENT_METHODS)
68
+ end
69
+
70
+ def retry_if
71
+ self[:retry_if] ||= DEFAULT_CHECK
72
+ end
73
+
74
+ def retry_block
75
+ self[:retry_block] ||= Proc.new {}
76
+ end
77
+
78
+ def retry_statuses
79
+ Array(self[:retry_statuses] ||= [])
80
+ end
81
+ end
82
+
83
+ # Public: Initialize middleware
84
+ #
85
+ # Options:
86
+ # max - Maximum number of retries (default: 2)
87
+ # interval - Pause in seconds between retries (default: 0)
88
+ # interval_randomness - The maximum random interval amount expressed
89
+ # as a float between 0 and 1 to use in addition to the
90
+ # interval. (default: 0)
91
+ # max_interval - An upper limit for the interval (default: Float::MAX)
92
+ # backoff_factor - The amount to multiple each successive retry's
93
+ # interval amount by in order to provide backoff
94
+ # (default: 1)
95
+ # exceptions - The list of exceptions to handle. Exceptions can be
96
+ # given as Class, Module, or String. (default:
97
+ # [Errno::ETIMEDOUT, 'Timeout::Error',
98
+ # Error::TimeoutError, Faraday::Error::RetriableResponse])
99
+ # methods - A list of HTTP methods to retry without calling retry_if. Pass
100
+ # an empty Array to call retry_if for all exceptions.
101
+ # (defaults to the idempotent HTTP methods in IDEMPOTENT_METHODS)
102
+ # retry_if - block that will receive the env object and the exception raised
103
+ # and should decide if the code should retry still the action or
104
+ # not independent of the retry count. This would be useful
105
+ # if the exception produced is non-recoverable or if the
106
+ # the HTTP method called is not idempotent.
107
+ # (defaults to return false)
108
+ # retry_block - block that is executed after every retry. Request environment, middleware options,
109
+ # current number of retries and the exception is passed to the block as parameters.
110
+ def initialize(app, options = nil)
111
+ super(app)
112
+ @options = Options.from(options)
113
+ @errmatch = build_exception_matcher(@options.exceptions)
114
+ end
115
+
116
+ def calculate_sleep_amount(retries, env)
117
+ retry_after = calculate_retry_after(env)
118
+ retry_interval = calculate_retry_interval(retries)
119
+
120
+ return if retry_after && retry_after > @options.max_interval
121
+
122
+ retry_after && retry_after >= retry_interval ? retry_after : retry_interval
123
+ end
124
+
125
+ def call(env)
126
+ retries = @options.max
127
+ request_body = env[:body]
128
+ begin
129
+ env[:body] = request_body # after failure env[:body] is set to the response body
130
+ @app.call(env).tap do |resp|
131
+ raise SLFaraday::Error::RetriableResponse.new(nil, resp) if @options.retry_statuses.include?(resp.status)
132
+ end
133
+ rescue @errmatch => exception
134
+ if retries > 0 && retry_request?(env, exception)
135
+ retries -= 1
136
+ rewind_files(request_body)
137
+ @options.retry_block.call(env, @options, retries, exception)
138
+ if (sleep_amount = calculate_sleep_amount(retries + 1, env))
139
+ sleep sleep_amount
140
+ retry
141
+ end
142
+ end
143
+
144
+ if exception.is_a?(SLFaraday::Error::RetriableResponse)
145
+ exception.response
146
+ else
147
+ raise
148
+ end
149
+ end
150
+ end
151
+
152
+ # Private: construct an exception matcher object.
153
+ #
154
+ # An exception matcher for the rescue clause can usually be any object that
155
+ # responds to `===`, but for Ruby 1.8 it has to be a Class or Module.
156
+ def build_exception_matcher(exceptions)
157
+ matcher = Module.new
158
+ (class << matcher; self; end).class_eval do
159
+ define_method(:===) do |error|
160
+ exceptions.any? do |ex|
161
+ if ex.is_a? Module
162
+ error.is_a? ex
163
+ else
164
+ error.class.to_s == ex.to_s
165
+ end
166
+ end
167
+ end
168
+ end
169
+ matcher
170
+ end
171
+
172
+ private
173
+
174
+ def retry_request?(env, exception)
175
+ @options.methods.include?(env[:method]) || @options.retry_if.call(env, exception)
176
+ end
177
+
178
+ def rewind_files(body)
179
+ return unless body.is_a?(Hash)
180
+ body.each do |_, value|
181
+ if value.is_a? UploadIO
182
+ value.rewind
183
+ end
184
+ end
185
+ end
186
+
187
+ # MDN spec for Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
188
+ def calculate_retry_after(env)
189
+ response_headers = env[:response_headers]
190
+ return unless response_headers
191
+
192
+ retry_after_value = env[:response_headers]["Retry-After"]
193
+
194
+ # Try to parse date from the header value
195
+ begin
196
+ datetime = DateTime.rfc2822(retry_after_value)
197
+ datetime.to_time - Time.now.utc
198
+ rescue ArgumentError
199
+ retry_after_value.to_f
200
+ end
201
+ end
202
+
203
+ def calculate_retry_interval(retries)
204
+ retry_index = @options.max - retries
205
+ current_interval = @options.interval * (@options.backoff_factor ** retry_index)
206
+ current_interval = [current_interval, @options.max_interval].min
207
+ random_interval = rand * @options.interval_randomness.to_f * @options.interval
208
+
209
+ current_interval + random_interval
210
+ end
211
+ end
212
+ end
@@ -0,0 +1,15 @@
1
+ module SLFaraday
2
+ class Request::TokenAuthentication < Request.load_middleware(:authorization)
3
+ # Public
4
+ def self.header(token, options = nil)
5
+ options ||= {}
6
+ options[:token] = token
7
+ super(:Token, options)
8
+ end
9
+
10
+ def initialize(app, token, options = nil)
11
+ super(app, token, options)
12
+ end
13
+ end
14
+ end
15
+
@@ -0,0 +1,36 @@
1
+ module SLFaraday
2
+ class Request::UrlEncoded < SLFaraday::Middleware
3
+ CONTENT_TYPE = 'Content-Type'.freeze unless defined? CONTENT_TYPE
4
+
5
+ class << self
6
+ attr_accessor :mime_type
7
+ end
8
+ self.mime_type = 'application/x-www-form-urlencoded'.freeze
9
+
10
+ def call(env)
11
+ match_content_type(env) do |data|
12
+ params = SLFaraday::Utils::ParamsHash[data]
13
+ env.body = params.to_query(env.params_encoder)
14
+ end
15
+ @app.call env
16
+ end
17
+
18
+ def match_content_type(env)
19
+ if process_request?(env)
20
+ env.request_headers[CONTENT_TYPE] ||= self.class.mime_type
21
+ yield(env.body) unless env.body.respond_to?(:to_str)
22
+ end
23
+ end
24
+
25
+ def process_request?(env)
26
+ type = request_type(env)
27
+ env.body and (type.empty? or type == self.class.mime_type)
28
+ end
29
+
30
+ def request_type(env)
31
+ type = env.request_headers[CONTENT_TYPE].to_s
32
+ type = type.split(';', 2).first if type.index(';')
33
+ type
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,97 @@
1
+ require 'forwardable'
2
+
3
+ module SLFaraday
4
+ class Response
5
+ # Used for simple response middleware.
6
+ class Middleware < SLFaraday::Middleware
7
+ def call(env)
8
+ @app.call(env).on_complete do |environment|
9
+ on_complete(environment)
10
+ end
11
+ end
12
+
13
+ # Override this to modify the environment after the response has finished.
14
+ # Calls the `parse` method if defined
15
+ def on_complete(env)
16
+ env.body = parse(env.body) if respond_to?(:parse) && env.parse_body?
17
+ end
18
+ end
19
+
20
+ extend Forwardable
21
+ extend MiddlewareRegistry
22
+
23
+ register_middleware File.expand_path('../response', __FILE__),
24
+ :raise_error => [:RaiseError, 'raise_error'],
25
+ :logger => [:Logger, 'logger']
26
+
27
+ def initialize(env = nil)
28
+ @env = Env.from(env) if env
29
+ @on_complete_callbacks = []
30
+ end
31
+
32
+ attr_reader :env
33
+
34
+ def_delegators :env, :to_hash
35
+
36
+ def status
37
+ finished? ? env.status : nil
38
+ end
39
+
40
+ def reason_phrase
41
+ finished? ? env.reason_phrase : nil
42
+ end
43
+
44
+ def headers
45
+ finished? ? env.response_headers : {}
46
+ end
47
+ def_delegator :headers, :[]
48
+
49
+ def body
50
+ finished? ? env.body : nil
51
+ end
52
+
53
+ def finished?
54
+ !!env
55
+ end
56
+
57
+ def on_complete
58
+ if not finished?
59
+ @on_complete_callbacks << Proc.new
60
+ else
61
+ yield(env)
62
+ end
63
+ return self
64
+ end
65
+
66
+ def finish(env)
67
+ raise "response already finished" if finished?
68
+ @env = env.is_a?(Env) ? env : Env.from(env)
69
+ @on_complete_callbacks.each { |callback| callback.call(@env) }
70
+ return self
71
+ end
72
+
73
+ def success?
74
+ finished? && env.success?
75
+ end
76
+
77
+ # because @on_complete_callbacks cannot be marshalled
78
+ def marshal_dump
79
+ !finished? ? nil : {
80
+ :status => @env.status, :body => @env.body,
81
+ :response_headers => @env.response_headers
82
+ }
83
+ end
84
+
85
+ def marshal_load(env)
86
+ @env = Env.from(env)
87
+ end
88
+
89
+ # Expand the env with more properties, without overriding existing ones.
90
+ # Useful for applying request params after restoring a marshalled Response.
91
+ def apply_request(request_env)
92
+ raise "response didn't finish yet" unless finished?
93
+ @env = Env.from(request_env).update(@env)
94
+ return self
95
+ end
96
+ end
97
+ end