request-replay 0.6.3 → 0.7.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.
- checksums.yaml +4 -4
- data/.travis.yml +3 -5
- data/CHANGES.md +5 -0
- data/Gemfile +6 -0
- data/README.md +19 -1
- data/Rakefile +1 -1
- data/lib/request-replay.rb +3 -1
- data/lib/request-replay/middleware.rb +11 -9
- data/lib/request-replay/proxy.rb +25 -0
- data/lib/request-replay/test.rb +38 -0
- data/request-replay.gemspec +15 -8
- data/task/README.md +54 -0
- data/task/gemgem.rb +9 -11
- data/test/test_middleware.rb +79 -0
- data/test/test_proxy.rb +68 -0
- data/test/test_request-replay.rb +78 -0
- metadata +23 -17
- data/task/.gitignore +0 -1
- data/test/test_basic.rb +0 -178
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0335c8c8c412eae553868c108b0d157521c76b0b
|
4
|
+
data.tar.gz: 393e2da293913de62fff4960b5e6fb12b70f6593
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 854270e4079d0737727d53e88f9ceabb836f16ecbbb6cbd7fde7a4400625ea999451c6931d7d1e406216f14cf83bb75cea257110d25657b861c0d4c3e5a03ada
|
7
|
+
data.tar.gz: dc452c780b57c25e28d763acccc48f3e0efa8d71472a772174bdac7ebd525e7af65f303b6d82e230037ef452cdb31585dd9148b7f7c088ec69869c84f4526cce
|
data/.travis.yml
CHANGED
data/CHANGES.md
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
# CHANGES
|
2
2
|
|
3
|
+
## request-replay 0.7.0 -- 2014-03-30
|
4
|
+
|
5
|
+
* Fixed a bug where nginx with sendfile on might not send a full file back.
|
6
|
+
* Introduced RequestReplay::Proxy which could serve as a reverse proxy.
|
7
|
+
|
3
8
|
## request-replay 0.6.3 -- 2013-10-07
|
4
9
|
|
5
10
|
* Fixed an issue where Rack::Request does not try to rewind rack.input for
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -43,6 +43,24 @@ use RequestReplay::Middleware, 'localhost:8080',
|
|
43
43
|
run lambda{ |env| [200, {}, [env.inspect]] }
|
44
44
|
```
|
45
45
|
|
46
|
+
You could also use `RequestReplay::Proxy` as a reverse proxy. Note that
|
47
|
+
this only works on Rack servers which support [Rack Hijacking][].
|
48
|
+
|
49
|
+
[Rack Hijacking]: http://rack.rubyforge.org/doc/SPEC.html
|
50
|
+
|
51
|
+
``` ruby
|
52
|
+
require 'request-replay'
|
53
|
+
run RequestReplay::Proxy.new(
|
54
|
+
'example.com', :add_headers => {'Host' => 'example.com'},
|
55
|
+
# We could also rewrite the env
|
56
|
+
:rewrite_env => lambda{ |env|
|
57
|
+
if env['HTTP_HOST'].start_with?('api.')
|
58
|
+
env['PATH_INFO'] = "/api/#{env['PATH_INFO']}"
|
59
|
+
end
|
60
|
+
env
|
61
|
+
})
|
62
|
+
```
|
63
|
+
|
46
64
|
## CONTRIBUTORS:
|
47
65
|
|
48
66
|
* Jim Wang (@yyjim)
|
@@ -52,7 +70,7 @@ run lambda{ |env| [200, {}, [env.inspect]] }
|
|
52
70
|
|
53
71
|
Apache License 2.0
|
54
72
|
|
55
|
-
Copyright (c) 2013, Lin Jen-Shin (godfat)
|
73
|
+
Copyright (c) 2013-2014, Lin Jen-Shin (godfat)
|
56
74
|
|
57
75
|
Licensed under the Apache License, Version 2.0 (the "License");
|
58
76
|
you may not use this file except in compliance with the License.
|
data/Rakefile
CHANGED
data/lib/request-replay.rb
CHANGED
@@ -4,6 +4,7 @@ require 'stringio'
|
|
4
4
|
|
5
5
|
class RequestReplay
|
6
6
|
autoload :Middleware, 'request-replay/middleware'
|
7
|
+
autoload :Proxy , 'request-replay/proxy'
|
7
8
|
|
8
9
|
NEWLINE = "\r\n" .freeze
|
9
10
|
HTTP_VERSION = 'HTTP/1.1' .freeze
|
@@ -25,6 +26,8 @@ class RequestReplay
|
|
25
26
|
IO.copy_stream(env[RACK_INPUT], @buf)
|
26
27
|
@buf.rewind
|
27
28
|
env[RACK_INPUT].rewind
|
29
|
+
else
|
30
|
+
@buf = nil
|
28
31
|
end
|
29
32
|
end
|
30
33
|
|
@@ -40,7 +43,6 @@ class RequestReplay
|
|
40
43
|
write_request
|
41
44
|
write_headers
|
42
45
|
write_payload
|
43
|
-
sock.close_write
|
44
46
|
IO.select([sock], [], [], read_wait) if read_wait
|
45
47
|
yield(sock) if block_given?
|
46
48
|
rescue => e
|
@@ -7,17 +7,19 @@ class RequestReplay::Middleware
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def call env
|
10
|
-
# Unfortunately, we need to dup env because other middleware might be
|
11
|
-
# modifying it and make RequestReplay not able to get the original env.
|
12
|
-
rr_env = if rewrite = @options[:rewrite_env]
|
13
|
-
rewrite.call(env.dup)
|
14
|
-
else
|
15
|
-
env.dup
|
16
|
-
end
|
17
|
-
|
18
10
|
# We don't want to read the socket in a thread, so create it in main
|
19
11
|
# thread, and send the data in a thread as we don't care the responses.
|
20
|
-
Thread.new(RequestReplay.new(
|
12
|
+
Thread.new(RequestReplay.new(rewrite_env(env), @host, @options), &:start)
|
21
13
|
@app.call(env)
|
22
14
|
end
|
15
|
+
|
16
|
+
def rewrite_env env
|
17
|
+
# Unfortunately, we need to dup env because other middleware might be
|
18
|
+
# modifying it and make RequestReplay not able to get the original env.
|
19
|
+
if rewrite = @options[:rewrite_env]
|
20
|
+
rewrite.call(env.dup)
|
21
|
+
else
|
22
|
+
env.dup
|
23
|
+
end
|
24
|
+
end
|
23
25
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
|
2
|
+
require 'request-replay'
|
3
|
+
|
4
|
+
class RequestReplay::Proxy
|
5
|
+
def initialize host, options={}
|
6
|
+
@host, @options = host, options
|
7
|
+
end
|
8
|
+
|
9
|
+
def call env
|
10
|
+
env['rack.hijack'].call
|
11
|
+
RequestReplay.new(rewrite_env(env), @host, @options).start do |sock|
|
12
|
+
IO.copy_stream(sock, env['rack.hijack_io'])
|
13
|
+
env['rack.hijack_io'].close
|
14
|
+
end
|
15
|
+
[200, {}, []]
|
16
|
+
end
|
17
|
+
|
18
|
+
def rewrite_env env
|
19
|
+
if rewrite = @options[:rewrite_env]
|
20
|
+
rewrite.call(env)
|
21
|
+
else
|
22
|
+
env
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
|
2
|
+
require 'bacon'
|
3
|
+
require 'muack'
|
4
|
+
|
5
|
+
require 'request-replay'
|
6
|
+
require 'rack'
|
7
|
+
|
8
|
+
Bacon.summary_on_exit
|
9
|
+
Bacon::Context.__send__(:include, Muack::API)
|
10
|
+
|
11
|
+
module Kernel
|
12
|
+
def eq? rhs
|
13
|
+
self == rhs
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
shared :test do
|
18
|
+
@host = 'localhost'.freeze
|
19
|
+
@port = 1024 + rand(2**16 - 1024)
|
20
|
+
@serv = TCPServer.new('localhost', @port)
|
21
|
+
@hopt = "#{@host}:#{@port}".freeze
|
22
|
+
@env = {'REQUEST_METHOD' => 'GET',
|
23
|
+
'PATH_INFO' => '/', 'QUERY_STRING' => 'q=1',
|
24
|
+
'HTTP_HOST' => 'localhost',
|
25
|
+
'HTTP_PORK' => 'BEEF' }.freeze
|
26
|
+
|
27
|
+
@verify = lambda do |response, expected|
|
28
|
+
sock = @serv.accept
|
29
|
+
if expected.start_with?('POST')
|
30
|
+
sock.readline("\r\n\r\n") + sock.readline("\r\n\r\n")
|
31
|
+
else
|
32
|
+
sock.readline("\r\n\r\n")
|
33
|
+
end.should.eq(expected)
|
34
|
+
sock.write(expected)
|
35
|
+
sock.close
|
36
|
+
response.value.should.eq(expected)
|
37
|
+
end
|
38
|
+
end
|
data/request-replay.gemspec
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
# stub: request-replay 0.
|
2
|
+
# stub: request-replay 0.7.0 ruby lib
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = "request-replay"
|
6
|
-
s.version = "0.
|
6
|
+
s.version = "0.7.0"
|
7
7
|
|
8
8
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
9
|
+
s.require_paths = ["lib"]
|
9
10
|
s.authors = ["Lin Jen-Shin (godfat)"]
|
10
|
-
s.date = "
|
11
|
+
s.date = "2014-03-30"
|
11
12
|
s.description = "Replay the request via Rack env"
|
12
13
|
s.email = ["godfat (XD) godfat.org"]
|
13
14
|
s.files = [
|
@@ -21,16 +22,22 @@ Gem::Specification.new do |s|
|
|
21
22
|
"Rakefile",
|
22
23
|
"lib/request-replay.rb",
|
23
24
|
"lib/request-replay/middleware.rb",
|
25
|
+
"lib/request-replay/proxy.rb",
|
26
|
+
"lib/request-replay/test.rb",
|
24
27
|
"request-replay.gemspec",
|
25
|
-
"task
|
28
|
+
"task/README.md",
|
26
29
|
"task/gemgem.rb",
|
27
|
-
"test/
|
30
|
+
"test/test_middleware.rb",
|
31
|
+
"test/test_proxy.rb",
|
32
|
+
"test/test_request-replay.rb"]
|
28
33
|
s.homepage = "https://github.com/godfat/request-replay"
|
29
34
|
s.licenses = ["Apache License 2.0"]
|
30
|
-
s.
|
31
|
-
s.rubygems_version = "2.1.5"
|
35
|
+
s.rubygems_version = "2.2.2"
|
32
36
|
s.summary = "Replay the request via Rack env"
|
33
|
-
s.test_files = [
|
37
|
+
s.test_files = [
|
38
|
+
"test/test_middleware.rb",
|
39
|
+
"test/test_proxy.rb",
|
40
|
+
"test/test_request-replay.rb"]
|
34
41
|
|
35
42
|
if s.respond_to? :specification_version then
|
36
43
|
s.specification_version = 4
|
data/task/README.md
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
# Gemgem
|
2
|
+
|
3
|
+
## DESCRIPTION:
|
4
|
+
|
5
|
+
Provided tasks:
|
6
|
+
|
7
|
+
rake clean # Remove ignored files
|
8
|
+
rake gem:build # Build gem
|
9
|
+
rake gem:install # Install gem
|
10
|
+
rake gem:release # Release gem
|
11
|
+
rake gem:spec # Generate gemspec
|
12
|
+
rake test # Run tests in memory
|
13
|
+
|
14
|
+
## REQUIREMENTS:
|
15
|
+
|
16
|
+
* Tested with MRI (official CRuby) 1.9.3, 2.0.0, Rubinius and JRuby.
|
17
|
+
|
18
|
+
## INSTALLATION:
|
19
|
+
|
20
|
+
git submodule add git://github.com/godfat/gemgem.git task
|
21
|
+
|
22
|
+
And in Rakefile:
|
23
|
+
|
24
|
+
``` ruby
|
25
|
+
begin
|
26
|
+
require "#{dir = File.dirname(__FILE__)}/task/gemgem"
|
27
|
+
rescue LoadError
|
28
|
+
sh 'git submodule update --init'
|
29
|
+
exec Gem.ruby, '-S', $PROGRAM_NAME, *ARGV
|
30
|
+
end
|
31
|
+
|
32
|
+
Gemgem.init(dir) do |s|
|
33
|
+
s.name = 'your-gem'
|
34
|
+
s.version = '0.1.0'
|
35
|
+
end
|
36
|
+
```
|
37
|
+
|
38
|
+
## LICENSE:
|
39
|
+
|
40
|
+
Apache License 2.0
|
41
|
+
|
42
|
+
Copyright (c) 2011-2013, Lin Jen-Shin (godfat)
|
43
|
+
|
44
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
45
|
+
you may not use this file except in compliance with the License.
|
46
|
+
You may obtain a copy of the License at
|
47
|
+
|
48
|
+
<http://www.apache.org/licenses/LICENSE-2.0>
|
49
|
+
|
50
|
+
Unless required by applicable law or agreed to in writing, software
|
51
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
52
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
53
|
+
See the License for the specific language governing permissions and
|
54
|
+
limitations under the License.
|
data/task/gemgem.rb
CHANGED
@@ -144,20 +144,18 @@ module Gemgem
|
|
144
144
|
end
|
145
145
|
|
146
146
|
def ignored_pattern
|
147
|
-
@ignored_pattern ||=
|
147
|
+
@ignored_pattern ||= if gitignore.empty?
|
148
|
+
/^$/
|
149
|
+
else
|
150
|
+
Regexp.new(expand_patterns(gitignore).join('|'))
|
151
|
+
end
|
148
152
|
end
|
149
153
|
|
150
154
|
def expand_patterns pathes
|
151
155
|
# http://git-scm.com/docs/gitignore
|
152
156
|
pathes.flat_map{ |path|
|
153
|
-
|
154
|
-
|
155
|
-
Regexp.escape(path).gsub(/\\\*/, '[^/]*')
|
156
|
-
when %r{^/}
|
157
|
-
"^#{Regexp.escape(path[1..-1])}"
|
158
|
-
else # we didn't implement negative pattern for now
|
159
|
-
Regexp.escape(path)
|
160
|
-
end
|
157
|
+
# we didn't implement negative pattern for now
|
158
|
+
Regexp.escape(path).sub(%r{^/}, '^').gsub(/\\\*/, '[^/]*')
|
161
159
|
}
|
162
160
|
end
|
163
161
|
|
@@ -226,7 +224,7 @@ end
|
|
226
224
|
|
227
225
|
end # of gem namespace
|
228
226
|
|
229
|
-
desc 'Run tests
|
227
|
+
desc 'Run tests'
|
230
228
|
task :test do
|
231
229
|
next if Gemgem.test_files.empty?
|
232
230
|
|
@@ -236,7 +234,7 @@ task :test do
|
|
236
234
|
Gemgem.test_files.each{ |file| require "#{Gemgem.dir}/#{file[0..-4]}" }
|
237
235
|
end
|
238
236
|
|
239
|
-
desc '
|
237
|
+
desc 'Trash ignored files'
|
240
238
|
task :clean => ['gem:spec'] do
|
241
239
|
next if Gemgem.ignored_files.empty?
|
242
240
|
|
@@ -0,0 +1,79 @@
|
|
1
|
+
|
2
|
+
require 'request-replay/test'
|
3
|
+
|
4
|
+
describe RequestReplay::Middleware do
|
5
|
+
behaves_like :test
|
6
|
+
|
7
|
+
should 'PUT' do
|
8
|
+
hopt = @hopt
|
9
|
+
app = Rack::Builder.app do
|
10
|
+
use RequestReplay::Middleware, hopt
|
11
|
+
run lambda{ |_| [200, {}, []] }
|
12
|
+
end
|
13
|
+
|
14
|
+
app.call(@env.merge('REQUEST_METHOD' => 'PUT'))
|
15
|
+
begin
|
16
|
+
sock = @serv.accept
|
17
|
+
sock.read.should.eq <<-HTTP
|
18
|
+
PUT /?q=1 HTTP/1.1\r
|
19
|
+
Host: localhost\r
|
20
|
+
Pork: BEEF\r
|
21
|
+
\r
|
22
|
+
HTTP
|
23
|
+
ensure
|
24
|
+
sock.close
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
should 'retain original env' do
|
29
|
+
hopt = @hopt
|
30
|
+
e = @env.dup
|
31
|
+
|
32
|
+
app = Rack::Builder.app do
|
33
|
+
use RequestReplay::Middleware, hopt
|
34
|
+
run lambda{ |env|
|
35
|
+
env['PATH_INFO'] = '/bad'
|
36
|
+
[200, {}, []]
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
app.call(e)
|
41
|
+
begin
|
42
|
+
sock = @serv.accept
|
43
|
+
sock.read.should.eq <<-HTTP
|
44
|
+
GET /?q=1 HTTP/1.1\r
|
45
|
+
Host: localhost\r
|
46
|
+
Pork: BEEF\r
|
47
|
+
\r
|
48
|
+
HTTP
|
49
|
+
ensure
|
50
|
+
sock.close
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
should 'rewrite_env' do
|
55
|
+
hopt = @hopt
|
56
|
+
app = Rack::Builder.app do
|
57
|
+
use RequestReplay::Middleware, hopt, :rewrite_env => lambda{ |env|
|
58
|
+
if env['HTTP_HOST'].start_with?('api.')
|
59
|
+
env['PATH_INFO'] = "/api#{env['PATH_INFO']}"
|
60
|
+
end
|
61
|
+
env
|
62
|
+
}, :add_headers => {'Host' => 'eg.com'}
|
63
|
+
run lambda{ |_| [200, {}, []] }
|
64
|
+
end
|
65
|
+
|
66
|
+
app.call(@env.merge('HTTP_HOST' => 'api.localhost'))
|
67
|
+
begin
|
68
|
+
sock = @serv.accept
|
69
|
+
sock.read.should.eq <<-HTTP
|
70
|
+
GET /api/?q=1 HTTP/1.1\r
|
71
|
+
Host: eg.com\r
|
72
|
+
Pork: BEEF\r
|
73
|
+
\r
|
74
|
+
HTTP
|
75
|
+
ensure
|
76
|
+
sock.close
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/test/test_proxy.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
require 'request-replay/test'
|
4
|
+
|
5
|
+
describe RequestReplay::Proxy do
|
6
|
+
behaves_like :test
|
7
|
+
|
8
|
+
request = lambda do |env, buf, options={}|
|
9
|
+
mock(buf).close
|
10
|
+
Thread.new{
|
11
|
+
begin
|
12
|
+
RequestReplay::Proxy.new(@hopt, options).call(env)
|
13
|
+
buf.string
|
14
|
+
rescue => e
|
15
|
+
p e
|
16
|
+
end
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
after do
|
21
|
+
Muack.verify
|
22
|
+
end
|
23
|
+
|
24
|
+
should 'basic' do
|
25
|
+
expected = <<-HTTP
|
26
|
+
GET /?q=1 HTTP/1.1\r
|
27
|
+
Host: localhost\r
|
28
|
+
Pork: BEEF\r
|
29
|
+
\r
|
30
|
+
HTTP
|
31
|
+
|
32
|
+
buf = StringIO.new
|
33
|
+
env = {'rack.hijack' => mock.call{ env['rack.hijack_io'] = buf }.object}.
|
34
|
+
merge(@env)
|
35
|
+
|
36
|
+
@verify[request[env, buf], expected]
|
37
|
+
end
|
38
|
+
|
39
|
+
should 'add_headers' do
|
40
|
+
expected = <<-HTTP
|
41
|
+
GET /?q=1 HTTP/1.1\r
|
42
|
+
Host: ex.com\r
|
43
|
+
Pork: BEEF\r
|
44
|
+
\r
|
45
|
+
HTTP
|
46
|
+
|
47
|
+
buf = StringIO.new
|
48
|
+
env = {'rack.hijack' => mock.call{ env['rack.hijack_io'] = buf }.object}.
|
49
|
+
merge(@env)
|
50
|
+
|
51
|
+
@verify[request[env, buf, :add_headers => {'Host' => 'ex.com'}], expected]
|
52
|
+
end
|
53
|
+
|
54
|
+
should 'rewrite_env' do
|
55
|
+
expected = <<-HTTP
|
56
|
+
GET /a?q=1 HTTP/1.1\r
|
57
|
+
Host: localhost\r
|
58
|
+
Pork: BEEF\r
|
59
|
+
\r
|
60
|
+
HTTP
|
61
|
+
|
62
|
+
buf = StringIO.new
|
63
|
+
env = {'rack.hijack' => mock.call{ env['rack.hijack_io'] = buf }.object}.
|
64
|
+
merge(@env)
|
65
|
+
rewrite_env = lambda{ |env| env['PATH_INFO'] = '/a'; env }
|
66
|
+
@verify[request[env, buf, :rewrite_env => rewrite_env], expected]
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
|
2
|
+
require 'request-replay/test'
|
3
|
+
|
4
|
+
describe RequestReplay do
|
5
|
+
behaves_like :test
|
6
|
+
|
7
|
+
request = lambda do |env, headers={}, read_wait=nil|
|
8
|
+
Thread.new(RequestReplay.new(@env.merge(env), @hopt,
|
9
|
+
:add_headers => headers,
|
10
|
+
:read_wait => read_wait)) do |replay|
|
11
|
+
replay.start(&:read)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
after do
|
16
|
+
Muack.verify
|
17
|
+
end
|
18
|
+
|
19
|
+
should 'GET' do
|
20
|
+
@verify[request[{'REQUEST_METHOD' => 'GET'}, 'Host' => 'ex.com'], <<-HTTP]
|
21
|
+
GET /?q=1 HTTP/1.1\r
|
22
|
+
Host: ex.com\r
|
23
|
+
Pork: BEEF\r
|
24
|
+
\r
|
25
|
+
HTTP
|
26
|
+
end
|
27
|
+
|
28
|
+
should 'POST' do
|
29
|
+
@verify[request['REQUEST_METHOD' => 'POST',
|
30
|
+
'QUERY_STRING' => '' , # test no query string
|
31
|
+
'PATH_INFO' => '' , # test no path info
|
32
|
+
'rack.input' => StringIO.new("PAYLOAD\r\n\r\n")], <<-HTTP]
|
33
|
+
POST / HTTP/1.1\r
|
34
|
+
Host: localhost\r
|
35
|
+
Pork: BEEF\r
|
36
|
+
\r
|
37
|
+
PAYLOAD\r
|
38
|
+
\r
|
39
|
+
HTTP
|
40
|
+
end
|
41
|
+
|
42
|
+
should 'read_wait' do
|
43
|
+
read_wait = 5
|
44
|
+
mock(IO).select(satisfy{ |rs| rs.size == 1 &&
|
45
|
+
rs[0].kind_of?(IO) },
|
46
|
+
[], [], read_wait)
|
47
|
+
|
48
|
+
@verify[request[{}, {}, read_wait], <<-HTTP]
|
49
|
+
GET /?q=1 HTTP/1.1\r
|
50
|
+
Host: localhost\r
|
51
|
+
Pork: BEEF\r
|
52
|
+
\r
|
53
|
+
HTTP
|
54
|
+
end
|
55
|
+
|
56
|
+
should 'puts error' do
|
57
|
+
any_instance_of(TCPSocket) do |sock|
|
58
|
+
mock(sock).read{ raise 'ERROR' }
|
59
|
+
end
|
60
|
+
|
61
|
+
errors = StringIO.new
|
62
|
+
begin
|
63
|
+
request['rack.errors' => errors].value
|
64
|
+
ensure
|
65
|
+
@serv.accept.close
|
66
|
+
end
|
67
|
+
errors.string.should.start_with? '[RequestReplay] Error:'
|
68
|
+
end
|
69
|
+
|
70
|
+
should 'not affect Rack::Request' do
|
71
|
+
input = StringIO.new('a=0&b=1')
|
72
|
+
e = {'rack.input' => input, 'REQUEST_METHOD' => 'POST'}
|
73
|
+
t = request[e]
|
74
|
+
@serv.accept.close
|
75
|
+
t.join
|
76
|
+
Rack::Request.new(e).POST.should.eq('a' => '0', 'b' => '1')
|
77
|
+
end
|
78
|
+
end
|
metadata
CHANGED
@@ -1,55 +1,55 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: request-replay
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lin Jen-Shin (godfat)
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2014-03-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bacon
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: muack
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rack
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
description: Replay the request via Rack env
|
@@ -59,9 +59,9 @@ executables: []
|
|
59
59
|
extensions: []
|
60
60
|
extra_rdoc_files: []
|
61
61
|
files:
|
62
|
-
- .gitignore
|
63
|
-
- .gitmodules
|
64
|
-
- .travis.yml
|
62
|
+
- ".gitignore"
|
63
|
+
- ".gitmodules"
|
64
|
+
- ".travis.yml"
|
65
65
|
- CHANGES.md
|
66
66
|
- Gemfile
|
67
67
|
- LICENSE
|
@@ -69,10 +69,14 @@ files:
|
|
69
69
|
- Rakefile
|
70
70
|
- lib/request-replay.rb
|
71
71
|
- lib/request-replay/middleware.rb
|
72
|
+
- lib/request-replay/proxy.rb
|
73
|
+
- lib/request-replay/test.rb
|
72
74
|
- request-replay.gemspec
|
73
|
-
- task
|
75
|
+
- task/README.md
|
74
76
|
- task/gemgem.rb
|
75
|
-
- test/
|
77
|
+
- test/test_middleware.rb
|
78
|
+
- test/test_proxy.rb
|
79
|
+
- test/test_request-replay.rb
|
76
80
|
homepage: https://github.com/godfat/request-replay
|
77
81
|
licenses:
|
78
82
|
- Apache License 2.0
|
@@ -83,19 +87,21 @@ require_paths:
|
|
83
87
|
- lib
|
84
88
|
required_ruby_version: !ruby/object:Gem::Requirement
|
85
89
|
requirements:
|
86
|
-
- -
|
90
|
+
- - ">="
|
87
91
|
- !ruby/object:Gem::Version
|
88
92
|
version: '0'
|
89
93
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
94
|
requirements:
|
91
|
-
- -
|
95
|
+
- - ">="
|
92
96
|
- !ruby/object:Gem::Version
|
93
97
|
version: '0'
|
94
98
|
requirements: []
|
95
99
|
rubyforge_project:
|
96
|
-
rubygems_version: 2.
|
100
|
+
rubygems_version: 2.2.2
|
97
101
|
signing_key:
|
98
102
|
specification_version: 4
|
99
103
|
summary: Replay the request via Rack env
|
100
104
|
test_files:
|
101
|
-
- test/
|
105
|
+
- test/test_middleware.rb
|
106
|
+
- test/test_proxy.rb
|
107
|
+
- test/test_request-replay.rb
|
data/task/.gitignore
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
*.rbc
|
data/test/test_basic.rb
DELETED
@@ -1,178 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'bacon'
|
3
|
-
require 'muack'
|
4
|
-
|
5
|
-
Bacon.summary_on_exit
|
6
|
-
include Muack::API
|
7
|
-
|
8
|
-
module Kernel
|
9
|
-
def eq? rhs
|
10
|
-
self == rhs
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
require 'request-replay'
|
15
|
-
require 'rack'
|
16
|
-
|
17
|
-
describe RequestReplay do
|
18
|
-
host = 'localhost'.freeze
|
19
|
-
port = 1024 + rand(2**16 - 1024)
|
20
|
-
serv = TCPServer.new('localhost', port)
|
21
|
-
hopt = "#{host}:#{port}".freeze
|
22
|
-
env = {'REQUEST_METHOD' => 'GET',
|
23
|
-
'PATH_INFO' => '/', 'QUERY_STRING' => 'q=1',
|
24
|
-
'HTTP_HOST' => 'localhost',
|
25
|
-
'HTTP_PORK' => 'BEEF' }.freeze
|
26
|
-
|
27
|
-
verify = lambda do |response, expected|
|
28
|
-
sock = serv.accept
|
29
|
-
sock.read .should.eq(expected)
|
30
|
-
sock.write(expected)
|
31
|
-
sock.close
|
32
|
-
response.value.should.eq(expected)
|
33
|
-
end
|
34
|
-
|
35
|
-
request = lambda do |env1, headers={}, read_wait=nil|
|
36
|
-
Thread.new(RequestReplay.new(env.merge(env1), hopt,
|
37
|
-
:add_headers => headers,
|
38
|
-
:read_wait => read_wait)) do |replay|
|
39
|
-
replay.start(&:read)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
after do
|
44
|
-
Muack.verify
|
45
|
-
end
|
46
|
-
|
47
|
-
should 'GET' do
|
48
|
-
verify[request[{'REQUEST_METHOD' => 'GET'}, 'Host' => 'ex.com'], <<-HTTP]
|
49
|
-
GET /?q=1 HTTP/1.1\r
|
50
|
-
Host: ex.com\r
|
51
|
-
Pork: BEEF\r
|
52
|
-
\r
|
53
|
-
HTTP
|
54
|
-
end
|
55
|
-
|
56
|
-
should 'POST' do
|
57
|
-
verify[request['REQUEST_METHOD' => 'POST',
|
58
|
-
'QUERY_STRING' => '' , # test no query string
|
59
|
-
'PATH_INFO' => '' , # test no path info
|
60
|
-
'rack.input' => StringIO.new("PAYLOAD\r\n\r\n")], <<-HTTP]
|
61
|
-
POST / HTTP/1.1\r
|
62
|
-
Host: localhost\r
|
63
|
-
Pork: BEEF\r
|
64
|
-
\r
|
65
|
-
PAYLOAD\r
|
66
|
-
\r
|
67
|
-
HTTP
|
68
|
-
end
|
69
|
-
|
70
|
-
should 'read_wait' do
|
71
|
-
read_wait = 5
|
72
|
-
mock(IO).select(satisfy{ |rs| rs.size == 1 &&
|
73
|
-
rs[0].kind_of?(IO) },
|
74
|
-
[], [], read_wait)
|
75
|
-
|
76
|
-
verify[request[{}, {}, read_wait], <<-HTTP]
|
77
|
-
GET /?q=1 HTTP/1.1\r
|
78
|
-
Host: localhost\r
|
79
|
-
Pork: BEEF\r
|
80
|
-
\r
|
81
|
-
HTTP
|
82
|
-
end
|
83
|
-
|
84
|
-
should 'puts error' do
|
85
|
-
any_instance_of(TCPSocket) do |sock|
|
86
|
-
mock(sock).read{ raise 'ERROR' }
|
87
|
-
end
|
88
|
-
|
89
|
-
errors = StringIO.new
|
90
|
-
begin
|
91
|
-
request['rack.errors' => errors].value
|
92
|
-
ensure
|
93
|
-
serv.accept.close
|
94
|
-
end
|
95
|
-
errors.string.should.start_with? '[RequestReplay] Error:'
|
96
|
-
end
|
97
|
-
|
98
|
-
should 'not affect Rack::Request' do
|
99
|
-
input = StringIO.new('a=0&b=1')
|
100
|
-
e = {'rack.input' => input, 'REQUEST_METHOD' => 'POST'}
|
101
|
-
t = request[e]
|
102
|
-
serv.accept.close
|
103
|
-
t.join
|
104
|
-
Rack::Request.new(e).POST.should.eq('a' => '0', 'b' => '1')
|
105
|
-
end
|
106
|
-
|
107
|
-
describe RequestReplay::Middleware do
|
108
|
-
should 'PUT' do
|
109
|
-
app = Rack::Builder.app do
|
110
|
-
use RequestReplay::Middleware, hopt
|
111
|
-
run lambda{ |env| [200, {}, []] }
|
112
|
-
end
|
113
|
-
|
114
|
-
app.call(env.merge('REQUEST_METHOD' => 'PUT'))
|
115
|
-
begin
|
116
|
-
sock = serv.accept
|
117
|
-
sock.read.should.eq <<-HTTP
|
118
|
-
PUT /?q=1 HTTP/1.1\r
|
119
|
-
Host: localhost\r
|
120
|
-
Pork: BEEF\r
|
121
|
-
\r
|
122
|
-
HTTP
|
123
|
-
ensure
|
124
|
-
sock.close
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
should 'retain original env' do
|
129
|
-
e = env.dup
|
130
|
-
|
131
|
-
app = Rack::Builder.app do
|
132
|
-
use RequestReplay::Middleware, hopt
|
133
|
-
run lambda{ |env|
|
134
|
-
env['PATH_INFO'] = '/bad'
|
135
|
-
[200, {}, []]
|
136
|
-
}
|
137
|
-
end
|
138
|
-
|
139
|
-
app.call(e)
|
140
|
-
begin
|
141
|
-
sock = serv.accept
|
142
|
-
sock.read.should.eq <<-HTTP
|
143
|
-
GET /?q=1 HTTP/1.1\r
|
144
|
-
Host: localhost\r
|
145
|
-
Pork: BEEF\r
|
146
|
-
\r
|
147
|
-
HTTP
|
148
|
-
ensure
|
149
|
-
sock.close
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
should 'rewrite_env' do
|
154
|
-
app = Rack::Builder.app do
|
155
|
-
use RequestReplay::Middleware, hopt, :rewrite_env => lambda{ |env|
|
156
|
-
if env['HTTP_HOST'].start_with?('api.')
|
157
|
-
env['PATH_INFO'] = "/api#{env['PATH_INFO']}"
|
158
|
-
end
|
159
|
-
env
|
160
|
-
}, :add_headers => {'Host' => 'eg.com'}
|
161
|
-
run lambda{ |env| [200, {}, []] }
|
162
|
-
end
|
163
|
-
|
164
|
-
app.call(env.merge('HTTP_HOST' => 'api.localhost'))
|
165
|
-
begin
|
166
|
-
sock = serv.accept
|
167
|
-
sock.read.should.eq <<-HTTP
|
168
|
-
GET /api/?q=1 HTTP/1.1\r
|
169
|
-
Host: eg.com\r
|
170
|
-
Pork: BEEF\r
|
171
|
-
\r
|
172
|
-
HTTP
|
173
|
-
ensure
|
174
|
-
sock.close
|
175
|
-
end
|
176
|
-
end
|
177
|
-
end
|
178
|
-
end
|