http 0.8.3 → 0.8.4

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
  SHA1:
3
- metadata.gz: 6855d98f9ce4716fb04fda587060dfcc2869b378
4
- data.tar.gz: cc3dd5823219d9c1043d59a4ecd28783f3a54314
3
+ metadata.gz: 9b829e0c5ca1c70ca3f55b33080088ab248c52fc
4
+ data.tar.gz: 248df6f0b8df5a75bfa872d5f24a263568f63e5a
5
5
  SHA512:
6
- metadata.gz: ac67b4ffeddb6b1fc1f53c8c9ccc75cae95dfa2fe834f7c9ef4f997734b846a4f380fdc61c8216239e95fa666b774f1083653193357006a31b7c83404747484b
7
- data.tar.gz: 5a41152c4bf84a18db3b9bfe93dca7cb94d68176d0c02038efc21c8955915ebbf11a36535c867e762ddb09c7385ea9b235ac37d9fe2b605ce0ea6a20bb8495dc
6
+ metadata.gz: b4e37035a7a6b692d103a24e6f75a30509a5d2a92aa1b4c21a2c0a393886c648c5b28df3e36779aa274430243dbde29af69ea4eaff25c5ff4aecd3c880bc0068
7
+ data.tar.gz: 76fae19bd0b8f31e9825a3514e21f83f006bc205c2e118ec4fec8ebd644900d3bbbf2f7119dc800ac4782b4ba9665be64a588083585d9bf12bae36e97188c69b
@@ -3,7 +3,7 @@ Metrics/BlockNesting:
3
3
 
4
4
  Metrics/ClassLength:
5
5
  CountComments: false
6
- Max: 110
6
+ Max: 120
7
7
 
8
8
  Metrics/PerceivedComplexity:
9
9
  Max: 8
@@ -37,7 +37,7 @@ Style/Documentation:
37
37
  Enabled: false
38
38
 
39
39
  Style/DotPosition:
40
- EnforcedStyle: leading
40
+ EnforcedStyle: trailing
41
41
 
42
42
  Style/DoubleNegation:
43
43
  Enabled: false
data/CHANGES.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## master (unreleased)
2
+
3
+
4
+ ## 0.8.4 (2015-04-23)
5
+
6
+ * Deprecate `#default_headers` and `#default_headers=`. (@ixti)
7
+ * Deprecate chainable methods with `with_` prefix. See #207. (@ixti)
8
+ * Add support of HTTPS connections through proxy. See #186. (@Connorhd)
9
+
10
+
1
11
  ## 0.8.3 (2015-04-07)
2
12
 
3
13
  * Fix request headline. See #206. (@ixti)
data/README.md CHANGED
@@ -40,7 +40,7 @@ Installation
40
40
 
41
41
  Add this line to your application's Gemfile:
42
42
 
43
- gem 'http'
43
+ gem "http"
44
44
 
45
45
  And then execute:
46
46
 
@@ -52,7 +52,7 @@ Or install it yourself as:
52
52
 
53
53
  Inside of your Ruby program do:
54
54
 
55
- require 'http'
55
+ require "http"
56
56
 
57
57
  ...to pull it in as a dependency.
58
58
 
@@ -70,7 +70,7 @@ Here's some simple examples to get you started:
70
70
  ### GET requests
71
71
 
72
72
  ```ruby
73
- >> HTTP.get('https://github.com').to_s
73
+ >> HTTP.get("https://github.com").to_s
74
74
  => "<html><head><meta http-equiv=\"content-type\" content=..."
75
75
  ```
76
76
 
@@ -78,7 +78,7 @@ That's all it takes! To obtain an `HTTP::Response` object instead of the respons
78
78
  body, all we have to do is omit the #to_s on the end:
79
79
 
80
80
  ```ruby
81
- >> HTTP.get('https://github.com')
81
+ >> HTTP.get("https://github.com")
82
82
  => #<HTTP/1.0 200 OK @headers={"Content-Type"=>"text/html; charset=UTF-8", "Date"=>"Fri, ...>
83
83
  => #<HTTP::Response/1.1 200 OK @headers={"Content-Type"=>"text/html; ...>
84
84
  ```
@@ -86,51 +86,51 @@ body, all we have to do is omit the #to_s on the end:
86
86
  We can also obtain an `HTTP::Response::Body` object for this response:
87
87
 
88
88
  ```ruby
89
- >> HTTP.get('https://github.com').body
89
+ >> HTTP.get("https://github.com").body
90
90
  => #<HTTP::Response::Body:814d7aac @streaming=false>
91
91
  ```
92
92
 
93
93
  The response body can be streamed with `HTTP::Response::Body#readpartial`:
94
94
 
95
95
  ```ruby
96
- >> HTTP.get('https://github.com').body.readpartial
96
+ >> HTTP.get("https://github.com").body.readpartial
97
97
  => "<!doctype html><html "
98
98
  ```
99
99
 
100
100
  In practice you'll want to bind the HTTP::Response::Body to a local variable (e.g.
101
- "body") and call readpartial on it repeatedly until it returns nil.
101
+ "body") and call readpartial on it repeatedly until it returns `nil`.
102
102
 
103
103
  ### POST requests
104
104
 
105
105
  Making POST requests is simple too. Want to POST a form?
106
106
 
107
107
  ```ruby
108
- HTTP.post('http://example.com/resource', :form => {:foo => '42'})
108
+ HTTP.post("http://example.com/resource", :form => {:foo => "42"})
109
109
  ```
110
110
  Making GET requests with query string parameters is as simple.
111
111
 
