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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a2f3ade2ec039aaadb19726b347d6cddb7db0f2590b91ab5d6eb69b8fd5c0aee
4
- data.tar.gz: 0733602e8b7bab9e95df20cff04bc11981964260db17242460a2c26341a9032b
3
+ metadata.gz: 1d2b9dbd7abcfa81bcdbd29b6dd2045e6d2210e92b303f7cfcdc4ab35ab0b868
4
+ data.tar.gz: 729d4b7d964c8a5a3bec860f6bceb669a12225900a01b4737de8fdf6ba02a049
5
5
  SHA512:
6
- metadata.gz: 9c25af1d60872d711a475028eddc06bc54ee7dd609cd3cbd1858ff667a1facb5e1cfb7ca38889ab7a8603d018a6c69e4b56ee11eaba525818f2cd0bf0a7b59c5
7
- data.tar.gz: d105d9a16183951129e62ed1b905a12e12f251541154e90869bb9a74449c10925ec19e3f3fce8d9300f7af38a00dcf6aa26e0a4f2d37ca9882a1bc64a494cba8
6
+ metadata.gz: 70c0b51f0313e4ffedd1146ae93035db45bc8fe3a7cee647ea11cb0397d6862e99047befbc39aee6a08b17fd1e3d16394eb59ad9ad092140ea9354da10feadf6
7
+ data.tar.gz: b0f3587f3c08b255be222f8f59530e19b5fcc6e589f93eafb1eaa21fac832a0f01847dfcf309ed443e51fdafd96a516241143c1a75795b3d09f0ce7088eedac0
@@ -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
- log("Listening #{bind_address}:#{bind_port}")
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
- log(req.request_line)
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
- log(e.message, "ERROR")
50
+ logger.error(e.message)
49
51
  end
50
52
 
51
53
  def shutdown
52
54
  if socket
53
- log("Shutting down")
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 "HTTP/1.1 200 OK\n\n"
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
- headers= resp.to_hash.merge(Via: [HEADER_VIA, resp['Via']].compact.join(', '))
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")}\n\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
- log(err.message, "ERROR")
143
- puts err.backtrace.map { |line| " #{line}" }
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
- log(e.message, "WARNING")
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
@@ -1,3 +1,3 @@
1
1
  module ForwardProxy
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.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.3.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-06-27 00:00:00.000000000 Z
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: