ably-em-http-request 1.1.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/.gemtest +0 -0
  3. data/.github/workflows/ci.yml +22 -0
  4. data/.gitignore +9 -0
  5. data/.rspec +0 -0
  6. data/Changelog.md +78 -0
  7. data/Gemfile +14 -0
  8. data/LICENSE +21 -0
  9. data/README.md +66 -0
  10. data/Rakefile +10 -0
  11. data/ably-em-http-request.gemspec +33 -0
  12. data/benchmarks/clients.rb +170 -0
  13. data/benchmarks/em-excon.rb +87 -0
  14. data/benchmarks/em-profile.gif +0 -0
  15. data/benchmarks/em-profile.txt +65 -0
  16. data/benchmarks/server.rb +48 -0
  17. data/examples/.gitignore +1 -0
  18. data/examples/digest_auth/client.rb +25 -0
  19. data/examples/digest_auth/server.rb +28 -0
  20. data/examples/fetch.rb +30 -0
  21. data/examples/fibered-http.rb +51 -0
  22. data/examples/multi.rb +25 -0
  23. data/examples/oauth-tweet.rb +35 -0
  24. data/examples/socks5.rb +23 -0
  25. data/lib/em/io_streamer.rb +51 -0
  26. data/lib/em-http/client.rb +343 -0
  27. data/lib/em-http/core_ext/bytesize.rb +6 -0
  28. data/lib/em-http/decoders.rb +252 -0
  29. data/lib/em-http/http_client_options.rb +51 -0
  30. data/lib/em-http/http_connection.rb +408 -0
  31. data/lib/em-http/http_connection_options.rb +72 -0
  32. data/lib/em-http/http_encoding.rb +151 -0
  33. data/lib/em-http/http_header.rb +85 -0
  34. data/lib/em-http/http_status_codes.rb +59 -0
  35. data/lib/em-http/middleware/digest_auth.rb +114 -0
  36. data/lib/em-http/middleware/json_response.rb +17 -0
  37. data/lib/em-http/middleware/oauth.rb +42 -0
  38. data/lib/em-http/middleware/oauth2.rb +30 -0
  39. data/lib/em-http/multi.rb +59 -0
  40. data/lib/em-http/request.rb +25 -0
  41. data/lib/em-http/version.rb +7 -0
  42. data/lib/em-http-request.rb +1 -0
  43. data/lib/em-http.rb +20 -0
  44. data/spec/client_fiber_spec.rb +23 -0
  45. data/spec/client_spec.rb +1000 -0
  46. data/spec/digest_auth_spec.rb +48 -0
  47. data/spec/dns_spec.rb +41 -0
  48. data/spec/encoding_spec.rb +49 -0
  49. data/spec/external_spec.rb +146 -0
  50. data/spec/fixtures/google.ca +16 -0
  51. data/spec/fixtures/gzip-sample.gz +0 -0
  52. data/spec/gzip_spec.rb +91 -0
  53. data/spec/helper.rb +27 -0
  54. data/spec/http_proxy_spec.rb +268 -0
  55. data/spec/middleware/oauth2_spec.rb +15 -0
  56. data/spec/middleware_spec.rb +143 -0
  57. data/spec/multi_spec.rb +104 -0
  58. data/spec/pipelining_spec.rb +62 -0
  59. data/spec/redirect_spec.rb +430 -0
  60. data/spec/socksify_proxy_spec.rb +56 -0
  61. data/spec/spec_helper.rb +25 -0
  62. data/spec/ssl_spec.rb +67 -0
  63. data/spec/stallion.rb +334 -0
  64. data/spec/stub_server.rb +45 -0
  65. metadata +269 -0