112
112
  ```ruby
113
- HTTP.get('http://example.com/resource', :params => {:foo => 'bar'})
113
+ HTTP.get("http://example.com/resource", :params => {:foo => "bar"})
114
114
  ```
115
115
 
116
116
  Want to POST with a specific body, JSON for instance?
117
117
 
118
118
  ```ruby
119
- HTTP.post('http://example.com/resource', :json => { :foo => '42' })
119
+ HTTP.post("http://example.com/resource", :json => { :foo => "42" })
120
120
  ```
121
121
 
122
122
  Or just a plain body?
123
123
 
124
124
  ```ruby
125
- HTTP.post('http://example.com/resource', :body => 'foo=42&bar=baz')
125
+ HTTP.post("http://example.com/resource", :body => "foo=42&bar=baz")
126
126
  ```
127
127
 
128
128
  Posting a file?
129
129
 
130
130
  ``` ruby
131
- HTTP.post('http://examplc.com/resource', :form => {
132
- :username => 'ixti',
133
- :avatar => HTTP::FormData::File.new('/home/ixit/avatar.png')
131
+ HTTP.post("http://examplc.com/resource", :form => {
132
+ :username => "ixti",
133
+ :avatar => HTTP::FormData::File.new("/home/ixit/avatar.png")
134
134
  })
135
135
  ```
136
136
 
@@ -142,15 +142,15 @@ Making request behind proxy is as simple as making them directly. Just specify
142
142
  hostname (or IP address) of your proxy server and its port, and here you go:
143
143
 
144
144
  ```ruby
145
- HTTP.via('proxy-hostname.local', 8080)
146
- .get('http://example.com/resource')
145
+ HTTP.via("proxy-hostname.local", 8080)
146
+ .get("http://example.com/resource")
147
147
  ```
148
148
 
149
149
  Proxy needs authentication? No problem:
150
150
 
151
151
  ```ruby
152
- HTTP.via('proxy-hostname.local', 8080, 'username', 'password')
153
- .get('http://example.com/resource')
152
+ HTTP.via("proxy-hostname.local", 8080, "username", "password")
153
+ .get("http://example.com/resource")
154
154
  ```
155
155
 
156
156
  ### Adding Headers
@@ -160,7 +160,7 @@ you want to get the latest commit of this library from GitHub in JSON format.
160
160
  One way we could do this is by tacking a filename on the end of the URL:
161
161
 
162
162
  ```ruby
163
- HTTP.get('https://github.com/httprb/http.rb/commit/HEAD.json')
163
+ HTTP.get("https://github.com/httprb/http.rb/commit/HEAD.json")
164
164
  ```
165
165
 
166
166
  The GitHub API happens to support this approach, but really this is a bit of a
@@ -170,21 +170,18 @@ the full, raw power of HTTP, we can perform content negotiation the way HTTP
170
170
  intends us to, by using the Accept header:
171
171
 
172
172
  ```ruby
173
- HTTP.with_headers(:accept => 'application/json').
174
- get('https://github.com/httprb/http.rb/commit/HEAD')
173
+ HTTP.headers(:accept => "application/json")
174
+ .get("https://github.com/httprb/http.rb/commit/HEAD")
175
175
  ```
176
176
 
177
177
  This requests JSON from GitHub. GitHub is smart enough to understand our
178
- request and returns a response with Content-Type: application/json.
178
+ request and returns a response with `Content-Type: application/json`.
179
179
 
180
- Shorter aliases exists for HTTP.with_headers:
180
+ Shorter alias exists for `HTTP.headers`:
181
181
 
182
182
  ```ruby
183
- HTTP.with(:accept => 'application/json').
184
- get('https://github.com/httprb/http.rb/commit/HEAD')
185
-
186
- HTTP[:accept => 'application/json'].
187
- get('https://github.com/httprb/http.rb/commit/HEAD')
183
+ HTTP[:accept => "application/json"]
184
+ .get("https://github.com/httprb/http.rb/commit/HEAD")
188
185
  ```
189
186
 
190
187
  ### Authorization Header
