slow_server 0.1.2 → 0.1.3
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/README.md +38 -13
- data/exe/slow_client +2 -2
- data/exe/slow_server +2 -2
- data/lib/slow_server.rb +4 -9
- data/lib/slow_server/client.rb +29 -19
- data/lib/slow_server/config.rb +53 -11
- data/lib/slow_server/server.rb +48 -19
- data/lib/slow_server/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: 7e993e4056d8bcf3c4f2aad4e5a826a9ff13a27f
|
4
|
+
data.tar.gz: 2ffe6af0c24b470cb1dd1d462dbacc5e3405c48b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cc65204f942fa8d813b831688f247f59371baa37de6cb593a4ba8d4cdee5f8100d47d3b8b92a2eba003e93086c40613cdd1a7f04534da9b8b3bef1d31dca1128
|
7
|
+
data.tar.gz: 9ffdf2608647676aec94d9172cae6a0c720cd89551b771fb65675288b25c502a65cd1c925585e14f1234ce31df1f8fa1547797cc2af101aff967707a02ef1fc1
|
data/README.md
CHANGED
@@ -1,28 +1,53 @@
|
|
1
1
|
# SlowServer
|
2
2
|
|
3
|
-
|
3
|
+
This Gem has two parts, slow_server and slow_client, together they can be used to
|
4
|
+
test timeouts in various stages of connections.
|
4
5
|
|
5
|
-
|
6
|
+
Currently there are two types of delays supported by both client and server,
|
7
|
+
initial delay and chunk delay.
|
8
|
+
|
9
|
+
Initial delay (--delay) causes both client and server to wait some amount of
|
10
|
+
seconds after the connection is opened before sending anything.
|
11
|
+
|
12
|
+
Chunk delay (--chunk-delay) works together with chunk count (--chunks) to split the
|
13
|
+
message into chunks and send them one chunk at a time with some delay between. You
|
14
|
+
can think of this similar to Chunked Encoding for HTTP, but it's not actually using
|
15
|
+
Chunked Encoding
|
6
16
|
|
7
17
|
## Installation
|
8
18
|
|
9
|
-
|
19
|
+
$ gem install slow_server
|
10
20
|
|
11
|
-
|
12
|
-
gem 'slow_server'
|
13
|
-
```
|
21
|
+
## Usage
|
14
22
|
|
15
|
-
|
23
|
+
###slow_client
|
16
24
|
|
17
|
-
|
25
|
+
slow_client is somewhat similar to slowloris, it has tunable delays for various different phases of connection.
|
18
26
|
|
19
|
-
|
27
|
+
```
|
28
|
+
$ slow_client --help
|
29
|
+
Usage: slow_client [OPTIONS] [URI]
|
30
|
+
-X, --method METHOD Request Method (default: GET)
|
31
|
+
-p, --port NUMBER Listen Port (default: 4000)
|
32
|
+
-c, --chunks BYTES Chunks (default: 1)
|
33
|
+
-d, --delay SECONDS Transmission delay after connecting (default: 0)
|
34
|
+
-k, --chunk-delay SECONDS Delay between chunks (default: 0)
|
35
|
+
-v, --version Show Version
|
36
|
+
```
|
20
37
|
|
21
|
-
|
38
|
+
###slow_server
|
22
39
|
|
23
|
-
|
40
|
+
slow_server is the counterpart to slow_client, by default it will respond with the story of The Tortoise and The Hare, but it too has tunable delays.
|
24
41
|
|
25
|
-
|
42
|
+
```
|
43
|
+
$ slow_server --help
|
44
|
+
Usage: slow_server [OPTIONS] [RESPONSE]
|
45
|
+
-p, --port NUMBER Listen Port (default: 4000)
|
46
|
+
-c, --chunks BYTES Chunks (default: 1)
|
47
|
+
-d, --delay SECONDS Transmission delay after connecting (default: 0)
|
48
|
+
-k, --chunk-delay SECONDS Delay between chunks (default: 0)
|
49
|
+
-v, --version Show Version
|
50
|
+
```
|
26
51
|
|
27
52
|
## Development
|
28
53
|
|
@@ -32,7 +57,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
32
57
|
|
33
58
|
## Contributing
|
34
59
|
|
35
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
60
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/jscholl/slow_server.
|
36
61
|
|
37
62
|
|
38
63
|
## License
|
data/exe/slow_client
CHANGED
data/exe/slow_server
CHANGED
data/lib/slow_server.rb
CHANGED
@@ -6,17 +6,12 @@ require "slow_server/config"
|
|
6
6
|
module SlowServer
|
7
7
|
class << self
|
8
8
|
|
9
|
-
def
|
10
|
-
@
|
9
|
+
def server
|
10
|
+
@server ||= Server.new
|
11
11
|
end
|
12
12
|
|
13
|
-
def
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
def configure!
|
18
|
-
@config = Config.new
|
19
|
-
yield config
|
13
|
+
def client
|
14
|
+
@client ||= Client.new
|
20
15
|
end
|
21
16
|
|
22
17
|
end
|
data/lib/slow_server/client.rb
CHANGED
@@ -1,41 +1,51 @@
|
|
1
1
|
require 'socket'
|
2
|
+
require 'uri'
|
2
3
|
|
3
4
|
module SlowServer
|
4
5
|
class Client
|
5
6
|
|
6
7
|
def config
|
7
|
-
|
8
|
+
@config ||= ClientConfig.new
|
8
9
|
end
|
9
10
|
|
10
11
|
def chunk_size
|
11
|
-
(
|
12
|
+
(request_body.size / config.chunks.to_f).round
|
12
13
|
end
|
13
14
|
|
14
15
|
def chunks
|
15
|
-
|
16
|
+
request_body.scan(/.{1,#{chunk_size}}/m)
|
16
17
|
end
|
17
18
|
|
18
|
-
def
|
19
|
-
|
19
|
+
def request_body
|
20
|
+
[].tap do |req|
|
21
|
+
req << [config.request_method, config.request_uri].join(" ")
|
22
|
+
req += config.request_headers
|
23
|
+
end.join("\n")
|
24
|
+
end
|
25
|
+
|
26
|
+
def send_request(socket)
|
27
|
+
chunks.each do |chunk|
|
28
|
+
STDERR.puts "Sending #{chunk_size} bytes"
|
29
|
+
socket.print chunk
|
30
|
+
STDERR.puts "Waiting for #{config.chunk_delay} seconds"
|
31
|
+
sleep config.chunk_delay
|
32
|
+
end
|
33
|
+
socket.print("\r\n\r\n")
|
34
|
+
end
|
35
|
+
|
36
|
+
def get_response(socket)
|
37
|
+
response = socket.read
|
38
|
+
headers,body = response.split("\r\n\r\n", 2)
|
39
|
+
STDERR.puts "\n"
|
40
|
+
print body
|
20
41
|
end
|
21
42
|
|
22
43
|
def start
|
23
|
-
TCPSocket.open(
|
44
|
+
TCPSocket.open(config.host, config.port) do |socket|
|
24
45
|
STDERR.puts "Waiting for #{config.response_delay} seconds"
|
25
46
|
sleep config.response_delay
|
26
|
-
|
27
|
-
|
28
|
-
STDERR.puts "Sending #{chunk_size} bytes"
|
29
|
-
socket.print chunk
|
30
|
-
STDERR.puts "Waiting for #{config.chunk_delay} seconds"
|
31
|
-
sleep config.chunk_delay
|
32
|
-
end
|
33
|
-
socket.print("\r\n\r\n")
|
34
|
-
|
35
|
-
response = socket.read
|
36
|
-
headers,body = response.split("\r\n\r\n", 2)
|
37
|
-
STDERR.puts "\n"
|
38
|
-
print body
|
47
|
+
send_request(socket)
|
48
|
+
get_response(socket)
|
39
49
|
end
|
40
50
|
end
|
41
51
|
|
data/lib/slow_server/config.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
require 'optparse'
|
2
|
+
require 'uri'
|
2
3
|
|
3
4
|
module SlowServer
|
5
|
+
|
4
6
|
class Config
|
5
|
-
attr_accessor :
|
7
|
+
attr_accessor :port, :chunks, :response_delay, :chunk_delay
|
6
8
|
|
7
9
|
def initialize
|
8
|
-
# set defaults
|
9
|
-
self.response = File.read(File.expand_path("../../../files/response.txt", __FILE__))
|
10
10
|
self.port = 4000
|
11
11
|
self.chunks = 1
|
12
12
|
self.response_delay = 0
|
@@ -16,17 +16,59 @@ module SlowServer
|
|
16
16
|
def opts
|
17
17
|
@opts ||= OptionParser.new do |opt|
|
18
18
|
opt.banner = "Usage: #{File.basename($PROGRAM_NAME)} [OPTIONS] [RESPONSE]"
|
19
|
-
opt.on("-p", "--port NUMBER", Integer, "Listen Port
|
20
|
-
opt.on("-c", "--chunks BYTES", Integer, "Chunks
|
21
|
-
opt.on("-
|
22
|
-
opt.on("-k", "--chunk-delay SECONDS", Float, "Delay between chunks
|
23
|
-
opt.on("-v", "--version", "Show Version")
|
19
|
+
opt.on("-p", "--port NUMBER", Integer, "Listen Port (default: #{self.port})") { |v| self.port = v }
|
20
|
+
opt.on("-c", "--chunks BYTES", Integer, "Chunks (default: #{self.chunks})") { |v| self.chunks = v }
|
21
|
+
opt.on("-d", "--delay SECONDS", Integer, "Transmission delay after connecting (default: #{self.response_delay})") { |v| self.response_delay = v }
|
22
|
+
opt.on("-k", "--chunk-delay SECONDS", Float, "Delay between chunks (default: #{self.chunk_delay})") { |v| self.chunk_delay = v }
|
23
|
+
opt.on("-v", "--version", "Show Version") { puts SlowServer::VERSION; throw :exit }
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
def
|
28
|
-
|
29
|
-
|
27
|
+
def args
|
28
|
+
opts.parse!
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class ServerConfig < Config
|
33
|
+
attr_accessor :response_body
|
34
|
+
|
35
|
+
def initialize
|
36
|
+
super
|
37
|
+
self.response_body = File.read(File.expand_path("../../../files/response.txt", __FILE__))
|
38
|
+
end
|
39
|
+
|
40
|
+
def parse
|
41
|
+
response = args.join(" ")
|
42
|
+
self.response_body = response unless response.empty?
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class ClientConfig < Config
|
47
|
+
attr_accessor :request_method, :host, :request_uri, :request_headers
|
48
|
+
|
49
|
+
def initialize
|
50
|
+
super
|
51
|
+
self.request_method = 'GET'
|
52
|
+
self.host = 'localhost'
|
53
|
+
self.request_uri = "/"
|
54
|
+
self.request_headers = []
|
55
|
+
end
|
56
|
+
|
57
|
+
def opts
|
58
|
+
opts = super
|
59
|
+
opts.banner = "Usage: #{File.basename($PROGRAM_NAME)} [OPTIONS] [URI]"
|
60
|
+
opts.on_head("-p", "--port NUMBER", Integer, "Listen Port (default: #{self.port})") { |v| @port_override = v }
|
61
|
+
opts.on_head("-X", "--method METHOD", String, "Request Method (default: #{self.request_method})") { |v| self.request_method = v }
|
62
|
+
end
|
63
|
+
|
64
|
+
def parse
|
65
|
+
uri = URI.parse(args[0])
|
66
|
+
if !uri.respond_to?(:request_uri) && uri !~ %r{^\w+:\/\/}
|
67
|
+
uri = URI.parse("http://#{uri}")
|
68
|
+
end
|
69
|
+
self.host = uri.host
|
70
|
+
self.port = @port_override || uri.port
|
71
|
+
self.request_uri = uri.request_uri if uri.request_uri
|
30
72
|
end
|
31
73
|
|
32
74
|
end
|
data/lib/slow_server/server.rb
CHANGED
@@ -4,7 +4,7 @@ module SlowServer
|
|
4
4
|
class Server
|
5
5
|
|
6
6
|
def config
|
7
|
-
|
7
|
+
@config ||= ServerConfig.new
|
8
8
|
end
|
9
9
|
|
10
10
|
def server
|
@@ -12,35 +12,64 @@ module SlowServer
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def chunk_size
|
15
|
-
config.
|
15
|
+
(config.response_body.size / config.chunks.to_f).round
|
16
16
|
end
|
17
17
|
|
18
|
+
|
18
19
|
def chunks
|
19
|
-
config.
|
20
|
+
#config.response_body.scan(/.{1,#{chunk_size}}/m)
|
21
|
+
# NOTE: to be accurate, chunk_size needs to be variable, or at least increase in a giant burst at the end
|
22
|
+
#
|
23
|
+
|
24
|
+
offset = 0
|
25
|
+
length = 0
|
26
|
+
out = []
|
27
|
+
config.chunks.times do |i|
|
28
|
+
length = ((config.response_body.size - out.join.size) / (config.chunks - i).to_f).floor
|
29
|
+
out << config.response_body[offset..(offset+length)]
|
30
|
+
offset += length + 1
|
31
|
+
end
|
32
|
+
out
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
def response_headers
|
37
|
+
[].tap do |h|
|
38
|
+
h << "HTTP/1.1 200 OK"
|
39
|
+
h << "Content-Type: text/plain"
|
40
|
+
h << "Content-Length: #{config.response_body.size}"
|
41
|
+
h << "Connection: close"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def get_request(socket)
|
46
|
+
STDERR.puts socket.gets
|
47
|
+
STDERR.puts "Waiting for #{config.response_delay} seconds"
|
48
|
+
end
|
49
|
+
|
50
|
+
def send_response(socket)
|
51
|
+
STDERR.puts "Sending response headers"
|
52
|
+
socket.print response_headers.join("\n")
|
53
|
+
socket.print "\r\n\r\n"
|
54
|
+
chunks.each do |chunk|
|
55
|
+
STDERR.puts "Sending #{chunk_size} bytes"
|
56
|
+
socket.print chunk
|
57
|
+
STDERR.puts "Waiting for #{config.chunk_delay} seconds"
|
58
|
+
sleep config.chunk_delay
|
59
|
+
end
|
20
60
|
end
|
21
61
|
|
22
62
|
def start
|
23
63
|
loop do
|
24
64
|
Thread.start(server.accept) do |socket|
|
65
|
+
STDERR.puts "Accepted Connection"
|
66
|
+
# NOTE: consider putting a delay in here too
|
67
|
+
get_request(socket)
|
25
68
|
|
26
|
-
STDERR.puts socket.gets
|
27
|
-
STDERR.puts "Waiting for #{config.response_delay} seconds"
|
28
69
|
sleep config.response_delay
|
29
70
|
|
30
|
-
|
31
|
-
|
32
|
-
socket.print "HTTP/1.1 200 OK\r\n" +
|
33
|
-
"Content-Type: text/plain\r\n" +
|
34
|
-
"Content-Length: #{config.response.bytesize}\r\n" +
|
35
|
-
"Connection: close\r\n\r\n"
|
36
|
-
|
37
|
-
chunks.each do |chunk|
|
38
|
-
STDERR.puts "Sending #{chunk_size} bytes"
|
39
|
-
socket.print chunk
|
40
|
-
STDERR.puts "Waiting for #{config.chunk_delay} seconds"
|
41
|
-
sleep config.chunk_delay
|
42
|
-
end
|
43
|
-
|
71
|
+
send_response(socket)
|
72
|
+
STDERR.print "\n"
|
44
73
|
socket.close
|
45
74
|
end
|
46
75
|
end
|
data/lib/slow_server/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: slow_server
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jason Scholl
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-10-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|