forward-proxy 0.4.0 → 0.6.2
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/.github/workflows/ci.yaml +1 -1
- data/.github/workflows/cli.yaml +1 -1
- data/CHANGELOG.md +10 -0
- data/README.md +4 -3
- data/exe/forward-proxy +7 -1
- data/lib/forward_proxy/errors/connection_timeout_error.rb +5 -0
- data/lib/forward_proxy/server.rb +41 -27
- data/lib/forward_proxy/thread_pool.rb +7 -18
- data/lib/forward_proxy/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a1fe517be17887550c0afe7d8ad757227d79667083ad5530aa714a8e0b2398be
|
4
|
+
data.tar.gz: 574b65e5fd8bf6e324f0657f8bfc87342481c5f177c87f1e9f2cffe49953db17
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 34d36e4bfc21abaf59a75ecec4fa86b5d9157beb5e7f7437201f15689f584fb92076f6db5095929d52062b6c543a53d65bc81393bc5013204206d8f2c041c4d2
|
7
|
+
data.tar.gz: 4e7c99b2485929fe9fb93da86256bd642ff56f8f93207b3cdd0eccc6606d4c6f53d64514adbf550831062185390ae5b1327619bfa26dcd2631ca817acab6c36d
|
data/.github/workflows/ci.yaml
CHANGED
data/.github/workflows/cli.yaml
CHANGED
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
@@ -6,8 +6,8 @@ Minimal forward proxy using 150LOC and only standard libraries. Useful for devel
|
|
6
6
|
|
7
7
|
```
|
8
8
|
$ forward-proxy --binding 0.0.0.0 --port 3182 --threads 2
|
9
|
-
[2021-
|
10
|
-
[2021-
|
9
|
+
I, [2021-07-04T10:33:32.947653 #1790] INFO -- : Listening 0.0.0.0:3182
|
10
|
+
I, [2021-07-04T10:33:32.998298 #1790] INFO -- : CONNECT raw.githubusercontent.com:443 HTTP/1.1
|
11
11
|
```
|
12
12
|
|
13
13
|
## Installation
|
@@ -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, --
|
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,13 @@ OptionParser.new do |parser|
|
|
15
15
|
options[:bind_address] = bind_address
|
16
16
|
end
|
17
17
|
|
18
|
-
parser.on("-
|
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,
|
24
|
+
"Specify the number of client threads. Default: 128") do |threads|
|
19
25
|
options[:threads] = threads
|
20
26
|
end
|
21
27
|
|
data/lib/forward_proxy/server.rb
CHANGED
@@ -1,20 +1,23 @@
|
|
1
1
|
require 'logger'
|
2
2
|
require 'socket'
|
3
|
-
require '
|
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:
|
14
|
-
@logger = logger
|
15
|
-
@thread_pool = ThreadPool.new(threads)
|
15
|
+
def initialize(bind_address: "127.0.0.1", bind_port: 9292, threads: 4, timeout: 300, logger: default_logger)
|
16
16
|
@bind_address = bind_address
|
17
17
|
@bind_port = bind_port
|
18
|
+
@logger = logger
|
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
|
-
|
33
|
+
Timeout::timeout(timeout, Errors::ConnectionTimeoutError, "connection exceeded #{timeout} seconds") do
|
34
|
+
req = parse_req(client_conn)
|
31
35
|
|
32
|
-
|
36
|
+
logger.info(req.request_line.strip)
|
33
37
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
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
|
-
rescue =>
|
41
|
-
handle_error(
|
45
|
+
rescue => e
|
46
|
+
handle_error(client_conn, e)
|
42
47
|
ensure
|
43
48
|
client_conn.close
|
44
49
|
end
|
@@ -130,20 +135,20 @@ module ForwardProxy
|
|
130
135
|
# "Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content"
|
131
136
|
# https://tools.ietf.org/html/rfc7231#section-4.3.6
|
132
137
|
|
133
|
-
#
|
134
|
-
#
|
135
|
-
#
|
138
|
+
# An intermediary MAY combine an ordered subsequence of Via header
|
139
|
+
# field entries into a single such entry if the entries have identical
|
140
|
+
# received-protocol values. For example,
|
136
141
|
#
|
137
|
-
#
|
142
|
+
# Via: 1.0 ricky, 1.1 ethel, 1.1 fred, 1.0 lucy
|
138
143
|
#
|
139
|
-
#
|
144
|
+
# could be collapsed to
|
140
145
|
#
|
141
|
-
#
|
146
|
+
# Via: 1.0 ricky, 1.1 mertz, 1.0 lucy
|
142
147
|
#
|
143
|
-
#
|
144
|
-
#
|
145
|
-
#
|
146
|
-
#
|
148
|
+
# A sender SHOULD NOT combine multiple entries unless they are all
|
149
|
+
# under the same organizational control and the hosts have already been
|
150
|
+
# replaced by pseudonyms. A sender MUST NOT combine entries that have
|
151
|
+
# different received-protocol values.
|
147
152
|
headers = resp.to_hash.merge(Via: [HEADER_VIA, resp['Via']].compact.join(', '))
|
148
153
|
|
149
154
|
client_conn.puts <<~eos.chomp
|
@@ -165,18 +170,27 @@ module ForwardProxy
|
|
165
170
|
end
|
166
171
|
end
|
167
172
|
|
168
|
-
def handle_error(
|
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
|
181
|
+
HTTP/1.1 #{status_code}
|
171
182
|
Via: #{HEADER_VIA}
|
172
183
|
#{HEADER_EOP}
|
173
184
|
eos
|
174
185
|
|
175
186
|
logger.error(err.message)
|
176
|
-
|
177
187
|
logger.debug(err.backtrace.join("\n"))
|
178
188
|
end
|
179
189
|
|
190
|
+
def default_logger
|
191
|
+
Logger.new(STDOUT, level: :info)
|
192
|
+
end
|
193
|
+
|
180
194
|
def map_webrick_to_net_http_req(req)
|
181
195
|
req_headers = Hash[req.header.map { |k, v| [k, v.first] }]
|
182
196
|
|
@@ -1,21 +1,18 @@
|
|
1
1
|
module ForwardProxy
|
2
2
|
class ThreadPool
|
3
|
-
attr_reader :queue, :
|
3
|
+
attr_reader :queue, :size
|
4
4
|
|
5
5
|
def initialize(size)
|
6
|
-
@size
|
7
|
-
@queue
|
8
|
-
@threads = []
|
6
|
+
@size = size
|
7
|
+
@queue = Queue.new
|
9
8
|
end
|
10
9
|
|
11
10
|
def start
|
12
11
|
size.times do
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
job.call(*args)
|
18
|
-
end
|
12
|
+
Thread.new do
|
13
|
+
loop do
|
14
|
+
job, args = queue.pop
|
15
|
+
job.call(*args)
|
19
16
|
end
|
20
17
|
end
|
21
18
|
end
|
@@ -24,13 +21,5 @@ module ForwardProxy
|
|
24
21
|
def schedule(*args, &block)
|
25
22
|
queue.push([block, args])
|
26
23
|
end
|
27
|
-
|
28
|
-
def shutdown
|
29
|
-
threads.each do
|
30
|
-
schedule { throw :exit }
|
31
|
-
end
|
32
|
-
|
33
|
-
threads.each(&:join)
|
34
|
-
end
|
35
24
|
end
|
36
25
|
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.
|
4
|
+
version: 0.6.2
|
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-
|
11
|
+
date: 2021-07-17 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
|