@@ -193,23 +190,23 @@ With [HTTP Basic Authentication](http://tools.ietf.org/html/rfc2617) using
193
190
  a username and password:
194
191
 
195
192
  ```ruby
196
- HTTP.basic_auth(:user => 'user', :pass => 'pass')
193
+ HTTP.basic_auth(:user => "user", :pass => "pass")
197
194
  # <HTTP::Headers {"Authorization"=>"Basic dXNlcjpwYXNz"}>
198
195
  ```
199
196
 
200
197
  Or with plain as-is value:
201
198
 
202
199
  ```ruby
203
- HTTP.auth('Bearer VGhlIEhUVFAgR2VtLCBST0NLUw')
200
+ HTTP.auth("Bearer VGhlIEhUVFAgR2VtLCBST0NLUw")
204
201
  # <HTTP::Headers {"Authorization"=>"Bearer VGhlIEhUVFAgR2VtLCBST0NLUw"}>
205
202
  ```
206
203
 
207
204
  And Chain all together!
208
205
 
209
206
  ```ruby
210
- HTTP.basic_auth(:user => 'user', :pass => 'pass')
211
- .with('Cookie' => '9wq3w')
212
- .get('https://example.com')
207
+ HTTP.basic_auth(:user => "user", :pass => "pass")
208
+ .headers("Cookie" => "9wq3w")
209
+ .get("https://example.com")
213
210
  ```
214
211
 
215
212
  ### Content Negotiation
@@ -219,7 +216,7 @@ right? But usually it's not, and so we end up adding ".json" onto the ends of
219
216
  our URLs because the existing mechanisms make it too hard. It should be easy:
220
217
 
221
218
  ```ruby
222
- HTTP.accept(:json).get('https://github.com/httprb/http.rb/commit/HEAD')
219
+ HTTP.accept(:json).get("https://github.com/httprb/http.rb/commit/HEAD")
223
220
  ```
224
221
 
225
222
  This adds the appropriate Accept header for retrieving a JSON response for the
@@ -232,8 +229,8 @@ Celluloid::IO actor. Here's a parallel HTTP fetcher combining http.rb with
232
229
  Celluloid::IO:
233
230
 
234
231
  ```ruby
235
- require 'celluloid/io'
236
- require 'http'
232
+ require "celluloid/io"
233
+ require "http"
237
234
 
238
235
  class HttpFetcher
239
236
  include Celluloid::IO
@@ -256,10 +253,10 @@ http.rb provides caching of HTTP request (per
256
253
  so.
257
254
 
258
255
  ```ruby
259
- require 'http'
256
+ require "http"
260
257
 
261
- http = HTTP.with_cache(metastore: "file:/var/cache/my-app-http/meta",
262
- entitystore: "file:/var/cache/my-app-http/entity")
258
+ http = HTTP.cache(:metastore => "file:/var/cache/my-app-http/meta",
259
+ :entitystore => "file:/var/cache/my-app-http/entity")
263
260
 
264
261
  http.get("http://example.com/") # makes request
265
262
  http.get("http://example.com/") # skips making request and returns
@@ -69,9 +69,9 @@ module HTTP
69
69
  # ---
70
70
  # Some servers send a "Expire: -1" header which must be treated as expired
71
71
  def seconds_til_expires
72
- get("Expires")
73
- .map { |e| http_date_to_ttl(e) }
74
- .max
72
+ get("Expires").
73
+ map { |e| http_date_to_ttl(e) }.
74
+ max
75
75
  end
76
76
 
77
77
  def http_date_to_ttl(t_str)
@@ -89,11 +89,11 @@ module HTTP
89
89
 
90
90
  # @return [Numeric] the value of the max-age component of cache control
91
91
  def explicit_max_age
92
- get("Cache-Control")
93
- .map { |v| (/max-age=(\d+)/i).match(v) }
94
- .compact
95
- .map { |m| m[1].to_i }
96
- .max
92
+ get("Cache-Control").
93
+ map { |v| (/max-age=(\d+)/i).match(v) }.
94
+ compact.
95
+ map { |m| m[1].to_i }.
96
+ max
97
97
  end
98
98
  end
99
99
  end
@@ -140,20 +140,31 @@ module HTTP
140
140
  branch default_options.with_follow opts
141
141
  end
142
142
 
143
- # @deprecated
143
+ # @deprecated will be removed in 1.0.0
144
144
  # @see #follow
145
145
  alias_method :with_follow, :follow
146
146
 
147
- def with_cache(cache)
147
+ def cache(cache)
148
148
  branch default_options.with_cache(cache)
149
149
  end
150
150
 
151
+ # @deprecated will be removed in 1.0.0
152
+ # @see #cache
153
+ alias_method :with_cache, :cache
154
+
151
155
  # Make a request with the given headers
152
156
  # @param headers
153
- def with_headers(headers)
157
+ def headers(headers)
154
158
  branch default_options.with_headers(headers)
155
159
  end
156
- alias_method :with, :with_headers
160
+
161
+ # @deprecated will be removed in 1.0.0
162
+ # @see #headers
163
+ alias_method :with, :headers
164
+
165
+ # @deprecated will be removed in 1.0.0
166
+ # @see #headers
167
+ alias_method :with_headers, :headers
157
168
 
158
169
  # Accept the given MIME type(s)
159
170
  # @param type
@@ -195,12 +206,14 @@ module HTTP
195
206
  @default_options = HTTP::Options.new(opts)
196
207
  end
197
208
 
209
+ # @deprecated Will be removed in 1.0.0; Use `#default_options#headers`
198
210
  # Get headers of HTTP options
199
211
  def default_headers
200
212
  default_options.headers
201
213
  end
202
214
 
203
215
  # Set headers of HTTP options
216
+ # @deprecated Will be removed in 1.0.0; Use `#headers`
204
217
  # @param headers
205
218
  def default_headers=(headers)
206
219
  @default_options = default_options.dup do |opts|
@@ -21,8 +21,6 @@ module HTTP
21
21
 
22
22
  HTTP_OR_HTTPS_RE = %r{^https?://}i
23
23
 
24
- attr_reader :default_options
25
-
26
24
  def initialize(default_options = {})
27
25
  @default_options = HTTP::Options.new(default_options)
28
26
  @connection = nil
@@ -72,8 +70,11 @@ module HTTP
72
70
  @state = :dirty
73
71
 
74
72
  @connection ||= HTTP::Connection.new(req, options)
75
- @connection.send_request(req)
76
- @connection.read_headers!
73
+
74
+ unless @connection.failed_proxy_connect?
75
+ @connection.send_request(req)
76
+ @connection.read_headers!
77
+ end
77
78
 
78
79
  res = Response.new(
79
80
  @connection.status_code,
@@ -6,6 +6,7 @@ module HTTP
6
6
  # A connection to the HTTP server
7
7
  class Connection
8
8
  extend Forwardable
9
+
9
10
  # Attempt to read this much data
10
11
  BUFFER_SIZE = 16_384
11
12
 
@@ -18,16 +19,18 @@ module HTTP
18
19
  # @param [HTTP::Request] req
19
20
  # @param [HTTP::Options] options
20
21
  def initialize(req, options)
21
- @persistent = options.persistent?
22
- @keep_alive_timeout = options[:keep_alive_timeout].to_f
23
- @pending_request = false
24
- @pending_response = false
22
+ @persistent = options.persistent?
23
+ @keep_alive_timeout = options[:keep_alive_timeout].to_f
24
+ @pending_request = false
25
+ @pending_response = false
26
+ @failed_proxy_connect = false
25
27
 
26
28
  @parser = Response::Parser.new
27
29
 
28
30
  @socket = options[:timeout_class].new(options[:timeout_options])
29
31
  @socket.connect(options[:socket_class], req.socket_host, req.socket_port)
30
32
 
33
+ send_proxy_connect_request(req)
31
34
  start_tls(req, options)
32
35
  reset_timer
33
36
  end
@@ -41,6 +44,11 @@ module HTTP
41
44
  # @see (HTTP::Response::Parser#headers)
42
45
  def_delegator :@parser, :headers
43
46
 
47
+ # @return [Boolean] whenever proxy connect failed
48
+ def failed_proxy_connect?
49
+ @failed_proxy_connect
50
+ end
51
+
44
52
  # Send a request to the server
45
53
  #
46
54
  # @param [Request] Request to send to the server
@@ -129,7 +137,7 @@ module HTTP
129
137
  # @param (see #initialize)
130
138
  # @return [void]
131
139
  def start_tls(req, options)
132
- return unless req.uri.https? && !req.using_proxy?
140
+ return unless req.uri.https? && !failed_proxy_connect?
133
141
 
134
142
  ssl_context = options[:ssl_context]
135
143
 
@@ -141,6 +149,28 @@ module HTTP
141
149
  @socket.start_tls(req.uri.host, options[:ssl_socket_class], ssl_context)
142
150
  end
143
151
 
152
+ # Open tunnel through proxy
153
+ def send_proxy_connect_request(req)
154
+ return unless req.uri.https? && req.using_proxy?
155
+
156
+ @pending_request = true
157
+
158
+ req.connect_using_proxy @socket
159
+
160
+ @pending_request = false
161
+ @pending_response = true
162
+
163
+ read_headers!
164
+
165
+ if @parser.status_code == 200
166
+ @parser.reset
167
+ @pending_response = false
168
+ return
169
+ end
170
+
171
+ @failed_proxy_connect = true
172
+ end
173
+
144
174
  # Resets expiration of persistent connection.
145
175
  # @return [void]
146
176
  def reset_timer
@@ -30,7 +30,7 @@ module HTTP
30
30
 
31
31
  def def_option(name, &interpreter)
32
32
  defined_options << name.to_sym
33
- interpreter ||= ->(v) { v }
33
+ interpreter ||= lambda { |v| v }
34
34
 
35
35
  attr_accessor name
36
36
  protected :"#{name}="
@@ -118,9 +118,9 @@ module HTTP
118
118
  end
119
119
 
120
120
  def to_hash
121
- hash_pairs = self.class
122
- .defined_options
123
- .flat_map { |opt_name| [opt_name, self[opt_name]] }
121
+ hash_pairs = self.class.
122
+ defined_options.
123
+ flat_map { |opt_name| [opt_name, self[opt_name]] }
124
124
  Hash[*hash_pairs]
125
125
  end
126
126
 
@@ -90,7 +90,7 @@ module HTTP
90
90
 
91
91
  # Stream the request to a socket
92
92
  def stream(socket)
93
- include_proxy_authorization_header if using_authenticated_proxy?
93
+ include_proxy_authorization_header if using_authenticated_proxy? && !@uri.https?
94
94
  Request::Writer.new(socket, body, headers, request_header).stream
95
95
  end
96
96
 
@@ -106,8 +106,17 @@ module HTTP
106
106
 
107
107
  # Compute and add the Proxy-Authorization header
108
108
  def include_proxy_authorization_header
109
- digest = Base64.encode64("#{proxy[:proxy_username]}:#{proxy[:proxy_password]}").chomp
110
- headers["Proxy-Authorization"] = "Basic #{digest}"
109
+ headers["Proxy-Authorization"] = proxy_authorization_header
110
+ end
111
+
112
+ def proxy_authorization_header
113
+ digest = Base64.strict_encode64("#{proxy[:proxy_username]}:#{proxy[:proxy_password]}")
114
+ "Basic #{digest}"
115
+ end
116
+
117
+ # Setup tunnel through proxy for SSL request
118
+ def connect_using_proxy(socket)
119
+ Request::Writer.new(socket, nil, proxy_connect_headers, proxy_connect_header).connect_through_proxy
111
120
  end
112
121
 
113
122
  # Compute HTTP request header for direct or proxy request
@@ -116,6 +125,21 @@ module HTTP
116
125
  "#{verb.to_s.upcase} #{request_uri} HTTP/#{version}"
117
126
  end
118
127
 
128
+ # Compute HTTP request header SSL proxy connection
129
+ def proxy_connect_header
130
+ "CONNECT #{@uri.host}:#{@uri.port} HTTP/#{version}"
131
+ end
132
+
133
+ # Headers to send with proxy connect request
134
+ def proxy_connect_headers
135
+ connect_headers = HTTP::Headers.coerce(
136
+ "Host" => headers["Host"],
137
+ "User-Agent" => headers["User-Agent"]
138
+ )
139
+ connect_headers["Proxy-Authorization"] = proxy_authorization_header if using_authenticated_proxy?
140
+ connect_headers
141
+ end
142
+
119
143
  # Host for tcp socket
120
144
  def socket_host
121
145
  using_proxy? ? proxy[:proxy_address] : host
@@ -70,7 +70,7 @@ module HTTP
70
70
  end
71
71
 
72
72
  def env
73
- {"rack-cache.cache_key" => ->(r) { r.uri.to_s }}
73
+ {"rack-cache.cache_key" => lambda { |r| r.uri.to_s }}
74
74
  end
75
75
 
76
76
  private
@@ -80,11 +80,11 @@ module HTTP
80
80
  def conditional_headers_for(cached_response)
81
81
  headers = HTTP::Headers.new
82
82
 
83
- cached_response.headers.get("Etag")
84
- .each { |etag| headers.add("If-None-Match", etag) }
83
+ cached_response.headers.get("Etag").
84
+ each { |etag| headers.add("If-None-Match", etag) }
85
85
 
86
- cached_response.headers.get("Last-Modified")
87
- .each { |last_mod| headers.add("If-Modified-Since", last_mod) }
86
+ cached_response.headers.get("Last-Modified").
87
+ each { |last_mod| headers.add("If-Modified-Since", last_mod) }
88
88
 
89
89
  headers.add("Cache-Control", "max-age=0") if cache_headers.forces_revalidation?
90
90
 
@@ -29,6 +29,12 @@ module HTTP
29
29
  send_request_body
30
30
  end
31
31
 
32
+ # Send headers needed to connect through proxy
33
+ def connect_through_proxy
34
+ add_headers
35
+ @socket << join_headers
36
+ end
37
+
32
38
  # Adds the headers to the header array for the given request body we are working
33
39
  # with
34
40
  def add_body_type_headers
@@ -50,9 +56,8 @@ module HTTP
50
56
  def send_request_header
51
57
  add_headers
52
58
  add_body_type_headers
53
- header = join_headers
54
59
 
55
- @socket << header
60
+ @socket << join_headers
56
61
  end
57
62
 
58
63
  def send_request_body
@@ -123,9 +123,9 @@ module HTTP
123
123
 
124
124
  # @return [Time] the time at which the server generated this response.
125
125
  def server_response_time
126
- headers.get("Date")
127
- .map(&method(:to_time_or_epoch))
128
- .max || begin
126
+ headers.get("Date").
127
+ map(&method(:to_time_or_epoch)).
128
+ max || begin
129
129
  # set it if it is not already set
130
130
  headers["Date"] = received_at.httpdate
131
131
  received_at
@@ -1,3 +1,3 @@
1
1
  module HTTP
2
- VERSION = "0.8.3"
2
+ VERSION = "0.8.4"
3
3
  end
@@ -6,8 +6,8 @@ RSpec.describe HTTP::Cache do
6
6
  subject { described_class }
7
7
 
8
8
  it "allows metastore and entitystore" do
9
- expect(subject.new(:metastore => "heap:/", :entitystore => "heap:/"))
10
- .to be_kind_of HTTP::Cache
9
+ expect(subject.new(:metastore => "heap:/", :entitystore => "heap:/")).
10
+ to be_kind_of HTTP::Cache
11
11
  end
12
12
  end
13
13
 
@@ -151,10 +151,10 @@ RSpec.describe HTTP::Cache do
151
151
 
152
152
  it "makes request with conditional request headers" do
153
153
  subject.perform(request, opts) do |actual_request, _|
154
- expect(actual_request.headers["If-None-Match"])
155
- .to eq cached_response.headers["Etag"]
156
- expect(actual_request.headers["If-Modified-Since"])
157
- .to eq cached_response.headers["Last-Modified"]
154
+ expect(actual_request.headers["If-None-Match"]).
155
+ to eq cached_response.headers["Etag"]
156
+ expect(actual_request.headers["If-Modified-Since"]).
157
+ to eq cached_response.headers["Last-Modified"]
158
158
 
159
159
  origin_response
160
160
  end
@@ -60,8 +60,8 @@ RSpec.describe HTTP::Client do
60
60
  "http://example.com/" => redirect_response("/")
61
61
  )
62
62
 
63
- expect { client.get("http://example.com/") }
64
- .to raise_error(HTTP::Redirector::EndlessRedirectError)
63
+ expect { client.get("http://example.com/") }.
64
+ to raise_error(HTTP::Redirector::EndlessRedirectError)
65
65
  end
66
66
 
67
67
  it "fails if max amount of hops reached" do
@@ -75,8 +75,8 @@ RSpec.describe HTTP::Client do
75
75
  "http://example.com/6" => simple_response("OK")
76
76
  )
77
77
 
78
- expect { client.get("http://example.com/") }
79
- .to raise_error(HTTP::Redirector::TooManyRedirectsError)
78
+ expect { client.get("http://example.com/") }.
79
+ to raise_error(HTTP::Redirector::TooManyRedirectsError)
80
80
  end
81
81
 
82
82
  context "with non-ASCII URLs" do
@@ -103,17 +103,17 @@ RSpec.describe HTTP::Client do
103
103
  it "returns cached responses if they exist" do
104
104
  cached_response = simple_response("cached").caching
105
105
  StubbedClient.new(:cache =>
106
- HTTP::Cache.new(:metastore => "heap:/", :entitystore => "heap:/"))
107
- .stub("http://example.com/#{sn}" => cached_response)
108
- .get("http://example.com/#{sn}")
106
+ HTTP::Cache.new(:metastore => "heap:/", :entitystore => "heap:/")).
107
+ stub("http://example.com/#{sn}" => cached_response).
108
+ get("http://example.com/#{sn}")
109
109
 
