forward-proxy 0.5.0 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ccf19df114eeec55eaef8765999561904d8f5b6cd91b7ed2016053ec9e717408
4
- data.tar.gz: ce712f520c0ed32b93ea211ff658d330bef7eeb26c2ddfcea1246d955ce78175
3
+ metadata.gz: 3018291ebebbfa87a02ba1409fa3f0c0af9b5d0ffb8917636dd4f8e397d8a4fb
4
+ data.tar.gz: dd3420d19ee1ac89064d7fd965768072cc25ce100555a4dc59881530fc2b6d66
5
5
  SHA512:
6
- metadata.gz: b71608455b079161950b09521d8fd99496767463f3e2aa0f0d293f21e3955b03d7b0ba12f06f3b3df1ff6674d598ed2e7eec7492ffb8fd9047ebb19771625251
7
- data.tar.gz: '092035474f162e29d2c7d0735b43cd38e41580aadca7ae50e97e02dee8e6f3825f50393497c0a8db8a5e0b3622d3e44e25e69e03ae02b56eba1cad55abdc1388'
6
+ metadata.gz: c1676662f33627745b09c2049957a4232885862bac77ba4f1ecb48b085683ef832825d2a0b15c725bdf6553456bb710c1b847f4027e55e8ed31c1c31aa1b307f
7
+ data.tar.gz: '08652da6a675acfb0c371d571bad140d3a50673d76d2aae74ea6a33f2b4f1e21b07f3378fcaaf74099d6fe93de29cc923108c1d278a9364b885b80a405951643'
@@ -8,7 +8,7 @@ jobs:
8
8
 
9
9
  strategy:
10
10
  matrix:
11
- ruby: [ '2.3', '2.7' ]
11
+ ruby: [ '2.5', '2.7' ]
12
12
 
13
13
  steps:
14
14
  - uses: actions/checkout@v2
@@ -8,7 +8,7 @@ jobs:
8
8
 
9
9
  strategy:
10
10
  matrix:
11
- ruby: [ '2.3', '2.7' ]
11
+ ruby: [ '2.5', '2.7' ]
12
12
 
13
13
  steps:
14
14
  - uses: actions/checkout@v2
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 0.6.0
4
+
5
+ - add connection timeout to stop tracking connection from saturating client threads.
6
+ - add cli flats for connection timeout `-t` and `--timeout`.
7
+ - change cli short flag `-t` to `-c` for `--threads`.
8
+
9
+ ## 0.5.0
10
+
11
+ - increase default threads from `32` to `128`.
12
+
3
13
  ## 0.2.0
4
14
 
5
15
  - Extract errors into module.
data/README.md CHANGED
@@ -38,7 +38,8 @@ forward-proxy
38
38
  Usage: forward-proxy [options]
39
39
  -p, --port=PORT Bind to specified port. Default: 9292
40
40
  -b, --binding=BINDING Bind to the specified ip. Default: 127.0.0.1
41
- -t, --threads=THREADS Specify the number of client threads. Default: 32
41
+ -t, --timeout=TIMEOUT Specify the connection timeout in seconds. Default: 300
42
+ -c, --threads=THREADS Specify the number of client threads. Default: 128
42
43
  -h, --help Prints this help.
