ably-em-http-request 1.1.8

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.
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