110
110
  # cache is now warm
111
111
 
112
- client = StubbedClient.new(:cache => HTTP::Cache.new(:metastore => "heap:/", :entitystore => "heap:/"))
113
- .stub("http://example.com/#{sn}" => simple_response("OK"))
112
+ client = StubbedClient.new(:cache => HTTP::Cache.new(:metastore => "heap:/", :entitystore => "heap:/")).
113
+ stub("http://example.com/#{sn}" => simple_response("OK"))
114
114
 
115
- expect(client.get("http://example.com/#{sn}").body.to_s)
116
- .to eq cached_response.body.to_s
115
+ expect(client.get("http://example.com/#{sn}").body.to_s).
116
+ to eq cached_response.body.to_s
117
117
  end
118
118
  end
119
119
 
@@ -226,8 +226,8 @@ RSpec.describe HTTP::Client do
226
226
  end
227
227
 
228
228
  it "fails with OpenSSL::SSL::SSLError if host mismatch" do
229
- expect { client.get(dummy_ssl.endpoint.gsub("127.0.0.1", "localhost")) }
230
- .to raise_error(OpenSSL::SSL::SSLError, /does not match/)
229
+ expect { client.get(dummy_ssl.endpoint.gsub("127.0.0.1", "localhost")) }.
230
+ to raise_error(OpenSSL::SSL::SSLError, /does not match/)
231
231
  end