43
44
  ```
44
45
 
data/exe/forward-proxy CHANGED
@@ -15,7 +15,12 @@ OptionParser.new do |parser|
15
15
  options[:bind_address] = bind_address
16
16
  end
17
17
 
18
- parser.on("-tTHREADS", "--threads=THREADS", Integer,
18
+ parser.on("-tTIMEOUT", "--timeout=TIMEOUT", Integer,
19
+ "Specify the connection timeout in seconds. Default: 300") do |threads|
20
+ options[:timeout] = threads
21
+ end
22
+
23
+ parser.on("-cTHREADS", "--threads=THREADS", Integer,
19
24
  "Specify the number of client threads. Default: 128") do |threads|
20
25
  options[:threads] = threads
21
26
  end
@@ -0,0 +1,5 @@
1
+ module ForwardProxy
2
+ module Errors
3
+ class ConnectionTimeoutError < StandardError; end
4
+ end
5
+ end
@@ -1,20 +1,23 @@
1
1
  require 'logger'
2
2
  require 'socket'
3
- require 'webrick'
3
+ require 'timeout'
4
4
  require 'net/http'
5
+ require 'webrick'
6
+ require 'forward_proxy/errors/connection_timeout_error'
5
7
  require 'forward_proxy/errors/http_method_not_implemented'
6
8
  require 'forward_proxy/errors/http_parse_error'
7
9
  require 'forward_proxy/thread_pool'
8
10
 
9
11
  module ForwardProxy
10
12
  class Server
11
- attr_reader :bind_address, :bind_port, :logger
13
+ attr_reader :bind_address, :bind_port, :logger, :timeout
12
14
 
13
- def initialize(bind_address: "127.0.0.1", bind_port: 9292, threads: 128, logger: default_logger)
15
+ def initialize(bind_address: "127.0.0.1", bind_port: 9292, threads: 128, timeout: 300, logger: default_logger)
14
16
  @bind_address = bind_address
15
17
  @bind_port = bind_port
16
18
  @logger = logger
17
19
  @thread_pool = ThreadPool.new(threads)
20
+ @timeout = timeout
18
21
  end
19
22
 
20
23
  def start
@@ -27,18 +30,20 @@ module ForwardProxy
27
30
  loop do
28
31
  thread_pool.schedule(socket.accept) do |client_conn|
29
32
  begin
30
- req = parse_req(client_conn)
33
+ Timeout::timeout(timeout, Errors::ConnectionTimeoutError, "connection exceeded #{timeout} seconds") do
34
+ req = parse_req(client_conn)
31
35
 
32
- logger.info(req.request_line.strip)
36
+ logger.info(req.request_line.strip)
33
37
 
34
- case req.request_method
35
- when METHOD_CONNECT then handle_tunnel(client_conn, req)
36
- when METHOD_GET, METHOD_POST then handle(client_conn, req)
37
- else
38
- raise Errors::HTTPMethodNotImplemented
38
+ case req.request_method
39
+ when METHOD_CONNECT then handle_tunnel(client_conn, req)
40
+ when METHOD_GET, METHOD_POST then handle(client_conn, req)
41
+ else
42
+ raise Errors::HTTPMethodNotImplemented
43
+ end
39
44
  end
40
45
  rescue => e
41
- handle_error(e, client_conn)
46
+ handle_error(client_conn, e)
42
47
  ensure
43
48
  client_conn.close
44
49
  end
@@ -62,14 +67,14 @@ module ForwardProxy
62
67
 
63
68
  attr_reader :socket, :thread_pool
64
69
 
65
- # The following comments are from the IETF document
66
- # "Hypertext Transfer Protocol -- HTTP/1.1: Basic Rules"
67
- # https://datatracker.ietf.org/doc/html/rfc2616#section-2.2
68
-
69
70
  METHOD_CONNECT = "CONNECT"
70
71
  METHOD_GET = "GET"
71
72
  METHOD_POST = "POST"
72
73
 
74
+ # The following comments are from the IETF document
75
+ # "Hypertext Transfer Protocol -- HTTP/1.1: Basic Rules"
76
+ # https://datatracker.ietf.org/doc/html/rfc2616#section-2.2
77
+
73
78
  # HTTP/1.1 defines the sequence CR LF as the end-of-line marker for all
74
79
  # protocol elements except the entity-body.
75
80
  HEADER_EOP = "\r\n"
@@ -165,9 +170,15 @@ module ForwardProxy
165
170
  end
166
171
  end
167
172
 
168
- def handle_error(err, client_conn)
173
+ def handle_error(client_conn, err)
174
+ status_code = case err
175
+ when Errors::ConnectionTimeoutError then 504
176
+ else
177
+ 502
178
+ end
179
+
169
180
  client_conn.puts <<~eos.chomp
170
- HTTP/1.1 502
181
+ HTTP/1.1 #{status_code}
171
182
  Via: #{HEADER_VIA}
172
183
  #{HEADER_EOP}
173
184
  eos
@@ -1,24 +1,29 @@
1
1
  module ForwardProxy
2
2
  class ThreadPool
3
- attr_reader :queue, :size
3
+ attr_reader :queue, :size, :threads
4
4
 
5
5
  def initialize(size)
6
- @size = size
7
- @queue = Queue.new
6
+ @queue = Queue.new
7
+ @size = size
8
+ @threads = []
8
9
  end
9
10
 
10
11
  def start
11
12
  size.times do
12
- Thread.new do
13
+ thread = Thread.new do
13
14
  loop do
14
15
  job, args = queue.pop
15
16
  job.call(*args)
16
17
  end
17
18
  end
19
+
20
+ threads.push(thread)
18
21
  end
19
22
  end
20
23
 
21
24
  def schedule(*args, &block)
25
+ raise Exception, "no threads" unless threads.any?(&:alive?)
26
+
22
27
  queue.push([block, args])
23
28
  end
24
29
  end
@@ -1,3 +1,3 @@
1
1
  module ForwardProxy
2
- VERSION = "0.5.0"
2
+ VERSION = "0.7.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: forward-proxy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Moriarty
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-07-13 00:00:00.000000000 Z
11
+ date: 2021-07-23 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Forward proxy using just Ruby standard libraries.
14
14
  email:
@@ -32,6 +32,7 @@ files:
32
32
  - exe/forward-proxy
33
33
  - forward-proxy.gemspec
34
34
  - lib/forward_proxy.rb
35
+ - lib/forward_proxy/errors/connection_timeout_error.rb
35
36
  - lib/forward_proxy/errors/http_method_not_implemented.rb
36
37
  - lib/forward_proxy/errors/http_parse_error.rb
37
38
  - lib/forward_proxy/server.rb