forward-proxy 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|