232
232
 
233
233
  context "with SSL options instead of a context" do
@@ -29,13 +29,13 @@ RSpec.describe HTTP::Headers do
29
29
  end
30
30
 
31
31
  it "fails with empty header name" do
32
- expect { headers.set "", "foo bar" }
33
- .to raise_error HTTP::InvalidHeaderNameError
32
+ expect { headers.set "", "foo bar" }.
33
+ to raise_error HTTP::InvalidHeaderNameError
34
34
  end
35
35
 
36
36
  it "fails with invalid header name" do
37
- expect { headers.set "foo bar", "baz" }
38
- .to raise_error HTTP::InvalidHeaderNameError
37
+ expect { headers.set "foo bar", "baz" }.
38
+ to raise_error HTTP::InvalidHeaderNameError
39
39
  end
40
40
  end
41
41
 
@@ -77,13 +77,13 @@ RSpec.describe HTTP::Headers do
77
77
  end
78
78
 
79
79
  it "fails with empty header name" do
80
- expect { headers.delete "" }
81
- .to raise_error HTTP::InvalidHeaderNameError
80
+ expect { headers.delete "" }.
81
+ to raise_error HTTP::InvalidHeaderNameError
82
82
  end
83
83
 
84
84
  it "fails with invalid header name" do
85
- expect { headers.delete "foo bar" }
86
- .to raise_error HTTP::InvalidHeaderNameError
85
+ expect { headers.delete "foo bar" }.
86
+ to raise_error HTTP::InvalidHeaderNameError
87
87
  end
