rack-request_replication 0.1.3 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/rack/request_replication/forwarder.rb +58 -59
- data/lib/rack/request_replication/version.rb +1 -1
- data/rack-request_replication.gemspec +2 -1
- data/spec/app/test_app.rb +6 -6
- data/spec/forwarder_spec.rb +16 -8
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1b5f3b3d0ce122bb0437c305d39b81065462a923
|
4
|
+
data.tar.gz: f07ac10950d3c79c3a7b7d56324bb63ad3c18a81
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e50bf526bc98629172483e2ed48206ea362aacf55f59f1f2396f09c33db182bca44ee638c72b473d5f4b82d39fa013bf64343560b2b5e046dcf6aaa9df22a63a
|
7
|
+
data.tar.gz: 57a3c7b969f9b569fd39123cd37256cf0c5f8fe58cf6e5eb084b689770a70fd1738eecf5dd6bbfa848c8a41ebe9d0d0675ae9671fdf4065909b762148cc0d933
|
@@ -3,6 +3,7 @@ require 'json'
|
|
3
3
|
require 'net/http'
|
4
4
|
require 'uri'
|
5
5
|
require 'redis'
|
6
|
+
require 'active_support/core_ext/hash/conversions'
|
6
7
|
|
7
8
|
module Rack
|
8
9
|
module RequestReplication
|
@@ -32,7 +33,7 @@ module Rack
|
|
32
33
|
# @option redis [Integer] :port (6379)
|
33
34
|
# @option redis [String] :db ('rack-request-replication')
|
34
35
|
#
|
35
|
-
def initialize(
|
36
|
+
def initialize(app, options = {})
|
36
37
|
@app = app
|
37
38
|
@options = {
|
38
39
|
host: 'localhost',
|
@@ -42,7 +43,7 @@ module Rack
|
|
42
43
|
session_key: 'rack.session',
|
43
44
|
root_url: '/',
|
44
45
|
redis: {}
|
45
|
-
}.merge
|
46
|
+
}.merge(options)
|
46
47
|
end
|
47
48
|
|
48
49
|
##
|
@@ -50,10 +51,10 @@ module Rack
|
|
50
51
|
# @return [Array(Integer, Hash, #each)]
|
51
52
|
# @see http://rack.rubyforge.org/doc/SPEC.html
|
52
53
|
#
|
53
|
-
def call(
|
54
|
-
request = Rack::Request.new
|
55
|
-
replicate
|
56
|
-
app.call
|
54
|
+
def call(env)
|
55
|
+
request = Rack::Request.new(env)
|
56
|
+
replicate(request)
|
57
|
+
app.call(env)
|
57
58
|
end
|
58
59
|
|
59
60
|
##
|
@@ -62,11 +63,11 @@ module Rack
|
|
62
63
|
#
|
63
64
|
# @param [Rack::Request] request
|
64
65
|
#
|
65
|
-
def replicate(
|
66
|
-
opts = replicate_options_and_data
|
67
|
-
uri = forward_uri
|
66
|
+
def replicate(request)
|
67
|
+
opts = replicate_options_and_data(request)
|
68
|
+
uri = forward_uri(request)
|
68
69
|
|
69
|
-
http = Net::HTTP.new
|
70
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
70
71
|
http.use_ssl = options[:use_ssl]
|
71
72
|
http.verify_mode = OpenSSL::SSL::VERIFY_NONE unless options[:verify_ssl]
|
72
73
|
|
@@ -81,8 +82,8 @@ module Rack
|
|
81
82
|
|
82
83
|
Thread.new do
|
83
84
|
begin
|
84
|
-
forward_request.add_field("Cookie", cookies(
|
85
|
-
update_csrf_token_and_cookies(
|
85
|
+
forward_request.add_field("Cookie", cookies(request))
|
86
|
+
update_csrf_token_and_cookies(request, http.request(forward_request))
|
86
87
|
rescue => e
|
87
88
|
logger.debug "Replicating request failed with: #{e.message}"
|
88
89
|
end
|
@@ -95,9 +96,9 @@ module Rack
|
|
95
96
|
# @param [Rack::Request] request
|
96
97
|
# @param [Net::HTTP::Response] response
|
97
98
|
#
|
98
|
-
def update_csrf_token_and_cookies(
|
99
|
-
update_csrf_token(
|
100
|
-
update_cookies(
|
99
|
+
def update_csrf_token_and_cookies(request, response)
|
100
|
+
update_csrf_token(request, response)
|
101
|
+
update_cookies(request, response)
|
101
102
|
end
|
102
103
|
|
103
104
|
##
|
@@ -106,11 +107,11 @@ module Rack
|
|
106
107
|
# @param [Rack::Request] request
|
107
108
|
# @returns [String]
|
108
109
|
#
|
109
|
-
def csrf_token(
|
110
|
+
def csrf_token(request)
|
110
111
|
token = request.params["authenticity_token"]
|
111
112
|
return if token.nil?
|
112
113
|
|
113
|
-
redis.get(
|
114
|
+
redis.get("csrf-#{token}") || token
|
114
115
|
end
|
115
116
|
|
116
117
|
##
|
@@ -118,7 +119,7 @@ module Rack
|
|
118
119
|
#
|
119
120
|
# @param [Rack::Request] request
|
120
121
|
#
|
121
|
-
def update_csrf_token(
|
122
|
+
def update_csrf_token(request, response)
|
122
123
|
token = request.params["authenticity_token"]
|
123
124
|
return if token.nil?
|
124
125
|
|
@@ -134,7 +135,7 @@ module Rack
|
|
134
135
|
# @param [Net::HTTP::Response] response
|
135
136
|
# @returns [String]
|
136
137
|
#
|
137
|
-
def csrf_token_from(
|
138
|
+
def csrf_token_from(response)
|
138
139
|
response.split("\n").
|
139
140
|
select{|l| l.match(/csrf-token/) }.
|
140
141
|
first.split(" ").
|
@@ -152,11 +153,11 @@ module Rack
|
|
152
153
|
# @param [Rack::Request] request
|
153
154
|
# @param [Net::HTTP::Response] response
|
154
155
|
#
|
155
|
-
def update_cookies(
|
156
|
-
return unless cookies_id(
|
157
|
-
cookie = response.to_hash['set-cookie'].collect{|ea|ea[/^.*?;/]}.join rescue {}
|
158
|
-
cookie = Hash[cookie.split(";").map{|d|d.split('=')}] rescue {}
|
159
|
-
redis.set(
|
156
|
+
def update_cookies(request, response)
|
157
|
+
return unless cookies_id(request)
|
158
|
+
cookie = response.to_hash['set-cookie'].collect{ |ea|ea[/^.*?;/] }.join rescue {}
|
159
|
+
cookie = Hash[cookie.split(";").map{ |d|d.split('=') }] rescue {}
|
160
|
+
redis.set(cookies_id(request), cookie)
|
160
161
|
end
|
161
162
|
|
162
163
|
##
|
@@ -169,11 +170,9 @@ module Rack
|
|
169
170
|
# @param [Rack::Request] request
|
170
171
|
# @returns [Hash]
|
171
172
|
#
|
172
|
-
def cookies(
|
173
|
-
return (
|
174
|
-
redis.get(
|
175
|
-
request.cookies ||
|
176
|
-
{}
|
173
|
+
def cookies(request)
|
174
|
+
return (request.cookies || "") unless cookies_id(request)
|
175
|
+
redis.get(cookies_id(request)) || request.cookies || {}
|
177
176
|
end
|
178
177
|
|
179
178
|
##
|
@@ -185,11 +184,11 @@ module Rack
|
|
185
184
|
# @param [Rack::Request] request
|
186
185
|
# @returns [String]
|
187
186
|
#
|
188
|
-
def cookies_id(
|
187
|
+
def cookies_id(request)
|
189
188
|
cs = request.cookies
|
190
|
-
|
191
|
-
|
192
|
-
|
189
|
+
session = cs && cs[options[:session_key]]
|
190
|
+
session_id = session && session.split("\n--").last
|
191
|
+
session_id
|
193
192
|
end
|
194
193
|
|
195
194
|
##
|
@@ -201,8 +200,8 @@ module Rack
|
|
201
200
|
# @param [Hash{Symbol => Object}] opts ({})
|
202
201
|
# @returns [Net:HTTP::Get]
|
203
202
|
#
|
204
|
-
def create_get_request(
|
205
|
-
Net::HTTP::Get.new
|
203
|
+
def create_get_request(uri, opts = {})
|
204
|
+
Net::HTTP::Get.new(uri.request_uri)
|
206
205
|
end
|
207
206
|
|
208
207
|
##
|
@@ -215,9 +214,9 @@ module Rack
|
|
215
214
|
# @param [Hash{Symbol => Object}] opts ({})
|
216
215
|
# @returns [Net:HTTP::Post]
|
217
216
|
#
|
218
|
-
def create_post_request(
|
219
|
-
forward_request = Net::HTTP::Post.new
|
220
|
-
forward_request.
|
217
|
+
def create_post_request(uri, opts = {})
|
218
|
+
forward_request = Net::HTTP::Post.new(uri.request_uri)
|
219
|
+
forward_request.body = opts[:params].to_query
|
221
220
|
forward_request
|
222
221
|
end
|
223
222
|
|
@@ -231,9 +230,9 @@ module Rack
|
|
231
230
|
# @param [Hash{Symbol => Object}] opts ({})
|
232
231
|
# @returns [Net:HTTP::Put]
|
233
232
|
#
|
234
|
-
def create_put_request(
|
235
|
-
forward_request = Net::HTTP::Put.new
|
236
|
-
forward_request.
|
233
|
+
def create_put_request(uri, opts = {})
|
234
|
+
forward_request = Net::HTTP::Put.new(uri.request_uri)
|
235
|
+
forward_request.body = opts[:params].to_query
|
237
236
|
forward_request
|
238
237
|
end
|
239
238
|
|
@@ -247,9 +246,9 @@ module Rack
|
|
247
246
|
# @param [Hash{Symbol => Object}] opts ({})
|
248
247
|
# @returns [Net:HTTP::Patch]
|
249
248
|
#
|
250
|
-
def create_patch_request(
|
251
|
-
forward_request = Net::HTTP::Patch.new
|
252
|
-
forward_request.
|
249
|
+
def create_patch_request(uri, opts = {})
|
250
|
+
forward_request = Net::HTTP::Patch.new(uri.request_uri)
|
251
|
+
forward_request.body = opts[:params].to_query
|
253
252
|
forward_request
|
254
253
|
end
|
255
254
|
|
@@ -262,8 +261,8 @@ module Rack
|
|
262
261
|
# @param [Hash{Symbol => Object}] opts ({})
|
263
262
|
# @returns [Net:HTTP::Delete]
|
264
263
|
#
|
265
|
-
def create_delete_request(
|
266
|
-
Net::HTTP::Delete.new
|
264
|
+
def create_delete_request(uri, opts = {})
|
265
|
+
Net::HTTP::Delete.new(uri.request_uri)
|
267
266
|
end
|
268
267
|
|
269
268
|
##
|
@@ -275,8 +274,8 @@ module Rack
|
|
275
274
|
# @param [Hash{Symbol => Object}] opts ({})
|
276
275
|
# @returns [Net:HTTP::Options]
|
277
276
|
#
|
278
|
-
def create_options_request(
|
279
|
-
Net::HTTP::Options.new
|
277
|
+
def create_options_request(uri, opts = {})
|
278
|
+
Net::HTTP::Options.new(uri.request_uri)
|
280
279
|
end
|
281
280
|
|
282
281
|
##
|
@@ -288,8 +287,8 @@ module Rack
|
|
288
287
|
# @param [Hash{Symbol => Object}] opts ({})
|
289
288
|
# @returns [Net:HTTP::Options]
|
290
289
|
#
|
291
|
-
def create_propfind_request(
|
292
|
-
Net::HTTP::Propfind.new
|
290
|
+
def create_propfind_request(uri, opts = {})
|
291
|
+
Net::HTTP::Propfind.new(uri.request_uri)
|
293
292
|
end
|
294
293
|
|
295
294
|
##
|
@@ -299,7 +298,7 @@ module Rack
|
|
299
298
|
# @param [Rack::Request] request
|
300
299
|
# @returns [Hash]
|
301
300
|
#
|
302
|
-
def replicate_options_and_data(
|
301
|
+
def replicate_options_and_data(request)
|
303
302
|
replicated_options ||= {}
|
304
303
|
%w(
|
305
304
|
accept_encoding
|
@@ -314,12 +313,12 @@ module Rack
|
|
314
313
|
user_agent
|
315
314
|
url
|
316
315
|
).map(&:to_sym).each do |m|
|
317
|
-
value = request.send(
|
316
|
+
value = request.send(m)
|
318
317
|
replicated_options[m] = value unless value.nil?
|
319
318
|
end
|
320
319
|
|
321
320
|
if replicated_options[:params]["authenticity_token"]
|
322
|
-
replicated_options[:params]["authenticity_token"] = csrf_token(
|
321
|
+
replicated_options[:params]["authenticity_token"] = csrf_token(request)
|
323
322
|
end
|
324
323
|
|
325
324
|
replicated_options
|
@@ -332,8 +331,8 @@ module Rack
|
|
332
331
|
# @param [Rack::Request] request
|
333
332
|
# @returns [URI]
|
334
333
|
#
|
335
|
-
def forward_uri(
|
336
|
-
url = "#{request.scheme}://#{forward_host_with_port(
|
334
|
+
def forward_uri(request)
|
335
|
+
url = "#{request.scheme}://#{forward_host_with_port(request)}"
|
337
336
|
url << request.fullpath
|
338
337
|
URI(url)
|
339
338
|
end
|
@@ -345,9 +344,9 @@ module Rack
|
|
345
344
|
# @param [Rack::Request] request
|
346
345
|
# @returns [String]
|
347
346
|
#
|
348
|
-
def forward_host_with_port(
|
347
|
+
def forward_host_with_port(request)
|
349
348
|
host = options[:host].to_s
|
350
|
-
host = "#{host}:#{options[:port]}" unless port_matches_scheme?
|
349
|
+
host = "#{host}:#{options[:port]}" unless port_matches_scheme?(request)
|
351
350
|
host
|
352
351
|
end
|
353
352
|
|
@@ -369,7 +368,7 @@ module Rack
|
|
369
368
|
# @param [Rack::Request] request
|
370
369
|
# @returns [boolean]
|
371
370
|
#
|
372
|
-
def port_matches_scheme?(
|
371
|
+
def port_matches_scheme?(request)
|
373
372
|
options[:port].to_i == DEFAULT_PORTS[clean_scheme(request)]
|
374
373
|
end
|
375
374
|
|
@@ -379,7 +378,7 @@ module Rack
|
|
379
378
|
# @param [Rack::Request] request
|
380
379
|
# @returns [String]
|
381
380
|
#
|
382
|
-
def clean_scheme(
|
381
|
+
def clean_scheme(request)
|
383
382
|
request.scheme.match(/^\w+/)[0]
|
384
383
|
end
|
385
384
|
|
@@ -6,7 +6,7 @@ require 'rack/request_replication/version'
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = 'rack-request_replication'
|
8
8
|
spec.version = Rack::RequestReplication::VERSION
|
9
|
-
spec.authors = ['Wouter de Vos']
|
9
|
+
spec.authors = ['Wouter de Vos', 'Mark Mulder']
|
10
10
|
spec.email = ['wouter@springest.com']
|
11
11
|
spec.summary = %q{Request replication MiddleWare for Rack.}
|
12
12
|
spec.description = %q{Replicate or record HTTP requests to your Rack application and replay them elsewhere or at another time.}
|
@@ -28,4 +28,5 @@ Gem::Specification.new do |spec|
|
|
28
28
|
|
29
29
|
spec.add_runtime_dependency 'rack', '>= 1.0.0'
|
30
30
|
spec.add_runtime_dependency 'redis', '>= 1.0.0'
|
31
|
+
spec.add_runtime_dependency 'activesupport', '>= 2.1.0'
|
31
32
|
end
|
data/spec/app/test_app.rb
CHANGED
@@ -23,15 +23,15 @@ class TestApp < Sinatra::Base
|
|
23
23
|
end
|
24
24
|
|
25
25
|
post '/' do
|
26
|
-
|
26
|
+
request.params.to_s
|
27
27
|
end
|
28
28
|
|
29
29
|
put '/' do
|
30
|
-
|
30
|
+
request.params.to_s
|
31
31
|
end
|
32
32
|
|
33
33
|
patch '/' do
|
34
|
-
|
34
|
+
request.params.to_s
|
35
35
|
end
|
36
36
|
|
37
37
|
delete '/' do
|
@@ -60,17 +60,17 @@ class DestApp < Sinatra::Base
|
|
60
60
|
end
|
61
61
|
|
62
62
|
post '/' do
|
63
|
-
$destination_responses <<
|
63
|
+
$destination_responses << request.params.to_s
|
64
64
|
'Created!'
|
65
65
|
end
|
66
66
|
|
67
67
|
put '/' do
|
68
|
-
$destination_responses <<
|
68
|
+
$destination_responses << request.params.to_s
|
69
69
|
'Replaced!'
|
70
70
|
end
|
71
71
|
|
72
72
|
patch '/' do
|
73
|
-
$destination_responses <<
|
73
|
+
$destination_responses << request.params.to_s
|
74
74
|
'Updated'
|
75
75
|
end
|
76
76
|
|
data/spec/forwarder_spec.rb
CHANGED
@@ -38,21 +38,29 @@ describe Rack::RequestReplication::Forwarder do
|
|
38
38
|
end
|
39
39
|
|
40
40
|
describe 'a POST request' do
|
41
|
-
|
41
|
+
it 'posts correct parameters along parameters' do
|
42
|
+
post '/', foo: 'bar'
|
43
|
+
expect(destination_response).to eq "{\"foo\"=>\"bar\"}"
|
44
|
+
end
|
42
45
|
|
43
|
-
it
|
46
|
+
it "works with nested parameters" do
|
47
|
+
post '/', foo: { bar: 'buz' }
|
48
|
+
expect(destination_response).to eq "{\"foo\"=>{\"bar\"=>\"buz\"}}"
|
49
|
+
end
|
44
50
|
end
|
45
51
|
|
46
52
|
describe 'a PUT request' do
|
47
|
-
|
48
|
-
|
49
|
-
|
53
|
+
it 'posts correct parameters along parameters' do
|
54
|
+
put '/', foo: { bar: 'buz' }
|
55
|
+
expect(destination_response).to eq "{\"foo\"=>{\"bar\"=>\"buz\"}}"
|
56
|
+
end
|
50
57
|
end
|
51
58
|
|
52
59
|
describe 'a PATCH request' do
|
53
|
-
|
54
|
-
|
55
|
-
|
60
|
+
it 'posts correct parameters along parameters' do
|
61
|
+
patch '/', foo: { bar: 'buz' }
|
62
|
+
expect(destination_response).to eq "{\"foo\"=>{\"bar\"=>\"buz\"}}"
|
63
|
+
end
|
56
64
|
end
|
57
65
|
|
58
66
|
describe 'a DELETE request' do
|
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-request_replication
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Wouter de Vos
|
8
|
+
- Mark Mulder
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2015-
|
12
|
+
date: 2015-07-23 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: bundler
|
@@ -136,6 +137,20 @@ dependencies:
|
|
136
137
|
- - ">="
|
137
138
|
- !ruby/object:Gem::Version
|
138
139
|
version: 1.0.0
|
140
|
+
- !ruby/object:Gem::Dependency
|
141
|
+
name: activesupport
|
142
|
+
requirement: !ruby/object:Gem::Requirement
|
143
|
+
requirements:
|
144
|
+
- - ">="
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: 2.1.0
|
147
|
+
type: :runtime
|
148
|
+
prerelease: false
|
149
|
+
version_requirements: !ruby/object:Gem::Requirement
|
150
|
+
requirements:
|
151
|
+
- - ">="
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: 2.1.0
|
139
154
|
description: Replicate or record HTTP requests to your Rack application and replay
|
140
155
|
them elsewhere or at another time.
|
141
156
|
email:
|