forward-proxy 0.3.0 → 0.4.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/lib/forward_proxy/server.rb +46 -16
- data/lib/forward_proxy/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1d2b9dbd7abcfa81bcdbd29b6dd2045e6d2210e92b303f7cfcdc4ab35ab0b868
|
4
|
+
data.tar.gz: 729d4b7d964c8a5a3bec860f6bceb669a12225900a01b4737de8fdf6ba02a049
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70c0b51f0313e4ffedd1146ae93035db45bc8fe3a7cee647ea11cb0397d6862e99047befbc39aee6a08b17fd1e3d16394eb59ad9ad092140ea9354da10feadf6
|
7
|
+
data.tar.gz: b0f3587f3c08b255be222f8f59530e19b5fcc6e589f93eafb1eaa21fac832a0f01847dfcf309ed443e51fdafd96a516241143c1a75795b3d09f0ce7088eedac0
|
data/lib/forward_proxy/server.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'logger'
|
1
2
|
require 'socket'
|
2
3
|
require 'webrick'
|
3
4
|
require 'net/http'
|
@@ -7,9 +8,10 @@ require 'forward_proxy/thread_pool'
|
|
7
8
|
|
8
9
|
module ForwardProxy
|
9
10
|
class Server
|
10
|
-
attr_reader :bind_address, :bind_port
|
11
|
+
attr_reader :bind_address, :bind_port, :logger
|
11
12
|
|
12
|
-
def initialize(bind_address: "127.0.0.1", bind_port: 9292, threads: 32)
|
13
|
+
def initialize(bind_address: "127.0.0.1", bind_port: 9292, threads: 32, logger: Logger.new(STDOUT, level: :info))
|
14
|
+
@logger = logger
|
13
15
|
@thread_pool = ThreadPool.new(threads)
|
14
16
|
@bind_address = bind_address
|
15
17
|
@bind_port = bind_port
|
@@ -20,14 +22,14 @@ module ForwardProxy
|
|
20
22
|
|
21
23
|
@socket = TCPServer.new(bind_address, bind_port)
|
22
24
|
|
23
|
-
|
25
|
+
logger.info("Listening #{bind_address}:#{bind_port}")
|
24
26
|
|
25
27
|
loop do
|
26
28
|
thread_pool.schedule(socket.accept) do |client_conn|
|
27
29
|
begin
|
28
30
|
req = parse_req(client_conn)
|
29
31
|
|
30
|
-
|
32
|
+
logger.info(req.request_line)
|
31
33
|
|
32
34
|
case req.request_method
|
33
35
|
when METHOD_CONNECT then handle_tunnel(client_conn, req)
|
@@ -45,12 +47,12 @@ module ForwardProxy
|
|
45
47
|
rescue Interrupt
|
46
48
|
shutdown
|
47
49
|
rescue IOError, Errno::EBADF => e
|
48
|
-
|
50
|
+
logger.error(e.message)
|
49
51
|
end
|
50
52
|
|
51
53
|
def shutdown
|
52
54
|
if socket
|
53
|
-
|
55
|
+
logger.info("Shutting down")
|
54
56
|
|
55
57
|
socket.close
|
56
58
|
end
|
@@ -60,10 +62,18 @@ module ForwardProxy
|
|
60
62
|
|
61
63
|
attr_reader :socket, :thread_pool
|
62
64
|
|
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
|
+
|
63
69
|
METHOD_CONNECT = "CONNECT"
|
64
70
|
METHOD_GET = "GET"
|
65
71
|
METHOD_POST = "POST"
|
66
72
|
|
73
|
+
# HTTP/1.1 defines the sequence CR LF as the end-of-line marker for all
|
74
|
+
# protocol elements except the entity-body.
|
75
|
+
HEADER_EOP = "\r\n"
|
76
|
+
|
67
77
|
# The following comments are from the IETF document
|
68
78
|
# "Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content"
|
69
79
|
# https://tools.ietf.org/html/rfc7231#section-4.3.6
|
@@ -96,7 +106,10 @@ module ForwardProxy
|
|
96
106
|
# blank line that concludes the successful response's header section;
|
97
107
|
# data received after that blank line is from the server identified by
|
98
108
|
# the request-target.
|
99
|
-
client_conn.write
|
109
|
+
client_conn.write <<~eos.chomp
|
110
|
+
HTTP/1.1 200 OK
|
111
|
+
#{HEADER_EOP}
|
112
|
+
eos
|
100
113
|
|
101
114
|
# The CONNECT method requests that the recipient establish a tunnel to
|
102
115
|
# the destination origin server identified by the request-target and,
|
@@ -113,11 +126,30 @@ module ForwardProxy
|
|
113
126
|
def handle(client_conn, req)
|
114
127
|
Net::HTTP.start(req.host, req.port) do |http|
|
115
128
|
http.request(map_webrick_to_net_http_req(req)) do |resp|
|
116
|
-
|
129
|
+
# The following comments are from the IETF document
|
130
|
+
# "Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content"
|
131
|
+
# https://tools.ietf.org/html/rfc7231#section-4.3.6
|
132
|
+
|
133
|
+
# An intermediary MAY combine an ordered subsequence of Via header
|
134
|
+
# field entries into a single such entry if the entries have identical
|
135
|
+
# received-protocol values. For example,
|
136
|
+
#
|
137
|
+
# Via: 1.0 ricky, 1.1 ethel, 1.1 fred, 1.0 lucy
|
138
|
+
#
|
139
|
+
# could be collapsed to
|
140
|
+
#
|
141
|
+
# Via: 1.0 ricky, 1.1 mertz, 1.0 lucy
|
142
|
+
#
|
143
|
+
# A sender SHOULD NOT combine multiple entries unless they are all
|
144
|
+
# under the same organizational control and the hosts have already been
|
145
|
+
# replaced by pseudonyms. A sender MUST NOT combine entries that have
|
146
|
+
# different received-protocol values.
|
147
|
+
headers = resp.to_hash.merge(Via: [HEADER_VIA, resp['Via']].compact.join(', '))
|
117
148
|
|
118
149
|
client_conn.puts <<~eos.chomp
|
119
150
|
HTTP/1.1 #{resp.code}
|
120
|
-
#{headers.map { |header, value| "#{header}: #{value}" }.join("\n")}
|
151
|
+
#{headers.map { |header, value| "#{header}: #{value}" }.join("\n")}
|
152
|
+
#{HEADER_EOP}
|
121
153
|
eos
|
122
154
|
|
123
155
|
# The following comments are taken from:
|
@@ -137,10 +169,12 @@ module ForwardProxy
|
|
137
169
|
client_conn.puts <<~eos.chomp
|
138
170
|
HTTP/1.1 502
|
139
171
|
Via: #{HEADER_VIA}
|
172
|
+
#{HEADER_EOP}
|
140
173
|
eos
|
141
174
|
|
142
|
-
|
143
|
-
|
175
|
+
logger.error(err.message)
|
176
|
+
|
177
|
+
logger.debug(err.backtrace.join("\n"))
|
144
178
|
end
|
145
179
|
|
146
180
|
def map_webrick_to_net_http_req(req)
|
@@ -159,7 +193,7 @@ module ForwardProxy
|
|
159
193
|
def transfer(src_conn, dest_conn)
|
160
194
|
IO.copy_stream(src_conn, dest_conn)
|
161
195
|
rescue => e
|
162
|
-
|
196
|
+
logger.warn(e.message)
|
163
197
|
end
|
164
198
|
|
165
199
|
def parse_req(client_conn)
|
@@ -169,9 +203,5 @@ module ForwardProxy
|
|
169
203
|
rescue => e
|
170
204
|
throw Errors::HTTPParseError.new(e.message)
|
171
205
|
end
|
172
|
-
|
173
|
-
def log(str, level = 'INFO')
|
174
|
-
puts "[#{Time.now}] #{level} #{str}"
|
175
|
-
end
|
176
206
|
end
|
177
207
|
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.4.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-
|
11
|
+
date: 2021-07-04 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Forward proxy using just Ruby standard libraries.
|
14
14
|
email:
|