@@ -0,0 +1,48 @@
1
+ require 'helper'
2
+
3
+ $: << 'lib' << '../lib'
4
+
5
+ require 'em-http/middleware/digest_auth'
6
+
7
+ describe 'Digest Auth Authentication header generation' do
8
+ before :each do
9
+ @reference_header = 'Digest username="digest_username", realm="DigestAuth_REALM", algorithm=MD5, uri="/", nonce="MDAxMzQzNzQwNjA2OmRjZjAyZDY3YWMyMWVkZGQ4OWE2Nzg3ZTY3YTNlMjg5", response="96829962ffc31fa2852f86dc7f9f609b", opaque="BzdNK3gsJ2ixTrBJ"'
10
+ end
11
+
12
+ it 'should generate the correct header' do
13
+ www_authenticate = 'Digest realm="DigestAuth_REALM", nonce="MDAxMzQzNzQwNjA2OmRjZjAyZDY3YWMyMWVkZGQ4OWE2Nzg3ZTY3YTNlMjg5", opaque="BzdNK3gsJ2ixTrBJ", stale=false, algorithm=MD5'
14
+
15
+ params = {
16
+ username: 'digest_username',
17
+ password: 'digest_password'
18
+ }
19
+
20
+ middleware = EM::AblyHttpRequest::Middleware::DigestAuth.new(www_authenticate, params)
21
+ middleware.build_auth_digest('GET', '/').should == @reference_header
22
+ end
23
+
24
+ it 'should not generate the same header for a different user' do
25
+ www_authenticate = 'Digest realm="DigestAuth_REALM", nonce="MDAxMzQzNzQwNjA2OmRjZjAyZDY3YWMyMWVkZGQ4OWE2Nzg3ZTY3YTNlMjg5", opaque="BzdNK3gsJ2ixTrBJ", stale=false, algorithm=MD5'
26
+
27
+ params = {
28
+ username: 'digest_username_2',
29
+ password: 'digest_password'
30
+ }
31
+
32
+ middleware = EM::AblyHttpRequest::Middleware::DigestAuth.new(www_authenticate, params)
33
+ middleware.build_auth_digest('GET', '/').should_not == @reference_header
34
+ end
35
+
36
+ it 'should not generate the same header if the nounce changes' do
37
+ www_authenticate = 'Digest realm="DigestAuth_REALM", nonce="MDAxMzQzNzQwNjA2OmRjZjAyZDY3YWMyMWVkZGQ4OWE2Nzg3ZTY3YTNlMjg6", opaque="BzdNK3gsJ2ixTrBJ", stale=false, algorithm=MD5'
38
+
39
+ params = {
40
+ username: 'digest_username_2',
41
+ password: 'digest_password'
42
+ }
43
+
44
+ middleware = EM::AblyHttpRequest::Middleware::DigestAuth.new(www_authenticate, params)
45
+ middleware.build_auth_digest('GET', '/').should_not == @reference_header
46
+ end
47
+
48
+ end
data/spec/dns_spec.rb ADDED
@@ -0,0 +1,41 @@
1
+ require 'helper'
2
+
3
+ describe EventMachine::AblyHttpRequest::HttpRequest do
4
+
5
+ it "should fail gracefully on an invalid host in Location header" do
6
+ EventMachine.run {
7
+ http = EventMachine::AblyHttpRequest::HttpRequest.new('http://127.0.0.1:8090/redirect/badhost', :connect_timeout => 0.1).get :redirects => 1
8
+ http.callback { failed(http) }
9
+ http.errback {
10
+ http.error.should match(/unable to resolve (server |)address/)
11
+ EventMachine.stop
12
+ }
13
+ }
14
+ end
15
+
16
+ it "should fail GET on DNS timeout" do
17
+ EventMachine.run {
18
+ EventMachine.heartbeat_interval = 0.1
19
+ http = EventMachine::AblyHttpRequest::HttpRequest.new('http://127.1.1.1/', :connect_timeout => 0.1).get
20
+ http.callback { failed(http) }
21
+ http.errback {
22
+ http.response_header.status.should == 0
23
+ EventMachine.stop
24
+ }
25
+ }
26
+ end
27
+
28
+ it "should fail GET on invalid host" do
29
+ EventMachine.run {
30
+ EventMachine.heartbeat_interval = 0.1
31
+ http = EventMachine::AblyHttpRequest::HttpRequest.new('http://somethinglocal/', :connect_timeout => 0.1).get
32
+ http.callback { failed(http) }
33
+ http.errback {
34
+ http.error.should match(/unable to resolve (server |)address/)
35
+ http.response_header.status.should == 0
36
+ EventMachine.stop
37
+ }
38
+ }
39
+ end
40
+
41
+ end
@@ -0,0 +1,49 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'helper'
4
+
5
+ describe EventMachine::AblyHttpRequest::HttpEncoding do
6
+ include EventMachine::AblyHttpRequest::HttpEncoding
7
+
8
+ it "should transform a basic hash into HTTP POST Params" do
9
+ form_encode_body({:a => "alpha", :b => "beta"}).should == "a=alpha&b=beta"
10
+ end
11
+
12
+ it "should transform a more complex hash into HTTP POST Params" do
13
+ form_encode_body({:a => "a", :b => ["c", "d", "e"]}).should == "a=a&b[0]=c&b[1]=d&b[2]=e"
14
+ end
15
+
16
+ it "should transform a very complex hash into HTTP POST Params" do
17
+ params = form_encode_body({:a => "a", :b => [{:c => "c", :d => "d"}, {:e => "e", :f => "f"}]})
18
+ # 1.8.7 does not have ordered hashes.
19
+ params.split(/&/).sort.join('&').should == "a=a&b[0][c]=c&b[0][d]=d&b[1][e]=e&b[1][f]=f"
20
+ end
21
+
22
+ it "should escape values" do
23
+ params = form_encode_body({:stuff => 'string&string'})
24
+ params.should == "stuff=string%26string"
25
+ end
26
+
27
+ it "should escape keys" do
28
+ params = form_encode_body({'bad&str'=> {'key&key' => [:a, :b]}})
29
+ params.should == 'bad%26str[key%26key][0]=a&bad%26str[key%26key][1]=b'
30
+ end
31
+
32
+ it "should escape keys and values" do
33
+ params = form_encode_body({'bad&str'=> {'key&key' => ['bad+&stuff', '[test]']}})
34
+ params.should == "bad%26str[key%26key][0]=bad%2B%26stuff&bad%26str[key%26key][1]=%5Btest%5D"
35
+ end
36
+
37
+ it "should not issue warnings on non-ASCII encodings" do
38
+ # I don't know how to check for ruby warnings.
39
+ params = escape('valö')
40
+ params = escape('valö'.encode('ISO-8859-15'))
41
+ end
42
+
43
+ # xit "should be fast on long string escapes" do
44
+ # s = Time.now
45
+ # 5000.times { |n| form_encode_body({:a => "{a:'b', d:'f', g:['a','b']}"*50}) }
46
+ # (Time.now - s).should satisfy { |t| t < 1.5 }
47
+ # end
48
+
49
+ end
@@ -0,0 +1,146 @@
1
+ require 'helper'
2
+
3
+ describe EventMachine::AblyHttpRequest::HttpRequest do
4
+
5
+ it "should follow redirects on HEAD method (external)" do
6
+ EventMachine.run {
7
+ http = EventMachine::AblyHttpRequest::HttpRequest.new('http://www.google.com/').head :redirects => 1
8
+ http.errback { failed(http) }
9
+ http.callback {
10
+ http.response_header.status.should == 200
11
+ EM.stop
12
+ }
13
+ }
14
+ end
15
+
16
+ it "should follow redirect to https and initiate the handshake" do
17
+ EventMachine.run {
18
+ http = EventMachine::AblyHttpRequest::HttpRequest.new('http://github.com/').get :redirects => 5
19
+
20
+ http.errback { failed(http) }
21
+ http.callback {
22
+ http.response_header.status.should == 200
23
+ EventMachine.stop
24
+ }
25
+ }
26
+ end
27
+
28
+ it "should perform a streaming GET" do
29
+ EventMachine.run {
30
+
31
+ # digg.com uses chunked encoding
32
+ http = EventMachine::AblyHttpRequest::HttpRequest.new('http://www.httpwatch.com/httpgallery/chunked/').get
33
+
34
+ http.errback { failed(http) }
35
+ http.callback {
36
+ http.response_header.status.should == 200
37
+ EventMachine.stop
38
+ }
39
+ }
40
+ end
41
+
42
+ it "should handle a 100 continue" do
43
+ EventMachine.run {
44
+ # 8.2.3 Use of the 100 (Continue) Status - http://www.ietf.org/rfc/rfc2616.txt
45
+ #
46
+ # An origin server SHOULD NOT send a 100 (Continue) response if
47
+ # the request message does not include an Expect request-header
48
+ # field with the "100-continue" expectation, and MUST NOT send a
49
+ # 100 (Continue) response if such a request comes from an HTTP/1.0
50
+ # (or earlier) client. There is an exception to this rule: for
51
+ # compatibility with RFC 2068, a server MAY send a 100 (Continue)
52
+ # status in response to an HTTP/1.1 PUT or POST request that does
53
+ # not include an Expect request-header field with the "100-
54
+ # continue" expectation. This exception, the purpose of which is
55
+ # to minimize any client processing delays associated with an
56
+ # undeclared wait for 100 (Continue) status, applies only to
57
+ # HTTP/1.1 requests, and not to requests with any other HTTP-
58
+ # version value.
59
+ #
60
+ # 10.1.1: 100 Continue - http://www.ietf.org/rfc/rfc2068.txt
61
+ # The client may continue with its request. This interim response is
62
+ # used to inform the client that the initial part of the request has
63
+ # been received and has not yet been rejected by the server. The client
64
+ # SHOULD continue by sending the remainder of the request or, if the
65
+ # request has already been completed, ignore this response. The server
66
+ # MUST send a final response after the request has been completed.
67
+
68
+ url = 'http://ws.serviceobjects.com/lv/LeadValidation.asmx/ValidateLead_V2'
69
+ http = EventMachine::AblyHttpRequest::HttpRequest.new(url).post :body => {:name => :test}
70
+
71
+ http.errback { failed(http) }
72
+ http.callback {
73
+ http.response_header.status.should == 500
74
+ http.response.should match('Missing')
75
+ EventMachine.stop
76
+ }
77
+ }
78
+ end
79
+
80
+ it "should detect deflate encoding" do
81
+ EventMachine.run {
82
+
83
+ options = {:head => {"accept-encoding" => "deflate"}, :redirects => 5}
84
+ http = EventMachine::AblyHttpRequest::HttpRequest.new('https://www.bing.com/').get options
85
+
86
+ http.errback { failed(http) }
87
+ http.callback {
88
+ http.response_header.status.should == 200
89
+ http.response_header["CONTENT_ENCODING"].should == "deflate"
90
+
91
+ EventMachine.stop
92
+ }
93
+ }
94
+ end
95
+
96
+ it "should stream chunked gzipped data" do
97
+ EventMachine.run {
98
+ options = {:head => {"accept-encoding" => "gzip"}}
99
+ # GitHub sends chunked gzip, time for a little Inception ;)
100
+ http = EventMachine::AblyHttpRequest::HttpRequest.new('https://github.com/igrigorik/em-http-request/commits/master').get options
101
+
102
+ http.errback { failed(http) }
103
+ http.callback {
104
+ http.response_header.status.should == 200
105
+ http.response_header["CONTENT_ENCODING"].should == "gzip"
106
+ http.response.should == ''
107
+
108
+ EventMachine.stop
109
+ }
110
+
111
+ body = ''
112
+ http.stream do |chunk|
113
+ body << chunk
114
+ end
115
+ }
116
+ end
117
+
118
+ context "keepalive" do
119
+ it "should default to non-keepalive" do
120
+ EventMachine.run {
121
+ headers = {'If-Modified-Since' => 'Thu, 05 Aug 2010 22:54:44 GMT'}
122
+ http = EventMachine::AblyHttpRequest::HttpRequest.new('http://www.google.com/images/logos/ps_logo2.png').get :head => headers
123
+
124
+ http.errback { fail }
125
+ start = Time.now.to_i
126
+ http.callback {
127
+ (Time.now.to_i - start).should be_within(2).of(0)
128
+ EventMachine.stop
129
+ }
130
+ }
131
+ end
132
+
133
+ it "should work with keep-alive servers" do
134
+ EventMachine.run {
135
+ http = EventMachine::AblyHttpRequest::HttpRequest.new('https://github.com/igrigorik/em-http-request').get :keepalive => true
136
+
137
+ http.errback { failed(http) }
138
+ http.callback {
139
+ http.response_header.status.should == 200
140
+ EventMachine.stop
141
+ }
142
+ }
143
+ end
144
+ end
145
+
146
+ end
@@ -0,0 +1,16 @@
1
+ HTTP/1.1 301 Moved Permanently
2
+ Location: http://www.google.ca/
3
+ Content-Type: text/html; charset=UTF-8
4
+ Date: Sun, 09 Jan 2011 02:51:43 GMT
5
+ Expires: Tue, 08 Feb 2011 02:51:43 GMT
6
+ Cache-Control: public, max-age=2592000
7
+ Server: gws
8
+ Content-Length: 218
9
+ X-XSS-Protection: 1; mode=block
10
+
11
+ <HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
12
+ <TITLE>301 Moved</TITLE></HEAD><BODY>
13
+ <H1>301 Moved</H1>
14
+ The document has moved
15
+ <A HREF="http://www.google.ca/">here</A>.
16
+ </BODY></HTML>
Binary file
data/spec/gzip_spec.rb ADDED
@@ -0,0 +1,91 @@
1
+ require 'helper'
2
+
3
+ describe EventMachine::AblyHttpRequest::HttpDecoders::GZip do
4
+
5
+ let(:compressed) {
6
+ compressed = ["1f8b08089668a6500003686900cbc8e402007a7a6fed03000000"].pack("H*")
7
+ }
8
+
9
+ it "should extract the stream of a vanilla gzip" do
10
+ header = EventMachine::AblyHttpRequest::HttpDecoders::GZipHeader.new
11
+ stream = header.extract_stream(compressed)
12
+
13
+ stream.unpack("H*")[0].should eq("cbc8e402007a7a6fed03000000")
14
+ end
15
+
16
+ it "should decompress a vanilla gzip" do
17
+ decompressed = ""
18
+
19
+ gz = EventMachine::AblyHttpRequest::HttpDecoders::GZip.new do |data|
20
+ decompressed << data
21
+ end
22
+
23
+ gz << compressed
24
+ gz.finalize!
25
+
26
+ decompressed.should eq("hi\n")
27
+ end
28
+
29
+ it "should decompress a vanilla gzip file byte by byte" do
30
+ decompressed = ""
31
+
32
+ gz = EventMachine::AblyHttpRequest::HttpDecoders::GZip.new do |data|
33
+ decompressed << data
34
+ end
35
+
36
+ compressed.each_char do |byte|
37
+ gz << byte
38
+ end
39
+
40
+ gz.finalize!
41
+
42
+ decompressed.should eq("hi\n")
43
+ end
44
+
45
+ it "should decompress a large file" do
46
+ decompressed = ""
47
+
48
+ gz = EventMachine::AblyHttpRequest::HttpDecoders::GZip.new do |data|
49
+ decompressed << data
50
+ end
51
+
52
+ gz << File.read(File.dirname(__FILE__) + "/fixtures/gzip-sample.gz")
53
+
54
+ gz.finalize!
55
+
56
+ decompressed.size.should eq(32907)
57
+ end
58
+
59
+ it "should not care how many chunks the file is split up into" do
60
+ examples = [
61
+ ["\x1F", "\x8B", "\b", "\x00", "\x00", "\x00", "\x00", "\x00", "\x00", "\x00", "\xF3", "\xCB", "/", "Q", "p\xCB/\xCDK\x01\x00M\x8Ct\xB1\t\x00\x00\x00"],
62
+ ["\x1F", "\x8B", "\b", "\x00", "\x00", "\x00", "\x00", "\x00\x00\x00\xF3\xCB/Qp\xCB/\xCDK\x01\x00M\x8Ct\xB1\t\x00\x00\x00"]
63
+ ]
64
+
65
+ examples.each do |example|
66
+ decompressed = ""
67
+
68
+ gz = EventMachine::AblyHttpRequest::HttpDecoders::GZip.new do |data|
69
+ decompressed << data
70
+ end
71
+
72
+ example.each do |bytes|
73
+ gz << bytes
74
+ end
75
+
76
+ gz.finalize!
77
+
78
+ decompressed.should eq("Not Found")
79
+ end
80
+ end
81
+
82
+ it "should fail with a DecoderError if not a gzip file" do
83
+ not_a_gzip = ["1f8c08089668a650000"].pack("H*")
84
+ header = EventMachine::AblyHttpRequest::HttpDecoders::GZipHeader.new
85
+
86
+ lambda {
87
+ header.extract_stream(not_a_gzip)
88
+ }.should raise_exception(EventMachine::AblyHttpRequest::HttpDecoders::DecoderError)
89
+ end
90
+
91
+ end
data/spec/helper.rb ADDED
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+ require 'rubygems'
3
+ require 'bundler/setup'
4
+
5
+ require 'em-http'
6
+ require 'em-http/middleware/oauth2'
7
+ require 'multi_json'
8
+
9
+ require 'stallion'
10
+ require 'stub_server'
11
+
12
+ def failed(http = nil)
13
+ EventMachine.stop
14
+ http ? fail(http.error) : fail
15
+ end
16
+
17
+ def requires_port(port, &blk)
18
+ port_open = true
19
+ begin
20
+ s = TCPSocket.new('localhost', port)
21
+ s.close()
22
+ rescue
23
+ port_open = false
24
+ end
25
+
26
+ blk.call if port_open
27
+ end
@@ -0,0 +1,268 @@
1
+ require 'helper'
2
+
3
+ shared_examples "*_PROXY var (through proxy)" do
4
+ it "should use HTTP proxy" do
5
+ EventMachine.run {
6
+ http = EventMachine::AblyHttpRequest::HttpRequest.new("#{proxy_test_scheme}://127.0.0.1:8090/?q=test").get
7
+
8
+ http.errback { failed(http) }
9
+ http.callback {
10
+ http.response_header.status.should == 200
11
+ http.response_header.should_not include("X_PROXY_AUTH")
12
+ http.response.should match('test')
13
+ EventMachine.stop
14
+ }
15
+ }
16
+ end
17
+ end
18
+
19
+ shared_examples "*_PROXY var (testing var)" do
20
+ subject { AblyHttpRequest::HttpConnectionOptions.new("#{proxy_test_scheme}://example.com", {}) }
21
+ it { expect(subject.proxy_from_env).to eq({ :host => "127.0.0.1", :port => 8083, :type => :http }) }
22
+ it { expect(subject.host).to eq "127.0.0.1" }
23
+ it { expect(subject.port).to be 8083 }
24
+ it do
25
+ case proxy_test_scheme.to_sym
26
+ when :http
27
+ expect(subject.http_proxy?).to be_truthy
28
+ when :https
29
+ expect(subject.connect_proxy?).to be_truthy
30
+ end
31
+ end
32
+ end
33
+
34
+ describe EventMachine::AblyHttpRequest::HttpRequest do
35
+
36
+ context "connections via" do
37
+ context "without *_PROXY env" do
38
+ let(:proxy) { {:proxy => { :host => '127.0.0.1', :port => 8083 }} }
39
+ let(:authenticated_proxy) { {:proxy => { :host => '127.0.0.1', :port => 8083, :authorization => ["user", "name"] } } }
40
+
41
+ it "should use HTTP proxy" do
42
+ EventMachine.run {
43
+ http = EventMachine::AblyHttpRequest::HttpRequest.new('http://127.0.0.1:8090/?q=test', proxy).get
44
+
45
+ http.errback { failed(http) }
46
+ http.callback {
47
+ http.response_header.status.should == 200
48
+ http.response_header.should_not include("X_PROXY_AUTH")
49
+ http.response.should match('test')
50
+ EventMachine.stop
51
+ }
52
+ }
53
+ end
54
+
55
+ it "should use HTTP proxy with authentication" do
56
+ EventMachine.run {
57
+ http = EventMachine::AblyHttpRequest::HttpRequest.new('http://127.0.0.1:8090/proxyauth?q=test', authenticated_proxy).get
58
+
59
+ http.errback { failed(http) }
60
+ http.callback {
61
+ http.response_header.status.should == 200
62
+ http.response_header['X_PROXY_AUTH'].should == "Proxy-Authorization: Basic dXNlcjpuYW1l"
63
+ http.response.should match('test')
64
+ EventMachine.stop
65
+ }
66
+ }
67
+ end
68
+
69
+ it "should send absolute URIs to the proxy server" do
70
+ EventMachine.run {
71
+
72
+ http = EventMachine::AblyHttpRequest::HttpRequest.new('http://127.0.0.1:8090/?q=test', proxy).get
73
+
74
+ http.errback { failed(http) }
75
+ http.callback {
76
+ http.response_header.status.should == 200
77
+
78
+ # The test proxy server gives the requested uri back in this header
79
+ http.response_header['X_THE_REQUESTED_URI'].should == 'http://127.0.0.1:8090/?q=test'
80
+ http.response_header['X_THE_REQUESTED_URI'].should_not == '/?q=test'
81
+ http.response.should match('test')
82
+ EventMachine.stop
83
+ }
84
+ }
85
+ end
86
+
87
+ it "should strip basic auth from before the host in URI sent to proxy" do
88
+ EventMachine.run {
89
+
90
+ http = EventMachine::AblyHttpRequest::HttpRequest.new('http://user:pass@127.0.0.1:8090/echo_authorization_header', proxy).get
91
+
92
+ http.errback { failed(http) }
93
+ http.callback {
94
+ http.response_header.status.should == 200
95
+ # The test proxy server gives the requested uri back in this header
96
+ http.response_header['X_THE_REQUESTED_URI'].should == 'http://127.0.0.1:8090/echo_authorization_header'
97
+ # Ensure the basic auth was converted to a header correctly
98
+ http.response.should match('authorization:Basic dXNlcjpwYXNz')
99
+ EventMachine.stop
100
+ }
101
+ }
102
+ end
103
+
104
+ it "should include query parameters specified in the options" do
105
+ EventMachine.run {
106
+ http = EventMachine::AblyHttpRequest::HttpRequest.new('http://127.0.0.1:8090/', proxy).get :query => { 'q' => 'test' }
107
+
108
+ http.errback { failed(http) }
109
+ http.callback {
110
+ http.response_header.status.should == 200
111
+ http.response.should match('test')
112
+ EventMachine.stop
113
+ }
114
+ }
115
+ end
116
+
117
+ it "should use HTTP proxy while redirecting" do
118
+ EventMachine.run {
119
+ http = EventMachine::AblyHttpRequest::HttpRequest.new('http://127.0.0.1:8090/redirect', proxy).get :redirects => 1
120
+
121
+ http.errback { failed(http) }
122
+ http.callback {
123
+ http.response_header.status.should == 200
124
+
125
+ http.response_header['X_THE_REQUESTED_URI'].should == 'http://127.0.0.1:8090/gzip'
126
+ http.response_header['X_THE_REQUESTED_URI'].should_not == '/redirect'
127
+
128
+ http.response_header["CONTENT_ENCODING"].should == "gzip"
129
+ http.response.should == "compressed"
130
+ http.last_effective_url.to_s.should == 'http://127.0.0.1:8090/gzip'
131
+ http.redirects.should == 1
132
+
133
+ EventMachine.stop
134
+ }
135
+ }
136
+ end
137
+ end
138
+
139
+ context "when parsing *_PROXY var (through proxy)s" do
140
+ context "with $HTTP_PROXY env" do
141
+ let(:proxy_test_scheme) { :http }
142
+
143
+ before(:all) do
144
+ PROXY_ENV_VARS.each {|k| ENV.delete k }
145
+ ENV['HTTP_PROXY'] = 'http://127.0.0.1:8083'
146
+ end
147
+
148
+ include_examples "*_PROXY var (through proxy)"
149
+ end
150
+
151
+ context "with $http_proxy env" do
152
+ let(:proxy_test_scheme) { :http }
153
+
154
+ before(:all) do
155
+ PROXY_ENV_VARS.each {|k| ENV.delete k }
156
+ ENV['http_proxy'] = 'http://127.0.0.1:8083'
157
+ end
158
+
159
+ include_examples "*_PROXY var (through proxy)"
160
+ end
161
+
162
+ ## TODO: Use a Mongrel HTTP server that can handle SSL:
163
+ context "with $HTTPS_PROXY env", skip: "Mongrel isn't configured to handle HTTPS, currently" do
164
+ let(:proxy_test_scheme) { :https }
165
+
166
+ before(:all) do
167
+ PROXY_ENV_VARS.each {|k| ENV.delete k }
168
+ ENV['HTTPS_PROXY'] = 'http://127.0.0.1:8083'
169
+ end
170
+
171
+ include_examples "*_PROXY var (through proxy)"
172
+ end
173
+
174
+ ## TODO: Use a Mongrel HTTP server that can handle SSL:
175
+ context "with $https_proxy env", skip: "Mongrel isn't configured to handle HTTPS, currently" do
176
+ let(:proxy_test_scheme) { :https }
177
+
178
+ before(:all) do
179
+ PROXY_ENV_VARS.each {|k| ENV.delete k }
180
+ ENV['https_proxy'] = 'http://127.0.0.1:8083'
181
+ end
182
+
183
+ include_examples "*_PROXY var (through proxy)"
184
+ end
185
+
186
+ context "with $ALL_PROXY env" do
187
+ let(:proxy_test_scheme) { :http }
188
+
189
+ before(:all) do
190
+ PROXY_ENV_VARS.each {|k| ENV.delete k }
191
+ ENV['ALL_PROXY'] = 'http://127.0.0.1:8083'
192
+ end
193
+
194
+ include_examples "*_PROXY var (through proxy)"
195
+ end
196
+ end
197
+ end
198
+
199
+ context "when parsing *_PROXY vars" do
200
+ context "without a *_PROXY var" do
201
+ before(:all) do
202
+ PROXY_ENV_VARS.each {|k| ENV.delete k }
203
+ end
204
+
205
+ subject { AblyHttpRequest::HttpConnectionOptions.new("http://example.com", {}) }
206
+ it { expect(subject.proxy_from_env).to be_nil }
207
+ it { expect(subject.host).to eq "example.com" }
208
+ it { expect(subject.port).to be 80 }
209
+ it { expect(subject.http_proxy?).to be_falsey }
210
+ it { expect(subject.connect_proxy?).to be_falsey }
211
+ end
212
+
213
+ context "with $HTTP_PROXY env" do
214
+ let(:proxy_test_scheme) { :http }
215
+
216
+ before(:each) do
217
+ PROXY_ENV_VARS.each {|k| ENV.delete k }
218
+ ENV['HTTP_PROXY'] = 'http://127.0.0.1:8083'
219
+ end
220
+
221
+ include_examples "*_PROXY var (testing var)"
222
+ end
223
+
224
+ context "with $http_proxy env" do
225
+ let(:proxy_test_scheme) { :http }
226
+
227
+ before(:each) do
228
+ PROXY_ENV_VARS.each {|k| ENV.delete k }
229
+ ENV['http_proxy'] = 'http://127.0.0.1:8083'
230
+ end
231
+
232
+ include_examples "*_PROXY var (testing var)"
233
+ end
234
+
235
+ context "with $HTTPS_PROXY env" do
236
+ let(:proxy_test_scheme) { :https }
237
+
238
+ before(:each) do
239
+ PROXY_ENV_VARS.each {|k| ENV.delete k }
240
+ ENV['HTTPS_PROXY'] = 'http://127.0.0.1:8083'
241
+ end
242
+
243
+ include_examples "*_PROXY var (testing var)"
244
+ end
245
+
246
+ context "with $https_proxy env" do
247
+ let(:proxy_test_scheme) { :https }
248
+
249
+ before(:each) do
250
+ PROXY_ENV_VARS.each {|k| ENV.delete k }
251
+ ENV['https_proxy'] = 'http://127.0.0.1:8083'
252
+ end
253
+
254
+ include_examples "*_PROXY var (testing var)"
255
+ end
256
+
257
+ context "with $ALL_PROXY env" do
258
+ let(:proxy_test_scheme) { :https }
259
+
260
+ before(:each) do
261
+ PROXY_ENV_VARS.each {|k| ENV.delete k }
262
+ ENV['ALL_PROXY'] = 'http://127.0.0.1:8083'
263
+ end
264
+
265
+ include_examples "*_PROXY var (testing var)"
266
+ end
267
+ end
268
+ end