From 96e296a445536309e39a25e44c85c3fd6d437880 Mon Sep 17 00:00:00 2001 From: Ezekiel Templin Date: Tue, 22 May 2012 03:44:54 -0400 Subject: [PATCH 1/6] Authenticated HTTP proxy patch --- lib/em-http/client.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/em-http/client.rb b/lib/em-http/client.rb index a70ae7f1..9c8cc207 100644 --- a/lib/em-http/client.rb +++ b/lib/em-http/client.rb @@ -133,9 +133,9 @@ def normalize_body(body) def build_request head = @req.headers ? munge_header_keys(@req.headers) : {} - - if @req.http_proxy? - head['proxy-authorization'] = @req.proxy[:authorization] if @req.proxy[:authorization] + + if proxy = @conn.connopts.proxy + head['proxy-authorization'] = proxy[:authorization] if proxy[:authorization] end # Set the cookie header if provided From 039c2e6db00fbd6ae0b63990cd7030e51b959b5f Mon Sep 17 00:00:00 2001 From: Ezekiel Templin Date: Tue, 22 May 2012 23:33:47 -0400 Subject: [PATCH 2/6] Move and re-implement `http_proxy?` --- lib/em-http/client.rb | 3 ++- lib/em-http/http_client_options.rb | 1 - lib/em-http/http_connection_options.rb | 2 ++ spec/http_proxy_spec.rb | 33 +++++++++++++++++++------- spec/stallion.rb | 5 +++- 5 files changed, 32 insertions(+), 12 deletions(-) diff --git a/lib/em-http/client.rb b/lib/em-http/client.rb index 9c8cc207..24e929fd 100644 --- a/lib/em-http/client.rb +++ b/lib/em-http/client.rb @@ -134,7 +134,8 @@ def normalize_body(body) def build_request head = @req.headers ? munge_header_keys(@req.headers) : {} - if proxy = @conn.connopts.proxy + if @conn.connopts.http_proxy? + proxy = @conn.connopts.proxy head['proxy-authorization'] = proxy[:authorization] if proxy[:authorization] end diff --git a/lib/em-http/http_client_options.rb b/lib/em-http/http_client_options.rb index b284bf33..c83d6171 100644 --- a/lib/em-http/http_client_options.rb +++ b/lib/em-http/http_client_options.rb @@ -25,7 +25,6 @@ def initialize(uri, options, method) end def follow_redirect?; @followed < @redirects; end - def http_proxy?; @proxy && [nil, :http].include?(@proxy[:type]); end def ssl?; @uri.scheme == "https" || @uri.port == 443; end def no_body?; @method == "HEAD"; end diff --git a/lib/em-http/http_connection_options.rb b/lib/em-http/http_connection_options.rb index 8900448e..de7d8164 100644 --- a/lib/em-http/http_connection_options.rb +++ b/lib/em-http/http_connection_options.rb @@ -25,4 +25,6 @@ def initialize(uri, options) @port = uri.port end end + + def http_proxy?; @proxy && [nil, :http].include?(@proxy[:type]); end end diff --git a/spec/http_proxy_spec.rb b/spec/http_proxy_spec.rb index 33d67316..e937f964 100644 --- a/spec/http_proxy_spec.rb +++ b/spec/http_proxy_spec.rb @@ -4,6 +4,7 @@ context "connections via" do let(:proxy) { {:proxy => { :host => '127.0.0.1', :port => 8083 }} } + let(:authenticated_proxy) { {:proxy => { :host => '127.0.0.1', :port => 8083, :authorization => ["user", "name"] } } } it "should use HTTP proxy" do EventMachine.run { @@ -18,15 +19,29 @@ } end - it "should send absolute URIs to the proxy server" do + it "should use HTTP proxy with authentication" do EventMachine.run { + http = EventMachine::HttpRequest.new('http://127.0.0.1:8090/proxyauth?q=test', authenticated_proxy).get + + http.errback { failed(http) } + http.callback { + http.response_header.status.should == 200 + http.response_header['X_PROXY_AUTH'].should == "Proxy-Authorization: Basic dXNlcjpuYW1l" + http.response.should match('test') + EventMachine.stop + } + } + end + it "should send absolute URIs to the proxy server" do + EventMachine.run { + http = EventMachine::HttpRequest.new('http://127.0.0.1:8090/?q=test', proxy).get http.errback { failed(http) } http.callback { http.response_header.status.should == 200 - + # The test proxy server gives the requested uri back in this header http.response_header['X_THE_REQUESTED_URI'].should == 'http://127.0.0.1:8090/?q=test' http.response_header['X_THE_REQUESTED_URI'].should_not == '/?q=test' @@ -35,11 +50,11 @@ } } end - + it "should include query parameters specified in the options" do EventMachine.run { http = EventMachine::HttpRequest.new('http://127.0.0.1:8090/', proxy).get :query => { 'q' => 'test' } - + http.errback { failed(http) } http.callback { http.response_header.status.should == 200 @@ -48,23 +63,23 @@ } } end - + it "should use HTTP proxy while redirecting" do EventMachine.run { http = EventMachine::HttpRequest.new('http://127.0.0.1:8090/redirect', proxy).get :redirects => 1 - + http.errback { failed(http) } http.callback { http.response_header.status.should == 200 - + http.response_header['X_THE_REQUESTED_URI'].should == 'http://127.0.0.1:8090/gzip' http.response_header['X_THE_REQUESTED_URI'].should_not == '/redirect' - + http.response_header["CONTENT_ENCODING"].should == "gzip" http.response.should == "compressed" http.last_effective_url.to_s.should == 'http://127.0.0.1:8090/gzip' http.redirects.should == 1 - + EventMachine.stop } } diff --git a/spec/stallion.rb b/spec/stallion.rb index 83022027..21ca317e 100644 --- a/spec/stallion.rb +++ b/spec/stallion.rb @@ -243,6 +243,7 @@ def self.call(env) end parts = request.split("\r\n") method, destination, http_version = parts.first.split(' ') + proxy = parts.find { |part| part =~ /Proxy-Authorization/ } if destination =~ /^http:/ uri = Addressable::URI.parse(destination) absolute_path = uri.path + (uri.query ? "?#{uri.query}" : "") @@ -259,7 +260,9 @@ def self.call(env) # Take the initial line from the upstream response session.write client.gets - + + session.write "X-Proxy-Auth: #{proxy}\r\n" + # What (absolute) uri was requested? Send it back in a header session.write "X-The-Requested-URI: #{destination}\r\n" From 73cca091b52b6e596444ccdc083ffe54d8024953 Mon Sep 17 00:00:00 2001 From: Ezekiel Templin Date: Wed, 23 May 2012 00:26:35 -0400 Subject: [PATCH 3/6] Whitespace cleanup --- spec/http_proxy_spec.rb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/spec/http_proxy_spec.rb b/spec/http_proxy_spec.rb index e937f964..49155943 100644 --- a/spec/http_proxy_spec.rb +++ b/spec/http_proxy_spec.rb @@ -35,13 +35,13 @@ it "should send absolute URIs to the proxy server" do EventMachine.run { - + http = EventMachine::HttpRequest.new('http://127.0.0.1:8090/?q=test', proxy).get http.errback { failed(http) } http.callback { http.response_header.status.should == 200 - + # The test proxy server gives the requested uri back in this header http.response_header['X_THE_REQUESTED_URI'].should == 'http://127.0.0.1:8090/?q=test' http.response_header['X_THE_REQUESTED_URI'].should_not == '/?q=test' @@ -50,11 +50,11 @@ } } end - + it "should include query parameters specified in the options" do EventMachine.run { http = EventMachine::HttpRequest.new('http://127.0.0.1:8090/', proxy).get :query => { 'q' => 'test' } - + http.errback { failed(http) } http.callback { http.response_header.status.should == 200 @@ -63,23 +63,23 @@ } } end - + it "should use HTTP proxy while redirecting" do EventMachine.run { http = EventMachine::HttpRequest.new('http://127.0.0.1:8090/redirect', proxy).get :redirects => 1 - + http.errback { failed(http) } http.callback { http.response_header.status.should == 200 - + http.response_header['X_THE_REQUESTED_URI'].should == 'http://127.0.0.1:8090/gzip' http.response_header['X_THE_REQUESTED_URI'].should_not == '/redirect' - + http.response_header["CONTENT_ENCODING"].should == "gzip" http.response.should == "compressed" http.last_effective_url.to_s.should == 'http://127.0.0.1:8090/gzip' http.redirects.should == 1 - + EventMachine.stop } } From dcee99380ebe46b753818550964e106307fdf767 Mon Sep 17 00:00:00 2001 From: Ezekiel Templin Date: Wed, 23 May 2012 00:34:00 -0400 Subject: [PATCH 4/6] Only return X-Proxy-Auth when proxy-authorization is in request header --- spec/stallion.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spec/stallion.rb b/spec/stallion.rb index 21ca317e..07c335e0 100644 --- a/spec/stallion.rb +++ b/spec/stallion.rb @@ -261,7 +261,9 @@ def self.call(env) # Take the initial line from the upstream response session.write client.gets - session.write "X-Proxy-Auth: #{proxy}\r\n" + if proxy + session.write "X-Proxy-Auth: #{proxy}\r\n" + end # What (absolute) uri was requested? Send it back in a header session.write "X-The-Requested-URI: #{destination}\r\n" From 67e752bc9da6fd538b78bc6762a7632cd4337cb6 Mon Sep 17 00:00:00 2001 From: Ezekiel Templin Date: Wed, 23 May 2012 00:34:55 -0400 Subject: [PATCH 5/6] Ensure we're not making unexpected proxy auth request --- spec/http_proxy_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/http_proxy_spec.rb b/spec/http_proxy_spec.rb index 49155943..ad99cb59 100644 --- a/spec/http_proxy_spec.rb +++ b/spec/http_proxy_spec.rb @@ -13,6 +13,7 @@ http.errback { failed(http) } http.callback { http.response_header.status.should == 200 + http.response_header.should_not include("X_PROXY_AUTH") http.response.should match('test') EventMachine.stop } From 7d5752d1bcf90b749c3be6eb384e7bdf81441be0 Mon Sep 17 00:00:00 2001 From: Ezekiel Templin Date: Wed, 23 May 2012 00:36:46 -0400 Subject: [PATCH 6/6] Remove proxy attribute from ClientOptions --- lib/em-http/http_client_options.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/em-http/http_client_options.rb b/lib/em-http/http_client_options.rb index c83d6171..6b7d7a44 100644 --- a/lib/em-http/http_client_options.rb +++ b/lib/em-http/http_client_options.rb @@ -1,5 +1,5 @@ class HttpClientOptions - attr_reader :uri, :method, :host, :port, :proxy + attr_reader :uri, :method, :host, :port attr_reader :headers, :file, :body, :query, :path attr_reader :keepalive, :pass_cookies, :decoding