88
88
  end
89
89
 
@@ -111,13 +111,13 @@ RSpec.describe HTTP::Headers do
111
111
  end
112
112
 
113
113
  it "fails with empty header name" do
114
- expect { headers.add "", "foobar" }
115
- .to raise_error HTTP::InvalidHeaderNameError
114
+ expect { headers.add "", "foobar" }.
115
+ to raise_error HTTP::InvalidHeaderNameError
116
116
  end
117
117
 
118
118
  it "fails with invalid header name" do
119
- expect { headers.add "foo bar", "baz" }
120
- .to raise_error HTTP::InvalidHeaderNameError
119
+ expect { headers.add "foo bar", "baz" }.
120
+ to raise_error HTTP::InvalidHeaderNameError
121
121
  end
122
122
  end
123
123
 
@@ -139,13 +139,13 @@ RSpec.describe HTTP::Headers do
139
139
  end
140
140
 
141
141
  it "fails with empty header name" do
142
- expect { headers.get "" }
143
- .to raise_error HTTP::InvalidHeaderNameError
142
+ expect { headers.get "" }.
143
+ to raise_error HTTP::InvalidHeaderNameError
144
144
  end
145
145
 
146
146
  it "fails with invalid header name" do
147
- expect { headers.get "foo bar" }
148
- .to raise_error HTTP::InvalidHeaderNameError
147
+ expect { headers.get "foo bar" }.
148
+ to raise_error HTTP::InvalidHeaderNameError
149
149
  end
150
150
  end
151
151
 
@@ -33,24 +33,24 @@ RSpec.describe HTTP::Redirector do
33
33
  req = HTTP::Request.new :head, "http://example.com"
34
34
  res = proc { |prev_req| redirect_response(301, "#{prev_req.uri}/1") }
35
35
 
36
- expect { redirector.perform(req, res.call(req), &res) }
37
- .to raise_error HTTP::Redirector::TooManyRedirectsError
36
+ expect { redirector.perform(req, res.call(req), &res) }.
37
+ to raise_error HTTP::Redirector::TooManyRedirectsError
38
38
  end
39
39
 
40
40
  it "fails with EndlessRedirectError if endless loop detected" do
41
41
  req = HTTP::Request.new :head, "http://example.com"
42
42
  res = redirect_response(301, req.uri)
43
43
 
44
- expect { redirector.perform(req, res) { res } }
45
- .to raise_error HTTP::Redirector::EndlessRedirectError
44
+ expect { redirector.perform(req, res) { res } }.
45
+ to raise_error HTTP::Redirector::EndlessRedirectError
46
46
  end
47
47
 
48
48
  it "fails with StateError if there were no Location header" do
49
49
  req = HTTP::Request.new :head, "http://example.com"
50
50
  res = simple_response(301)
51
51
 
52
- expect { |b| redirector.perform(req, res, &b) }
53
- .to raise_error HTTP::StateError
52
+ expect { |b| redirector.perform(req, res, &b) }.
53
+ to raise_error HTTP::StateError
54
54
  end
55
55
 
56
56
  it "returns first non-redirect response" do
@@ -86,24 +86,24 @@ RSpec.describe HTTP::Redirector do
86
86
  req = HTTP::Request.new :put, "http://example.com"
87
87
  res = redirect_response 300, "http://example.com/1"
88
88
 
89
- expect { redirector.perform(req, res) { simple_response 200 } }
90
- .to raise_error HTTP::StateError
89
+ expect { redirector.perform(req, res) { simple_response 200 } }.
90
+ to raise_error HTTP::StateError
91
91
  end
92
92
 
93
93
  it "raises StateError if original request was POST" do
94
94
  req = HTTP::Request.new :post, "http://example.com"
95
95
  res = redirect_response 300, "http://example.com/1"
96
96
 
97
- expect { redirector.perform(req, res) { simple_response 200 } }
98
- .to raise_error HTTP::StateError
97
+ expect { redirector.perform(req, res) { simple_response 200 } }.
98
+ to raise_error HTTP::StateError
99
99
  end
100
100
 
101
101
  it "raises StateError if original request was DELETE" do
102
102
  req = HTTP::Request.new :delete, "http://example.com"
103
103
  res = redirect_response 300, "http://example.com/1"
104
104
 
105
- expect { redirector.perform(req, res) { simple_response 200 } }
106
- .to raise_error HTTP::StateError
105
+ expect { redirector.perform(req, res) { simple_response 200 } }.
106
+ to raise_error HTTP::StateError
107
107
  end
108
108
  end
109
109
 
@@ -170,24 +170,24 @@ RSpec.describe HTTP::Redirector do
170
170
  req = HTTP::Request.new :put, "http://example.com"
171
171
  res = redirect_response 301, "http://example.com/1"
172
172
 
173
- expect { redirector.perform(req, res) { simple_response 200 } }
174
- .to raise_error HTTP::StateError
173
+ expect { redirector.perform(req, res) { simple_response 200 } }.
174
+ to raise_error HTTP::StateError
175
175
  end
176
176
 
177
177
  it "raises StateError if original request was POST" do
178
178
  req = HTTP::Request.new :post, "http://example.com"
179
179
  res = redirect_response 301, "http://example.com/1"
180
180
 
181
- expect { redirector.perform(req, res) { simple_response 200 } }
182
- .to raise_error HTTP::StateError
181
+ expect { redirector.perform(req, res) { simple_response 200 } }.
182
+ to raise_error HTTP::StateError
183
183
  end
184
184
 
185
185
  it "raises StateError if original request was DELETE" do
186
186
  req = HTTP::Request.new :delete, "http://example.com"
187
187
  res = redirect_response 301, "http://example.com/1"
188
188
 
189
- expect { redirector.perform(req, res) { simple_response 200 } }
190
- .to raise_error HTTP::StateError
189
+ expect { redirector.perform(req, res) { simple_response 200 } }.
190
+ to raise_error HTTP::StateError
191
191
  end
192
192
  end
193
193
 
@@ -254,24 +254,24 @@ RSpec.describe HTTP::Redirector do
254
254
  req = HTTP::Request.new :put, "http://example.com"
255
255
  res = redirect_response 302, "http://example.com/1"
256
256
 
257
- expect { redirector.perform(req, res) { simple_response 200 } }
258
- .to raise_error HTTP::StateError
257
+ expect { redirector.perform(req, res) { simple_response 200 } }.
258
+ to raise_error HTTP::StateError
259
259
  end
260
260
 
261
261
  it "raises StateError if original request was POST" do
262
262
  req = HTTP::Request.new :post, "http://example.com"
263
263
  res = redirect_response 302, "http://example.com/1"
264
264
 
265
- expect { redirector.perform(req, res) { simple_response 200 } }
266
- .to raise_error HTTP::StateError
265
+ expect { redirector.perform(req, res) { simple_response 200 } }.
266
+ to raise_error HTTP::StateError
267
267
  end
268
268
 
269
269
  it "raises StateError if original request was DELETE" do
270
270
  req = HTTP::Request.new :delete, "http://example.com"
271
271
  res = redirect_response 302, "http://example.com/1"
272
272
 
273
- expect { redirector.perform(req, res) { simple_response 200 } }
274
- .to raise_error HTTP::StateError
273
+ expect { redirector.perform(req, res) { simple_response 200 } }.
274
+ to raise_error HTTP::StateError
275
275
  end
276
276
  end
277
277
 
@@ -105,8 +105,8 @@ RSpec.describe HTTP::Response do
105
105
  body = double :to_s => "foobar"
106
106
  response = HTTP::Response.new(200, "1.1", headers, body)
107
107
 
108
- expect(response.inspect)
109
- .to eq '#<HTTP::Response/1.1 200 OK {"Content-Type"=>"text/plain"}>'
108
+ expect(response.inspect).
109
+ to eq '#<HTTP::Response/1.1 200 OK {"Content-Type"=>"text/plain"}>'
110
110
  end
111
111
  end
112
112
 
@@ -5,6 +5,11 @@ require "support/proxy_server"
5
5
 
6
6
  RSpec.describe HTTP do
7
7
  run_server(:dummy) { DummyServer.new }
8
+ run_server(:dummy_ssl) { DummyServer.new(:ssl => true) }
9
+
10
+ let(:ssl_client) do
11
+ HTTP::Client.new :ssl_context => SSLHelper.client_context
12
+ end
8
13
 
9
14
  context "getting resources" do
10
15
  it "is easy" do
@@ -63,6 +68,18 @@ RSpec.describe HTTP do
63
68
  response = HTTP.via(proxy.addr, proxy.port, "username", "password").get dummy.endpoint
64
69
  expect(response.to_s).to match(/<!doctype html>/)
65
70
  end
