rack-request_replication 0.0.3 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +49 -4
- data/lib/rack/request_replication.rb +0 -1
- data/lib/rack/request_replication/forwarder.rb +61 -1
- data/lib/rack/request_replication/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f6ae7943af00005747ede7913cb2a8ec935ac80e
|
4
|
+
data.tar.gz: 469f4eda7bd661a49dd74ac05f57a7085c0e871e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 513b0e735a59e0acade09e128779bd4a132613e809fb7a1d5db9decb2d51f0e964b70776e05489dc77d24a20a004c4252a56dda915107e002c9a91f2f64d0f87
|
7
|
+
data.tar.gz: 467c2ba93881da20eea3d9567eb21039b59f87d3eacb409c27fc0ad86b8c1af014644ac12a4bec00282d9b6d026d1b44bdade62a08f4ad3f077e04ce32c08c0f
|
data/README.md
CHANGED
@@ -1,17 +1,62 @@
|
|
1
1
|
# Rack::RequestReplication - Replicate Rack app HTTP requests
|
2
2
|
|
3
3
|
Replicate requests from one app instance to another. At
|
4
|
-
[Springest](http://www.springest.com) we
|
5
|
-
|
6
|
-
|
4
|
+
[Springest](http://www.springest.com) we used
|
5
|
+
[Gor](https://github.com/buger/gor) once to test our new Postgres stack
|
6
|
+
vs our at that time current MySQL stack.
|
7
|
+
We replicated all live requests to our staging environment to test new
|
8
|
+
code before it went live. With real traffic!
|
7
9
|
|
8
|
-
|
10
|
+
Unfortunately, we could not test everything we wanted with the
|
11
|
+
[setup with Gor](http://devblog.springest.com/testing-big-infrastructure-changes-at-springest/).
|
12
|
+
Stuff that relied on sessions (like
|
13
|
+
[MySpringest](https://www.springest.com/my-springest), and course
|
14
|
+
management through our [Admin panel](http://providers.springest.com/))
|
15
|
+
could not be tested properly because the staging environment did not
|
16
|
+
share sessions with the production stack.
|
17
|
+
|
18
|
+
Recently, @foxycoder was asked to give a talk about these adventures at
|
19
|
+
[Amsterdam.rb](http://www.meetup.com/Amsterdam-rb/events/206133762/).
|
20
|
+
And while we were thinking about all the stuff that we needed to do to
|
21
|
+
get it right with Gor, we came up with the concept of this gem.
|
22
|
+
|
23
|
+
## Full control over the requests through Rack
|
24
|
+
|
25
|
+
This is Rack MiddleWare. And thanks to that, we have all the information
|
26
|
+
and handy tools available to parse and alter request data before we
|
27
|
+
forward it to another stack.
|
28
|
+
|
29
|
+
|
30
|
+
## Features
|
31
|
+
|
32
|
+
At the moment, it just forwards the request with only a couple of
|
33
|
+
changes:
|
34
|
+
|
35
|
+
- The host and/or port to match the stack to forward to.
|
36
|
+
- The session cookie – it stores a persistent link between the source
|
37
|
+
app's session and the destination app's session in Redis.
|
38
|
+
- The CSRF token – same as the session, the destination app's
|
39
|
+
`authenticity_token` is persistent and used in consecutive requests.
|
40
|
+
|
41
|
+
### Session support
|
9
42
|
|
10
43
|
It has support for sessions. To make use of it, you need to have Redis
|
11
44
|
running. Redis serves as a key-value store where sessions from the
|
12
45
|
Source App are linked to sessions from the Forward App. This way both
|
13
46
|
apps can have their own session management.
|
14
47
|
|
48
|
+
### Rails's CSRF tokens
|
49
|
+
|
50
|
+
Rails uses a cross site scripting defense mechanism in the form of an
|
51
|
+
`authenticity_token` parameter. Absense of it, or modifying it between
|
52
|
+
requests results in XSS errors. Therefore we needed to make sure these
|
53
|
+
were properly captured and replaced by the Forwarder before sending the
|
54
|
+
request to the other application.
|
55
|
+
|
56
|
+
CSRF tokens are also persisted in Redis and used in consecutive requests, by
|
57
|
+
updating `params["authenticity_token"]` before handing off the request
|
58
|
+
to the replica app.
|
59
|
+
|
15
60
|
## API Docs
|
16
61
|
|
17
62
|
Check out the official [API docs](http://rubydoc.info/gems/rack-request_replication)
|
@@ -67,13 +67,68 @@ module Rack
|
|
67
67
|
Thread.new do
|
68
68
|
begin
|
69
69
|
forward_request.add_field("Cookie", cookies( request ))
|
70
|
-
|
70
|
+
update_csrf_token_and_cookies( request, http.request(forward_request) )
|
71
71
|
rescue => e
|
72
72
|
logger.debug "Replicating request failed with: #{e.message}"
|
73
73
|
end
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
+
##
|
78
|
+
# Update CSRF token and cookies.
|
79
|
+
#
|
80
|
+
# @param [Rack::Request] request
|
81
|
+
# @param [Net::HTTP::Response] response
|
82
|
+
#
|
83
|
+
def update_csrf_token_and_cookies( request, response )
|
84
|
+
update_csrf_token( request, response )
|
85
|
+
update_cookies( request, response )
|
86
|
+
end
|
87
|
+
|
88
|
+
##
|
89
|
+
# The CSRF-token to use.
|
90
|
+
#
|
91
|
+
# @param [Rack::Request] request
|
92
|
+
# @returns [String]
|
93
|
+
#
|
94
|
+
def csrf_token( request )
|
95
|
+
token = request.params["authenticity_token"]
|
96
|
+
return if token.nil?
|
97
|
+
|
98
|
+
redis.get( "csrf-#{token}" ) || token
|
99
|
+
end
|
100
|
+
|
101
|
+
##
|
102
|
+
# Update CSRF token to bypass XSS errors in Rails.
|
103
|
+
#
|
104
|
+
# @param [Rack::Request] request
|
105
|
+
#
|
106
|
+
def update_csrf_token( request, response )
|
107
|
+
token = request.params["authenticity_token"]
|
108
|
+
return if token.nil?
|
109
|
+
|
110
|
+
response_token = csrf_token_from response
|
111
|
+
return token if response_token.nil?
|
112
|
+
|
113
|
+
redis.set "csrf-#{token}", response_token
|
114
|
+
end
|
115
|
+
|
116
|
+
##
|
117
|
+
# Pull CSRF token from the HTML document's header.
|
118
|
+
#
|
119
|
+
# @param [Net::HTTP::Response] response
|
120
|
+
# @returns [String]
|
121
|
+
#
|
122
|
+
def csrf_token_from( response )
|
123
|
+
response.split("\n").
|
124
|
+
select{|l| l.match(/csrf-token/) }.
|
125
|
+
first.split(" ").
|
126
|
+
select{|t| t.match(/^content=/)}.first.
|
127
|
+
match(/content="(.*)"/)[1]
|
128
|
+
rescue
|
129
|
+
nil
|
130
|
+
end
|
131
|
+
|
77
132
|
##
|
78
133
|
# Update cookies from the forwarded request using the session id
|
79
134
|
# from the cookie of the source app as a key. The cookie is stored
|
@@ -234,6 +289,11 @@ module Rack
|
|
234
289
|
value = request.send( m )
|
235
290
|
replicated_options[m] = value unless value.nil?
|
236
291
|
end
|
292
|
+
|
293
|
+
if replicated_options[:params]["authenticity_token"]
|
294
|
+
replicated_options[:params]["authenticity_token"] = csrf_token
|
295
|
+
end
|
296
|
+
|
237
297
|
replicated_options
|
238
298
|
end
|
239
299
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-request_replication
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Wouter de Vos
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-09-
|
11
|
+
date: 2014-09-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|