slow_server 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ea6a54afb4bf9a70253d27ce0acff0b0dd5178fa
4
- data.tar.gz: 3718dcc9e924ab3d5788a0af1fef4564f5ab94aa
3
+ metadata.gz: 7e993e4056d8bcf3c4f2aad4e5a826a9ff13a27f
4
+ data.tar.gz: 2ffe6af0c24b470cb1dd1d462dbacc5e3405c48b
5
5
  SHA512:
6
- metadata.gz: 54def5b25784072b04d30b44f01dd53c3fcfa785b4b816004591a6b905d3e7426d3bffde040c50c8425d8bfba840dcdccfecfd048f1567b9d8ecda261324e7ed
7
- data.tar.gz: 56e4395d19cd46f95754d6be0df4a03206e3284280f58bb0d64797f413cf41c8bbdc92bbce1406edbaeac293d58cc898c8475f42a8fccf176dd72135a4b57cd1
6
+ metadata.gz: cc65204f942fa8d813b831688f247f59371baa37de6cb593a4ba8d4cdee5f8100d47d3b8b92a2eba003e93086c40613cdd1a7f04534da9b8b3bef1d31dca1128
7
+ data.tar.gz: 9ffdf2608647676aec94d9172cae6a0c720cd89551b771fb65675288b25c502a65cd1c925585e14f1234ce31df1f8fa1547797cc2af101aff967707a02ef1fc1
data/README.md CHANGED
@@ -1,28 +1,53 @@
1
1
  # SlowServer
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/slow_server`. To experiment with that code, run `bin/console` for an interactive prompt.
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
- TODO: Delete this and the text above, and describe your gem
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
- Add this line to your application's Gemfile:
19
+ $ gem install slow_server
10
20
 
11
- ```ruby
12
- gem 'slow_server'
13
- ```
21
+ ## Usage
14
22
 
15
- And then execute:
23
+ ###slow_client
16
24
 
17
- $ bundle
25
+ slow_client is somewhat similar to slowloris, it has tunable delays for various different phases of connection.
18
26
 
19
- Or install it yourself as:
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
- $ gem install slow_server
38
+ ###slow_server
22
39
 
23
- ## Usage
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
- TODO: Write usage instructions here
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/[USERNAME]/slow_server.
60
+ Bug reports and pull requests are welcome on GitHub at https://github.com/jscholl/slow_server.
36
61
 
37
62
 
38
63
  ## License
@@ -2,6 +2,6 @@
2
2
  require 'slow_server'
3
3
 
4
4
  catch :exit do
5
- SlowServer.config.parse_opts
6
- SlowServer::Client.new().start
5
+ SlowServer.client.config.parse
6
+ SlowServer.client.start
7
7
  end
@@ -2,6 +2,6 @@
2
2
  require 'slow_server'
3
3
 
4
4
  catch :exit do
5
- SlowServer.config.parse_opts
6
- SlowServer::Server.new().start
5
+ SlowServer.server.config.parse
6
+ SlowServer.server.start
7
7
  end
@@ -6,17 +6,12 @@ require "slow_server/config"
6
6
  module SlowServer
7
7
  class << self
8
8
 
9
- def config
10
- @config ||= Config.new
9
+ def server
10
+ @server ||= Server.new
11
11
  end
12
12
 
13
- def configure
14
- yield config
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
@@ -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
- SlowServer.config
8
+ @config ||= ClientConfig.new
8
9
  end
9
10
 
10
11
  def chunk_size
11
- (request.size / config.chunks.to_f).ceil
12
+ (request_body.size / config.chunks.to_f).round
12
13
  end
13
14
 
14
15
  def chunks
15
- request.scan(/.{1,#{chunk_size}}/m)
16
+ request_body.scan(/.{1,#{chunk_size}}/m)
16
17
  end
17
18
 
18
- def request
19
- "GET /"
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("127.0.0.1", 4000) do |socket|
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
- 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
-
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
 
@@ -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 :response, :port, :chunks, :response_delay, :chunk_delay
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 (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("-r", "--response-delay SECONDS", Integer, "Response 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 }
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 parse_opts
28
- response = opts.parse!.join(" ")
29
- self.response = response unless response.empty?
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
@@ -4,7 +4,7 @@ module SlowServer
4
4
  class Server
5
5
 
6
6
  def config
7
- SlowServer.config
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.response.size / config.chunks
15
+ (config.response_body.size / config.chunks.to_f).round
16
16
  end
17
17
 
18
+
18
19
  def chunks
19
- config.response.scan(/.{1,#{chunk_size}}/m)
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
- STDERR.puts "Sending response headers"
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
@@ -1,3 +1,3 @@
1
1
  module SlowServer
2
- VERSION = "0.1.2"
2
+ VERSION = "0.1.3"
3
3
  end
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.2
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-06-06 00:00:00.000000000 Z
11
+ date: 2016-10-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler