em-http-request-samesite 1.1.7
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 +7 -0
- data/.gemtest +0 -0
- data/.gitignore +9 -0
- data/.rspec +0 -0
- data/.travis.yml +7 -0
- data/Changelog.md +68 -0
- data/Gemfile +14 -0
- data/README.md +63 -0
- data/Rakefile +10 -0
- data/benchmarks/clients.rb +170 -0
- data/benchmarks/em-excon.rb +87 -0
- data/benchmarks/em-profile.gif +0 -0
- data/benchmarks/em-profile.txt +65 -0
- data/benchmarks/server.rb +48 -0
- data/em-http-request.gemspec +32 -0
- data/examples/.gitignore +1 -0
- data/examples/digest_auth/client.rb +25 -0
- data/examples/digest_auth/server.rb +28 -0
- data/examples/fetch.rb +30 -0
- data/examples/fibered-http.rb +51 -0
- data/examples/multi.rb +25 -0
- data/examples/oauth-tweet.rb +35 -0
- data/examples/socks5.rb +23 -0
- data/lib/em-http-request.rb +1 -0
- data/lib/em-http.rb +20 -0
- data/lib/em-http/client.rb +341 -0
- data/lib/em-http/core_ext/bytesize.rb +6 -0
- data/lib/em-http/decoders.rb +252 -0
- data/lib/em-http/http_client_options.rb +49 -0
- data/lib/em-http/http_connection.rb +321 -0
- data/lib/em-http/http_connection_options.rb +70 -0
- data/lib/em-http/http_encoding.rb +149 -0
- data/lib/em-http/http_header.rb +83 -0
- data/lib/em-http/http_status_codes.rb +57 -0
- data/lib/em-http/middleware/digest_auth.rb +112 -0
- data/lib/em-http/middleware/json_response.rb +15 -0
- data/lib/em-http/middleware/oauth.rb +40 -0
- data/lib/em-http/middleware/oauth2.rb +28 -0
- data/lib/em-http/multi.rb +57 -0
- data/lib/em-http/request.rb +23 -0
- data/lib/em-http/version.rb +5 -0
- data/lib/em/io_streamer.rb +49 -0
- data/spec/client_fiber_spec.rb +23 -0
- data/spec/client_spec.rb +1000 -0
- data/spec/digest_auth_spec.rb +48 -0
- data/spec/dns_spec.rb +41 -0
- data/spec/encoding_spec.rb +49 -0
- data/spec/external_spec.rb +150 -0
- data/spec/fixtures/google.ca +16 -0
- data/spec/fixtures/gzip-sample.gz +0 -0
- data/spec/gzip_spec.rb +91 -0
- data/spec/helper.rb +31 -0
- data/spec/http_proxy_spec.rb +268 -0
- data/spec/middleware/oauth2_spec.rb +15 -0
- data/spec/middleware_spec.rb +143 -0
- data/spec/multi_spec.rb +104 -0
- data/spec/pipelining_spec.rb +66 -0
- data/spec/redirect_spec.rb +430 -0
- data/spec/socksify_proxy_spec.rb +60 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/ssl_spec.rb +71 -0
- data/spec/stallion.rb +334 -0
- data/spec/stub_server.rb +45 -0
- metadata +265 -0
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
requires_connection do
|
4
|
+
|
5
|
+
requires_port(8080) do
|
6
|
+
describe EventMachine::HttpRequest do
|
7
|
+
|
8
|
+
# ssh -D 8080 igvita
|
9
|
+
let(:proxy) { {:proxy => { :host => '127.0.0.1', :port => 8080, :type => :socks5 }} }
|
10
|
+
|
11
|
+
it "should use SOCKS5 proxy" do
|
12
|
+
EventMachine.run {
|
13
|
+
http = EventMachine::HttpRequest.new('http://jsonip.com/', proxy).get
|
14
|
+
|
15
|
+
http.errback { failed(http) }
|
16
|
+
http.callback {
|
17
|
+
http.response_header.status.should == 200
|
18
|
+
http.response.should match('173.230.151.99')
|
19
|
+
EventMachine.stop
|
20
|
+
}
|
21
|
+
}
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
requires_port(8081) do
|
27
|
+
describe EventMachine::HttpRequest do
|
28
|
+
|
29
|
+
# brew install tinyproxy
|
30
|
+
let(:http_proxy) { {:proxy => { :host => '127.0.0.1', :port => 8081 }} }
|
31
|
+
|
32
|
+
it "should use HTTP proxy by default" do
|
33
|
+
EventMachine.run {
|
34
|
+
http = EventMachine::HttpRequest.new('http://jsonip.com/', http_proxy).get
|
35
|
+
|
36
|
+
http.errback { failed(http) }
|
37
|
+
http.callback {
|
38
|
+
http.response_header.status.should == 200
|
39
|
+
http.response.should match(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/)
|
40
|
+
EventMachine.stop
|
41
|
+
}
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should auto CONNECT via HTTP proxy for HTTPS requests" do
|
46
|
+
EventMachine.run {
|
47
|
+
http = EventMachine::HttpRequest.new('https://ipjson.herokuapp.com/', http_proxy).get
|
48
|
+
|
49
|
+
http.errback { failed(http) }
|
50
|
+
http.callback {
|
51
|
+
http.response_header.status.should == 200
|
52
|
+
http.response.should match(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/)
|
53
|
+
EventMachine.stop
|
54
|
+
}
|
55
|
+
}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
PROXY_ENV_VARS = %w[HTTP_PROXY http_proxy HTTPS_PROXY https_proxy ALL_PROXY]
|
2
|
+
|
3
|
+
RSpec.configure do |config|
|
4
|
+
proxy_envs = {}
|
5
|
+
|
6
|
+
config.mock_with :rspec do |c|
|
7
|
+
c.syntax = [:should, :expect]
|
8
|
+
end
|
9
|
+
config.expect_with :rspec do |c|
|
10
|
+
c.syntax = [:should, :expect]
|
11
|
+
end
|
12
|
+
|
13
|
+
config.before :all do
|
14
|
+
# Back-up ENV *_PROXY vars
|
15
|
+
orig_proxy_envs = Hash[
|
16
|
+
PROXY_ENV_VARS.select {|k| ENV.key? k }.map {|k| [k, ENV.delete(k)] }
|
17
|
+
]
|
18
|
+
proxy_envs.replace(orig_proxy_envs)
|
19
|
+
end
|
20
|
+
|
21
|
+
config.after :all do
|
22
|
+
# Restore ENV *_PROXY vars
|
23
|
+
ENV.update(proxy_envs)
|
24
|
+
end
|
25
|
+
end
|
data/spec/ssl_spec.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
requires_connection do
|
4
|
+
|
5
|
+
describe EventMachine::HttpRequest do
|
6
|
+
it "should initiate SSL/TLS on HTTPS connections" do
|
7
|
+
EventMachine.run {
|
8
|
+
http = EventMachine::HttpRequest.new('https://mail.google.com:443/mail/').get
|
9
|
+
|
10
|
+
http.errback { failed(http) }
|
11
|
+
http.callback {
|
12
|
+
http.response_header.status.should == 302
|
13
|
+
EventMachine.stop
|
14
|
+
}
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "TLS hostname verification" do
|
19
|
+
before do
|
20
|
+
@cve_warning = "[WARNING; em-http-request] TLS hostname validation is disabled (use 'tls: {verify_peer: true}'), see" +
|
21
|
+
" CVE-2020-13482 and https://github.com/igrigorik/em-http-request/issues/339 for details"
|
22
|
+
@orig_stderr = $stderr
|
23
|
+
$stderr = StringIO.new
|
24
|
+
end
|
25
|
+
|
26
|
+
after do
|
27
|
+
$stderr = @orig_stderr
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should not warn if verify_peer is specified" do
|
31
|
+
EventMachine.run {
|
32
|
+
http = EventMachine::HttpRequest.new('https://mail.google.com:443/mail', {tls: {verify_peer: false}}).get
|
33
|
+
|
34
|
+
http.callback {
|
35
|
+
$stderr.rewind
|
36
|
+
$stderr.string.chomp.should_not eq(@cve_warning)
|
37
|
+
|
38
|
+
EventMachine.stop
|
39
|
+
}
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should not warn if verify_peer is true" do
|
44
|
+
EventMachine.run {
|
45
|
+
http = EventMachine::HttpRequest.new('https://mail.google.com:443/mail', {tls: {verify_peer: true}}).get
|
46
|
+
|
47
|
+
http.callback {
|
48
|
+
$stderr.rewind
|
49
|
+
$stderr.string.chomp.should_not eq(@cve_warning)
|
50
|
+
|
51
|
+
EventMachine.stop
|
52
|
+
}
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should warn if verify_peer is unspecified" do
|
57
|
+
EventMachine.run {
|
58
|
+
http = EventMachine::HttpRequest.new('https://mail.google.com:443/mail').get
|
59
|
+
|
60
|
+
http.callback {
|
61
|
+
$stderr.rewind
|
62
|
+
$stderr.string.chomp.should eq(@cve_warning)
|
63
|
+
|
64
|
+
EventMachine.stop
|
65
|
+
}
|
66
|
+
}
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
data/spec/stallion.rb
ADDED
@@ -0,0 +1,334 @@
|
|
1
|
+
# #--
|
2
|
+
# Includes portion originally Copyright (C)2008 Michael Fellinger
|
3
|
+
# MIT License
|
4
|
+
# #--
|
5
|
+
|
6
|
+
require 'rack'
|
7
|
+
|
8
|
+
module Stallion
|
9
|
+
class Mount
|
10
|
+
def initialize(name, *methods, &block)
|
11
|
+
@name, @methods, @block = name, methods, block
|
12
|
+
end
|
13
|
+
|
14
|
+
def ride
|
15
|
+
@block.call
|
16
|
+
end
|
17
|
+
|
18
|
+
def match?(request)
|
19
|
+
method = request['REQUEST_METHOD']
|
20
|
+
@methods.empty? or @methods.include?(method)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Stable
|
25
|
+
attr_reader :request, :response
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
@boxes = {}
|
29
|
+
end
|
30
|
+
|
31
|
+
def in(path, *methods, &block)
|
32
|
+
mount = Mount.new(path, *methods, &block)
|
33
|
+
@boxes[[path, methods]] = mount
|
34
|
+
mount
|
35
|
+
end
|
36
|
+
|
37
|
+
def call(request, response)
|
38
|
+
@request, @response = request, response
|
39
|
+
@boxes.each do |_, mount|
|
40
|
+
if mount.match?(request)
|
41
|
+
mount.ride
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
STABLES = {}
|
48
|
+
|
49
|
+
def self.saddle(name = nil)
|
50
|
+
STABLES[name] = stable = Stable.new
|
51
|
+
yield stable
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.run(options = {})
|
55
|
+
options = {:Host => "127.0.0.1", :Port => 8090}.merge(options)
|
56
|
+
|
57
|
+
ruby_version = RUBY_VERSION.split('.').map(&:to_i)
|
58
|
+
if ruby_version[0] >= 3
|
59
|
+
Rack::Handler::Mongrel.run(Rack::Lint.new(self), **options)
|
60
|
+
else
|
61
|
+
Rack::Handler::Mongrel.run(Rack::Lint.new(self), options)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.call(env)
|
66
|
+
request = Rack::Request.new(env)
|
67
|
+
response = Rack::Response.new
|
68
|
+
|
69
|
+
STABLES.each do |name, stable|
|
70
|
+
stable.call(request, response)
|
71
|
+
end
|
72
|
+
|
73
|
+
response.finish
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
Stallion.saddle :spec do |stable|
|
78
|
+
stable.in '/' do
|
79
|
+
|
80
|
+
if stable.request.path_info == '/fail'
|
81
|
+
stable.response.status = 404
|
82
|
+
|
83
|
+
elsif stable.request.path_info == '/fail_with_nonstandard_response'
|
84
|
+
stable.response.status = 420
|
85
|
+
|
86
|
+
elsif stable.request.query_string == 'q=test'
|
87
|
+
stable.response.write 'test'
|
88
|
+
|
89
|
+
elsif stable.request.path_info == '/echo_query'
|
90
|
+
stable.response["ETag"] = "abcdefg"
|
91
|
+
stable.response["Last-Modified"] = "Fri, 13 Aug 2010 17:31:21 GMT"
|
92
|
+
stable.response.write stable.request.query_string
|
93
|
+
|
94
|
+
elsif stable.request.path_info == '/echo_headers'
|
95
|
+
stable.response["Set-Cookie"] = "test=yes"
|
96
|
+
stable.response["X-Forward-Host"] = "proxy.local"
|
97
|
+
stable.response.write stable.request.query_string
|
98
|
+
|
99
|
+
elsif stable.request.path_info == '/echo_content_length'
|
100
|
+
stable.response.write stable.request.content_length
|
101
|
+
|
102
|
+
elsif stable.request.path_info == '/echo_content_length_from_header'
|
103
|
+
stable.response.write "content-length:#{stable.request.env["CONTENT_LENGTH"]}"
|
104
|
+
|
105
|
+
elsif stable.request.path_info == '/echo_authorization_header'
|
106
|
+
stable.response.write "authorization:#{stable.request.env["HTTP_AUTHORIZATION"]}"
|
107
|
+
|
108
|
+
elsif stable.request.head? && stable.request.path_info == '/'
|
109
|
+
stable.response.status = 200
|
110
|
+
|
111
|
+
elsif stable.request.delete?
|
112
|
+
stable.response.status = 200
|
113
|
+
|
114
|
+
elsif stable.request.put?
|
115
|
+
stable.response.write stable.request.body.read
|
116
|
+
|
117
|
+
elsif stable.request.post? || stable.request.patch?
|
118
|
+
if stable.request.path_info == '/echo_content_type'
|
119
|
+
stable.response["Content-Type"] = stable.request.env["CONTENT_TYPE"] || 'text/html'
|
120
|
+
stable.response.write stable.request.env["CONTENT_TYPE"]
|
121
|
+
else
|
122
|
+
stable.response.write stable.request.body.read
|
123
|
+
end
|
124
|
+
|
125
|
+
elsif stable.request.path_info == '/set_cookie'
|
126
|
+
stable.response["Set-Cookie"] = "id=1; expires=Sat, 09 Aug 2031 17:53:39 GMT; path=/;"
|
127
|
+
stable.response.write "cookie set"
|
128
|
+
|
129
|
+
elsif stable.request.path_info == '/set_multiple_cookies'
|
130
|
+
stable.response["Set-Cookie"] = [
|
131
|
+
"id=1; expires=Sat, 09 Aug 2031 17:53:39 GMT; path=/;",
|
132
|
+
"id=2;"
|
133
|
+
]
|
134
|
+
stable.response.write "cookies set"
|
135
|
+
|
136
|
+
elsif stable.request.path_info == '/echo_cookie'
|
137
|
+
stable.response.write stable.request.env["HTTP_COOKIE"]
|
138
|
+
|
139
|
+
elsif stable.request.path_info == '/timeout'
|
140
|
+
sleep(10)
|
141
|
+
stable.response.write 'timeout'
|
142
|
+
|
143
|
+
elsif stable.request.path_info == '/cookie_parrot'
|
144
|
+
stable.response.status = 200
|
145
|
+
stable.response["Set-Cookie"] = stable.request.env['HTTP_COOKIE']
|
146
|
+
|
147
|
+
elsif stable.request.path_info == '/redirect'
|
148
|
+
stable.response.status = 301
|
149
|
+
stable.response["Location"] = "/gzip"
|
150
|
+
stable.response.write 'redirect'
|
151
|
+
|
152
|
+
elsif stable.request.path_info == '/redirect/created'
|
153
|
+
stable.response.status = 201
|
154
|
+
stable.response["Location"] = "/"
|
155
|
+
stable.response.write 'Hello, World!'
|
156
|
+
|
157
|
+
elsif stable.request.path_info == '/redirect/multiple-with-cookie'
|
158
|
+
stable.response.status = 301
|
159
|
+
stable.response["Set-Cookie"] = "another_id=1; expires=Sat, 09 Aug 2031 17:53:39 GMT; path=/;"
|
160
|
+
stable.response["Location"] = "/redirect"
|
161
|
+
stable.response.write 'redirect'
|
162
|
+
|
163
|
+
elsif stable.request.path_info == '/redirect/bad'
|
164
|
+
stable.response.status = 301
|
165
|
+
stable.response["Location"] = "http://127.0.0.1:8090"
|
166
|
+
|
167
|
+
elsif stable.request.path_info == '/redirect/timeout'
|
168
|
+
stable.response.status = 301
|
169
|
+
stable.response["Location"] = "http://127.0.0.1:8090/timeout"
|
170
|
+
|
171
|
+
elsif stable.request.path_info == '/redirect/head'
|
172
|
+
stable.response.status = 301
|
173
|
+
stable.response["Location"] = "/"
|
174
|
+
|
175
|
+
elsif stable.request.path_info == '/redirect/middleware_redirects_1'
|
176
|
+
stable.response.status = 301
|
177
|
+
stable.response["EM-Middleware"] = stable.request.env["HTTP_EM_MIDDLEWARE"]
|
178
|
+
stable.response["Location"] = "/redirect/middleware_redirects_2"
|
179
|
+
|
180
|
+
elsif stable.request.path_info == '/redirect/middleware_redirects_2'
|
181
|
+
stable.response.status = 301
|
182
|
+
stable.response["EM-Middleware"] = stable.request.env["HTTP_EM_MIDDLEWARE"]
|
183
|
+
stable.response["Location"] = "/redirect/middleware_redirects_3"
|
184
|
+
|
185
|
+
elsif stable.request.path_info == '/redirect/middleware_redirects_3'
|
186
|
+
stable.response.status = 200
|
187
|
+
stable.response["EM-Middleware"] = stable.request.env["HTTP_EM_MIDDLEWARE"]
|
188
|
+
|
189
|
+
elsif stable.request.path_info == '/redirect/nohost'
|
190
|
+
stable.response.status = 301
|
191
|
+
stable.response["Location"] = "http:/"
|
192
|
+
|
193
|
+
elsif stable.request.path_info == '/redirect/badhost'
|
194
|
+
stable.response.status = 301
|
195
|
+
stable.response["Location"] = "http://$$$@$!%&^"
|
196
|
+
|
197
|
+
elsif stable.request.path_info == '/redirect/http_no_port'
|
198
|
+
stable.response.status = 301
|
199
|
+
stable.response["Location"] = "http://host/"
|
200
|
+
|
201
|
+
elsif stable.request.path_info == '/redirect/https_no_port'
|
202
|
+
stable.response.status = 301
|
203
|
+
stable.response["Location"] = "https://host/"
|
204
|
+
|
205
|
+
elsif stable.request.path_info == '/redirect/http_with_port'
|
206
|
+
stable.response.status = 301
|
207
|
+
stable.response["Location"] = "http://host:80/"
|
208
|
+
|
209
|
+
elsif stable.request.path_info == '/redirect/https_with_port'
|
210
|
+
stable.response.status = 301
|
211
|
+
stable.response["Location"] = "https://host:443/"
|
212
|
+
|
213
|
+
elsif stable.request.path_info == '/redirect/ignore_query_option'
|
214
|
+
stable.response.status = 301
|
215
|
+
stable.response['Location'] = '/redirect/url'
|
216
|
+
|
217
|
+
elsif stable.request.path_info == '/redirect/url'
|
218
|
+
stable.response.status = 200
|
219
|
+
stable.response.write stable.request.url
|
220
|
+
|
221
|
+
elsif stable.request.path_info == '/gzip'
|
222
|
+
io = StringIO.new
|
223
|
+
gzip = Zlib::GzipWriter.new(io)
|
224
|
+
gzip << "compressed"
|
225
|
+
gzip.close
|
226
|
+
|
227
|
+
stable.response.write io.string
|
228
|
+
stable.response["Content-Encoding"] = "gzip"
|
229
|
+
|
230
|
+
elsif stable.request.path_info == '/gzip-large'
|
231
|
+
contents = File.open(File.dirname(__FILE__) + "/fixtures/gzip-sample.gz", 'r') { |f| f.read }
|
232
|
+
|
233
|
+
stable.response.write contents
|
234
|
+
stable.response["Content-Encoding"] = "gzip"
|
235
|
+
|
236
|
+
elsif stable.request.path_info == '/deflate'
|
237
|
+
deflater = Zlib::Deflate.new(
|
238
|
+
Zlib::DEFAULT_COMPRESSION,
|
239
|
+
-Zlib::MAX_WBITS, # drop the zlib header which causes both Safari and IE to choke
|
240
|
+
Zlib::DEF_MEM_LEVEL,
|
241
|
+
Zlib::DEFAULT_STRATEGY
|
242
|
+
)
|
243
|
+
deflater.deflate("compressed")
|
244
|
+
stable.response.write deflater.finish
|
245
|
+
stable.response["Content-Encoding"] = "deflate"
|
246
|
+
|
247
|
+
elsif stable.request.path_info == '/echo_accept_encoding'
|
248
|
+
stable.response.status = 200
|
249
|
+
stable.response.write stable.request.env["HTTP_ACCEPT_ENCODING"]
|
250
|
+
|
251
|
+
elsif stable.request.env["HTTP_IF_NONE_MATCH"]
|
252
|
+
stable.response.status = 304
|
253
|
+
|
254
|
+
elsif stable.request.path_info == '/auth' && stable.request.env["HTTP_AUTHORIZATION"]
|
255
|
+
stable.response.status = 200
|
256
|
+
stable.response.write stable.request.env["HTTP_AUTHORIZATION"]
|
257
|
+
elsif stable.request.path_info == '/authtest'
|
258
|
+
auth = "Basic %s" % Base64.strict_encode64(['user', 'pass'].join(':')).split.join
|
259
|
+
if auth == stable.request.env["HTTP_AUTHORIZATION"]
|
260
|
+
stable.response.status = 200
|
261
|
+
stable.response.write 'success'
|
262
|
+
else
|
263
|
+
stable.response.status = 401
|
264
|
+
end
|
265
|
+
elsif stable.request.path_info == '/relative-location'
|
266
|
+
stable.response.status = 301
|
267
|
+
stable.response["Location"] = '/forwarded'
|
268
|
+
elsif stable.request.path_info == '/echo-user-agent'
|
269
|
+
stable.response.write stable.request.env["HTTP_USER_AGENT"].inspect
|
270
|
+
|
271
|
+
elsif
|
272
|
+
stable.response.write 'Hello, World!'
|
273
|
+
end
|
274
|
+
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
Thread.new do
|
279
|
+
begin
|
280
|
+
Stallion.run :Host => '127.0.0.1', :Port => 8090
|
281
|
+
rescue => e
|
282
|
+
print e
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
#
|
287
|
+
# Simple HTTP Proxy server
|
288
|
+
#
|
289
|
+
Thread.new do
|
290
|
+
server = TCPServer.new('127.0.0.1', 8083)
|
291
|
+
loop do
|
292
|
+
session = server.accept
|
293
|
+
request = ""
|
294
|
+
while (data = session.gets) != "\r\n"
|
295
|
+
request << data
|
296
|
+
end
|
297
|
+
parts = request.split("\r\n")
|
298
|
+
method, destination, http_version = parts.first.split(' ')
|
299
|
+
proxy = parts.find { |part| part =~ /Proxy-Authorization/ }
|
300
|
+
if destination =~ /^http:/
|
301
|
+
uri = Addressable::URI.parse(destination)
|
302
|
+
absolute_path = uri.path + (uri.query ? "?#{uri.query}" : "")
|
303
|
+
client = TCPSocket.open(uri.host, uri.port || 80)
|
304
|
+
|
305
|
+
client.write "#{method} #{absolute_path} #{http_version}\r\n"
|
306
|
+
parts[1..-1].each do |part|
|
307
|
+
client.write "#{part}\r\n"
|
308
|
+
end
|
309
|
+
|
310
|
+
client.write "\r\n"
|
311
|
+
client.flush
|
312
|
+
client.close_write
|
313
|
+
|
314
|
+
# Take the initial line from the upstream response
|
315
|
+
session.write client.gets
|
316
|
+
|
317
|
+
if proxy
|
318
|
+
session.write "X-Proxy-Auth: #{proxy}\r\n"
|
319
|
+
end
|
320
|
+
|
321
|
+
# What (absolute) uri was requested? Send it back in a header
|
322
|
+
session.write "X-The-Requested-URI: #{destination}\r\n"
|
323
|
+
|
324
|
+
while data = client.gets
|
325
|
+
session.write data
|
326
|
+
end
|
327
|
+
session.flush
|
328
|
+
client.close
|
329
|
+
end
|
330
|
+
session.close
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
sleep(1)
|