71
+
72
+ context "ssl" do
73
+ it "responds with the endpoint's body" do
74
+ response = ssl_client.via(proxy.addr, proxy.port).get dummy_ssl.endpoint
75
+ expect(response.to_s).to match(/<!doctype html>/)
76
+ end
77
+
78
+ it "ignores credentials" do
79
+ response = ssl_client.via(proxy.addr, proxy.port, "username", "password").get dummy_ssl.endpoint
80
+ expect(response.to_s).to match(/<!doctype html>/)
81
+ end
82
+ end
66
83
  end
67
84
 
68
85
  context "proxy with authentication" do
@@ -87,6 +104,23 @@ RSpec.describe HTTP do
87
104
  response = HTTP.via(proxy.addr, proxy.port).get dummy.endpoint
88
105
  expect(response.status).to eq(407)
89
106
  end
107
+
108
+ context "ssl" do
109
+ it "responds with the endpoint's body" do
110
+ response = ssl_client.via(proxy.addr, proxy.port, "username", "password").get dummy_ssl.endpoint
111
+ expect(response.to_s).to match(/<!doctype html>/)
112
+ end
113
+
114
+ it "responds with 407 when wrong credentials given" do
115
+ response = ssl_client.via(proxy.addr, proxy.port, "user", "pass").get dummy_ssl.endpoint
116
+ expect(response.status).to eq(407)
117
+ end
118
+
119
+ it "responds with 407 if no credentials given" do
120
+ response = ssl_client.via(proxy.addr, proxy.port).get dummy_ssl.endpoint
121
+ expect(response.status).to eq(407)
122
+ end
123
+ end
90
124
  end
91
125
  end
92
126
 
@@ -151,15 +185,15 @@ RSpec.describe HTTP do
151
185
 
152
186
  it "sets Authorization header with proper BasicAuth value" do
153
187
  client = HTTP.basic_auth :user => "foo", :pass => "bar"
154
- expect(client.default_headers[:authorization])
155
- .to match(%r{^Basic [A-Za-z0-9+/]+=*$})
188
+ expect(client.default_headers[:authorization]).
189
+ to match(%r{^Basic [A-Za-z0-9+/]+=*$})
156
190
  end
157
191
  end
158
192
 
159
- describe ".with_cache" do
193
+ describe ".cache" do
160
194
  it "sets cache option" do
161
195
  cache = double(:cache, :perform => nil)
162
- client = HTTP.with_cache cache
196
+ client = HTTP.cache cache
163
197
  expect(client.default_options[:cache]).to eq cache
164
198
  end
165
199
  end
@@ -82,8 +82,8 @@ RSpec.shared_context "HTTP handling" do
82
82
  end
83
83
 
84
84
  it "errors if reading takes too long" do
85
- expect { client.get("#{server.endpoint}/sleep").body.to_s }
86
- .to raise_error(HTTP::TimeoutError, /Timed out/)
85
+ expect { client.get("#{server.endpoint}/sleep").body.to_s }.
86
+ to raise_error(HTTP::TimeoutError, /Timed out/)
87
87
  end
88
88
  end
89
89
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: http
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.3
4
+ version: 0.8.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tony Arcieri
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2015-04-07 00:00:00.000000000 Z
13
+ date: 2015-04-23 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: http_parser.rb
@@ -180,9 +180,45 @@ required_rubygems_version: !ruby/object:Gem::Requirement
180
180
  version: '0'
181
181
  requirements: []
182
182
  rubyforge_project:
183
- rubygems_version: 2.2.2
183
+ rubygems_version: 2.4.5
184
184
  signing_key:
185
185
  specification_version: 4
186
186
  summary: HTTP should be easy
187
- test_files: []
187
+ test_files:
188
+ - spec/lib/http/cache/headers_spec.rb
189
+ - spec/lib/http/cache_spec.rb
190
+ - spec/lib/http/client_spec.rb
191
+ - spec/lib/http/content_type_spec.rb
192
+ - spec/lib/http/headers/mixin_spec.rb
193
+ - spec/lib/http/headers_spec.rb
194
+ - spec/lib/http/options/body_spec.rb
195
+ - spec/lib/http/options/form_spec.rb
196
+ - spec/lib/http/options/headers_spec.rb
197
+ - spec/lib/http/options/json_spec.rb
198
+ - spec/lib/http/options/merge_spec.rb
199
+ - spec/lib/http/options/new_spec.rb
200
+ - spec/lib/http/options/proxy_spec.rb
201
+ - spec/lib/http/options_spec.rb
202
+ - spec/lib/http/redirector_spec.rb
203
+ - spec/lib/http/request/caching_spec.rb
204
+ - spec/lib/http/request/writer_spec.rb
205
+ - spec/lib/http/request_spec.rb
206
+ - spec/lib/http/response/body_spec.rb
207
+ - spec/lib/http/response/caching_spec.rb
208
+ - spec/lib/http/response/io_body_spec.rb
209
+ - spec/lib/http/response/status_spec.rb
210
+ - spec/lib/http/response/string_body_spec.rb
211
+ - spec/lib/http/response_spec.rb
212
+ - spec/lib/http_spec.rb
213
+ - spec/spec_helper.rb
214
+ - spec/support/black_hole.rb
215
+ - spec/support/capture_warning.rb
216
+ - spec/support/connection_reuse_shared.rb
217
+ - spec/support/dummy_server.rb
218
+ - spec/support/dummy_server/servlet.rb
219
+ - spec/support/http_handling_shared.rb
220
+ - spec/support/proxy_server.rb
221
+ - spec/support/servers/config.rb
222
+ - spec/support/servers/runner.rb
223
+ - spec/support/ssl_helper.rb
188
224
  has_rdoc: