http 0.8.0.pre5 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cfd83e5db031e7c10a162574f2c700e879b66ea1
4
- data.tar.gz: 3bcb6718bb90463c39ac0170482c86fe04f59da9
3
+ metadata.gz: ca4f83715e058d0fd9d76333e0acc15ef369ad0c
4
+ data.tar.gz: c040a30b4733d5438368e83c21bfc7d83ebc20f9
5
5
  SHA512:
6
- metadata.gz: f1b99fd432ba3b1cb7e0ec555796d86d75029543148d8f1a8f0e7fd3d49f898fef0b0dc2afee46fb7eb38add8aa803266b212cfc5b4941d2aa88ea220c938dae
7
- data.tar.gz: 8594e4e915ea23e9646d0b3e335b733bf74be8af488a6fe15ff458c3edc1eb70ac3821abcab551afa4e419e4d301ddc13b1bee2c9623eb293683b694963bb106
6
+ metadata.gz: f10c3683cb13697bb8be4aa893041cfca2f823d5df98e3259a2cac238ab69721e4d3ddc5e68bd524301f3be6cfbc5c7cf266a36baf356396685fac4f253a56ff
7
+ data.tar.gz: 67ca53156ac393947f01e3e4e4620856f57751c5a85a64645d621779627a0dcf752e43995ae0ff1d3ee1a19975fa63de0d0573a939912e7971f3609915e17d2c
data/CHANGES.md CHANGED
@@ -1,9 +1,13 @@
1
- ## 0.8.0.pre5 (2015-03-27)
1
+ ## 0.8.0 (2015-04-01)
2
2
 
3
+ * Properly handle WaitWritable for SSL. See #199. (@zanker)
4
+ * Add support for non-ASCII URis. See #197. (@ixti)
5
+ * Add configurable connection timeouts. See #187, #194, #195. (@zanker)
6
+ * Refactor requests redirect following logic. See #179. (@ixti)
3
7
  * Support for persistent HTTP connections (@zanker)
4
8
  * Add caching support. See #77 and #177. (@Asmod4n, @pezra)
5
9
  * Improve servers used in specs boot up. Issue was initially raised up
6
- by @olegkovalenko. See #176.
10
+ by @olegkovalenko. See #176. (@ixti)
7
11
  * Reflect FormData rename changes (FormData -> HTTP::FormData). (@ixti)
8
12
  * `HTTP::Headers` now raises `HTTP::InvalidHeaderNameError` in case of
9
13
  (surprise) invalid HTTP header field name (e.g.`"Foo:Bar"`). See #173.
@@ -23,7 +23,8 @@ Gem::Specification.new do |gem|
23
23
  gem.version = HTTP::VERSION
24
24
 
25
25
  gem.add_runtime_dependency "http_parser.rb", "~> 0.6.0"
26
- gem.add_runtime_dependency "http-form_data", "~> 1.0.0"
26
+ gem.add_runtime_dependency "http-form_data", "~> 1.0.1"
27
+ gem.add_runtime_dependency "addressable", "~> 2.3"
27
28
 
28
29
  gem.add_development_dependency "bundler", "~> 1.0"
29
30
  end
@@ -1,9 +1,11 @@
1
1
  require "cgi"
2
2
  require "uri"
3
+
3
4
  require "http/form_data"
4
5
  require "http/options"
5
6
  require "http/connection"
6
7
  require "http/redirector"
8
+ require "http/uri"
7
9
 
8
10
  module HTTP
9
11
  # Clients make requests and receive responses
@@ -14,6 +16,8 @@ module HTTP
14
16
  KEEP_ALIVE = "Keep-Alive".freeze
15
17
  CLOSE = "close".freeze
16
18
 
19
+ HTTP_OR_HTTPS_RE = %r{^https?://}i
20
+
17
21
  attr_reader :default_options
18
22
 
19
23
  def initialize(default_options = {})
@@ -109,33 +113,25 @@ module HTTP
109
113
 
110
114
  # Strips out query/path to give us a consistent way of comparing hosts
111
115
  def base_host(uri)
112
- base = uri.dup
113
- base.query = nil
114
- base.path = ""
115
- base.to_s
116
+ uri.omit(:query, :path).to_s
116
117
  end
117
118
 
118
119
  # Merges query params if needed
120
+ #
121
+ # @param [#to_s] uri
122
+ # @return [URI]
119
123
  def make_request_uri(uri, options)
120
- uri = normalize_uri uri
124
+ uri = uri.to_s
121
125
 
122
- if options.params && !options.params.empty?
123
- params = CGI.parse(uri.query.to_s).merge(options.params || {})
124
- uri.query = URI.encode_www_form params
126
+ if default_options.persistent? && uri !~ HTTP_OR_HTTPS_RE
127
+ uri = "#{default_options.persistent}#{uri}"
125
128
  end
126
129
 
127
- uri
128
- end
130
+ uri = HTTP::URI.parse uri
129
131
 
130
- # Normalize URI
131
- #
132
- # @param [#to_s] uri
133
- # @return [URI]
134
- def normalize_uri(uri)
135
- if default_options.persistent? && uri !~ /^http|https/
136
- uri = URI("#{default_options.persistent}#{uri}")
137
- else
138
- uri = URI(uri.to_s)
132
+ if options.params && !options.params.empty?
133
+ params = CGI.parse(uri.query.to_s).merge(options.params || {})
134
+ uri.query = ::URI.encode_www_form params
139
135
  end
140
136
 
141
137
  # Some proxies (seen on WEBRick) fail if URL has
@@ -129,7 +129,7 @@ module HTTP
129
129
  # @param (see #initialize)
130
130
  # @return [void]
131
131
  def start_tls(req, options)
132
- return unless req.uri.is_a?(URI::HTTPS) && !req.using_proxy?
132
+ return unless req.uri.https? && !req.using_proxy?
133
133
 
134
134
  ssl_context = options[:ssl_context]
135
135
 
@@ -1,14 +1,18 @@
1
+ require "forwardable"
2
+ require "base64"
3
+ require "time"
4
+
1
5
  require "http/errors"
2
6
  require "http/headers"
3
7
  require "http/request/caching"
4
8
  require "http/request/writer"
5
9
  require "http/version"
6
- require "base64"
7
- require "uri"
8
- require "time"
10
+ require "http/uri"
9
11
 
10
12
  module HTTP
11
13
  class Request
14
+ extend Forwardable
15
+
12
16
  include HTTP::Headers::Mixin
13
17
 
14
18
  # The method given was not understood
@@ -70,7 +74,7 @@ module HTTP
70
74
  # :nodoc:
71
75
  def initialize(verb, uri, headers = {}, proxy = {}, body = nil, version = "1.1") # rubocop:disable ParameterLists
72
76
  @verb = verb.to_s.downcase.to_sym
73
- @uri = uri.is_a?(URI) ? uri : URI(uri.to_s)
77
+ @uri = HTTP::URI.parse uri
74
78
  @scheme = @uri.scheme && @uri.scheme.to_s.downcase.to_sym
75
79
 
76
80
  fail(UnsupportedMethodError, "unknown method: #{verb}") unless METHODS.include?(@verb)
@@ -80,14 +84,13 @@ module HTTP
80
84
 
81
85
  @headers = HTTP::Headers.coerce(headers || {})
82
86
 
83
- @headers["Host"] ||= default_host
87
+ @headers["Host"] ||= default_host_header_value
84
88
  @headers["User-Agent"] ||= USER_AGENT
85
89
  end
86
90
 
87
91
  # Returns new Request with updated uri
88
92
  def redirect(uri, verb = @verb)
89
- uri = @uri.merge uri.to_s
90
- req = self.class.new(verb, uri, headers, proxy, body, version)
93
+ req = self.class.new(verb, @uri.join(uri), headers, proxy, body, version)
91
94
  req["Host"] = req.uri.host
92
95
  req
93
96
  end
@@ -116,17 +119,17 @@ module HTTP
116
119
 
117
120
  # Compute HTTP request header for direct or proxy request
118
121
  def request_header
119
- "#{verb.to_s.upcase} #{path_for_request_header} HTTP/#{version}"
122
+ "#{verb.to_s.upcase} #{uri.normalize} HTTP/#{version}"
120
123
  end
121
124
 
122
125
  # Host for tcp socket
123
126
  def socket_host
124
- using_proxy? ? proxy[:proxy_address] : uri.host
127
+ using_proxy? ? proxy[:proxy_address] : host
125
128
  end
126
129
 
127
130
  # Port for tcp socket
128
131
  def socket_port
129
- using_proxy? ? proxy[:proxy_port] : uri.port
132
+ using_proxy? ? proxy[:proxy_port] : port
130
133
  end
131
134
 
132
135
  # @return [HTTP::Request::Caching]
@@ -136,32 +139,19 @@ module HTTP
136
139
 
137
140
  private
138
141
 
139
- def path_for_request_header
140
- if using_proxy?
141
- uri
142
- else
143
- uri_path_with_query
144
- end
145
- end
146
-
147
- def uri_path_with_query
148
- path = uri_has_query? ? "#{uri.path}?#{uri.query}" : uri.path
149
- path.empty? ? "/" : path
150
- end
142
+ # @!attribute [r] host
143
+ # @return [String]
144
+ def_delegator :@uri, :host
151
145
 
152
- def uri_has_query?
153
- uri.query && !uri.query.empty?
146
+ # @!attribute [r] port
147
+ # @return [Fixnum]
148
+ def port
149
+ @uri.port || @uri.default_port
154
150
  end
155
151
 
156
- # Default host (with port if needed) header value.
157
- #
158
- # @return [String]
159
- def default_host
160
- if PORTS[@scheme] == @uri.port
161
- @uri.host
162
- else
163
- "#{@uri.host}:#{@uri.port}"
164
- end
152
+ # @return [String] Default host (with port if needed) header value.
153
+ def default_host_header_value
154
+ PORTS[@scheme] != port ? "#{host}:#{port}" : host
165
155
  end
166
156
  end
167
157
  end
@@ -0,0 +1,23 @@
1
+ require "addressable/uri"
2
+
3
+ module HTTP
4
+ class URI < Addressable::URI
5
+ # HTTP scheme
6
+ HTTP_SCHEME = "http".freeze
7
+
8
+ # HTTPS scheme
9
+ HTTPS_SCHEME = "https".freeze
10
+
11
+ # @return [True] if URI is HTTP
12
+ # @return [False] otherwise
13
+ def http?
14
+ HTTP_SCHEME == scheme
15
+ end
16
+
17
+ # @return [True] if URI is HTTPS
18
+ # @return [False] otherwise
19
+ def https?
20
+ HTTPS_SCHEME == scheme
21
+ end
22
+ end
23
+ end
@@ -1,3 +1,3 @@
1
1
  module HTTP
2
- VERSION = "0.8.0.pre5"
2
+ VERSION = "0.8.0"
3
3
  end
@@ -1,3 +1,5 @@
1
+ # coding: utf-8
2
+
1
3
  require "support/http_handling_shared"
2
4
  require "support/dummy_server"
3
5
  require "support/ssl_helper"
@@ -9,7 +11,7 @@ RSpec.describe HTTP::Client do
9
11
 
10
12
  StubbedClient = Class.new(HTTP::Client) do
11
13
  def make_request(request, options)
12
- stubs.fetch(request.uri.to_s) { super(request, options) }
14
+ stubs.fetch(request.uri) { super(request, options) }
13
15
  end
14
16
 
15
17
  def stubs
@@ -17,7 +19,10 @@ RSpec.describe HTTP::Client do
17
19
  end
18
20
 
19
21
  def stub(stubs)
20
- @stubs = stubs
22
+ @stubs = stubs.each_with_object({}) do |(k, v), o|
23
+ o[HTTP::URI.parse k] = v
24
+ end
25
+
21
26
  self
22
27
  end
23
28
  end
@@ -73,6 +78,23 @@ RSpec.describe HTTP::Client do
73
78
  expect { client.get("http://example.com/") }
74
79
  .to raise_error(HTTP::Redirector::TooManyRedirectsError)
75
80
  end
81
+
82
+ context "with non-ASCII URLs" do
83
+ it "theoretically works like a charm" do
84
+ client = StubbedClient.new(:follow => true).stub(
85
+ "http://example.com/" => redirect_response("/könig"),
86
+ "http://example.com/könig" => simple_response("OK")
87
+ )
88
+
89
+ expect { client.get "http://example.com/könig" }.not_to raise_error
90
+ end
91
+
92
+ it "works like a charm in real world" do
93
+ url = "http://git.io/jNeY"
94
+ client = HTTP.follow
95
+ expect(client.get(url).to_s).to include "support for non-ascii URIs"
96
+ end
97
+ end
76
98
  end
77
99
 
78
100
  describe "caching" do
@@ -154,6 +176,19 @@ RSpec.describe HTTP::Client do
154
176
  end
155
177
 
156
178
  describe "#request" do
179
+ context "with non-ASCII URLs" do
180
+ it "theoretically works like a charm" do
181
+ client = described_class.new
182
+ expect { client.get "#{dummy.endpoint}/könig" }.not_to raise_error
183
+ end
184
+
185
+ it "works like a charm in real world" do
186
+ url = "https://github.com/httprb/http.rb/pull/197/ö無"
187
+ client = HTTP.follow
188
+ expect(client.get(url).to_s).to include "support for non-ascii URIs"
189
+ end
190
+ end
191
+
157
192
  context "with explicitly given `Host` header" do
158
193
  let(:headers) { {"Host" => "another.example.com"} }
159
194
  let(:client) { described_class.new :headers => headers }
@@ -71,7 +71,7 @@ RSpec.describe HTTP::Request do
71
71
 
72
72
  subject(:redirected) { request.redirect "http://blog.example.com/" }
73
73
 
74
- its(:uri) { is_expected.to eq URI.parse "http://blog.example.com/" }
74
+ its(:uri) { is_expected.to eq HTTP::URI.parse "http://blog.example.com/" }
75
75
 
76
76
  its(:verb) { is_expected.to eq request.verb }
77
77
  its(:body) { is_expected.to eq request.body }
@@ -84,7 +84,7 @@ RSpec.describe HTTP::Request do
84
84
  context "with schema-less absolute URL given" do
85
85
  subject(:redirected) { request.redirect "//another.example.com/blog" }
86
86
 
87
- its(:uri) { is_expected.to eq URI.parse "http://another.example.com/blog" }
87
+ its(:uri) { is_expected.to eq HTTP::URI.parse "http://another.example.com/blog" }
88
88
 
89
89
  its(:verb) { is_expected.to eq request.verb }
90
90
  its(:body) { is_expected.to eq request.body }
@@ -98,7 +98,7 @@ RSpec.describe HTTP::Request do
98
98
  context "with relative URL given" do
99
99
  subject(:redirected) { request.redirect "/blog" }
100
100
 
101
- its(:uri) { is_expected.to eq URI.parse "http://example.com/blog" }
101
+ its(:uri) { is_expected.to eq HTTP::URI.parse "http://example.com/blog" }
102
102
 
103
103
  its(:verb) { is_expected.to eq request.verb }
104
104
  its(:body) { is_expected.to eq request.body }
@@ -110,14 +110,14 @@ RSpec.describe HTTP::Request do
110
110
 
111
111
  context "with original URI having non-standard port" do
112
112
  let(:request) { HTTP::Request.new(:post, "http://example.com:8080/", headers, proxy, body) }
113
- its(:uri) { is_expected.to eq URI.parse "http://example.com:8080/blog" }
113
+ its(:uri) { is_expected.to eq HTTP::URI.parse "http://example.com:8080/blog" }
114
114
  end
115
115
  end
116
116
 
117
117
  context "with relative URL that misses leading slash given" do
118
118
  subject(:redirected) { request.redirect "blog" }
119
119
 
120
- its(:uri) { is_expected.to eq URI.parse "http://example.com/blog" }
120
+ its(:uri) { is_expected.to eq HTTP::URI.parse "http://example.com/blog" }
121
121
 
122
122
  its(:verb) { is_expected.to eq request.verb }
123
123
  its(:body) { is_expected.to eq request.body }
@@ -129,7 +129,7 @@ RSpec.describe HTTP::Request do
129
129
 
130
130
  context "with original URI having non-standard port" do
131
131
  let(:request) { HTTP::Request.new(:post, "http://example.com:8080/", headers, proxy, body) }
132
- its(:uri) { is_expected.to eq URI.parse "http://example.com:8080/blog" }
132
+ its(:uri) { is_expected.to eq HTTP::URI.parse "http://example.com:8080/blog" }
133
133
  end
134
134
  end
135
135
 
@@ -14,7 +14,7 @@ RSpec.describe HTTP do
14
14
 
15
15
  context "with URI instance" do
16
16
  it "is easy" do
17
- response = HTTP.get URI dummy.endpoint
17
+ response = HTTP.get HTTP::URI.parse dummy.endpoint
18
18
  expect(response.to_s).to match(/<!doctype html>/)
19
19
  end
20
20
  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.0.pre5
4
+ version: 0.8.0
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-03-31 00:00:00.000000000 Z
13
+ date: 2015-04-01 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: http_parser.rb
@@ -32,14 +32,28 @@ dependencies:
32
32
  requirements:
33
33
  - - "~>"
34
34
  - !ruby/object:Gem::Version
35
- version: 1.0.0
35
+ version: 1.0.1
36
36
  type: :runtime
37
37
  prerelease: false
38
38
  version_requirements: !ruby/object:Gem::Requirement
39
39
  requirements:
40
40
  - - "~>"
41
41
  - !ruby/object:Gem::Version
42
- version: 1.0.0
42
+ version: 1.0.1
43
+ - !ruby/object:Gem::Dependency
44
+ name: addressable
45
+ requirement: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '2.3'
50
+ type: :runtime
51
+ prerelease: false
52
+ version_requirements: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - "~>"
55
+ - !ruby/object:Gem::Version
56
+ version: '2.3'
43
57
  - !ruby/object:Gem::Dependency
44
58
  name: bundler
45
59
  requirement: !ruby/object:Gem::Requirement
@@ -107,6 +121,7 @@ files:
107
121
  - lib/http/timeout/global.rb
108
122
  - lib/http/timeout/null.rb
109
123
  - lib/http/timeout/per_operation.rb
124
+ - lib/http/uri.rb
110
125
  - lib/http/version.rb
111
126
  - logo.png
112
127
  - spec/lib/http/cache/headers_spec.rb
@@ -160,50 +175,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
160
175
  version: '0'
161
176
  required_rubygems_version: !ruby/object:Gem::Requirement
162
177
  requirements:
163
- - - ">"
178
+ - - ">="
164
179
  - !ruby/object:Gem::Version
165
- version: 1.3.1
180
+ version: '0'
166
181
  requirements: []
167
182
  rubyforge_project:
168
- rubygems_version: 2.4.5
183
+ rubygems_version: 2.2.2
169
184
  signing_key:
170
185
  specification_version: 4
171
186
  summary: HTTP should be easy
172
- test_files:
173
- - spec/lib/http/cache/headers_spec.rb
174
- - spec/lib/http/cache_spec.rb
175
- - spec/lib/http/client_spec.rb
176
- - spec/lib/http/content_type_spec.rb
177
- - spec/lib/http/headers/mixin_spec.rb
178
- - spec/lib/http/headers_spec.rb
179
- - spec/lib/http/options/body_spec.rb
180
- - spec/lib/http/options/form_spec.rb
181
- - spec/lib/http/options/headers_spec.rb
182
- - spec/lib/http/options/json_spec.rb
183
- - spec/lib/http/options/merge_spec.rb
184
- - spec/lib/http/options/new_spec.rb
185
- - spec/lib/http/options/proxy_spec.rb
186
- - spec/lib/http/options_spec.rb
187
- - spec/lib/http/redirector_spec.rb
188
- - spec/lib/http/request/caching_spec.rb
189
- - spec/lib/http/request/writer_spec.rb
190
- - spec/lib/http/request_spec.rb
191
- - spec/lib/http/response/body_spec.rb
192
- - spec/lib/http/response/caching_spec.rb
193
- - spec/lib/http/response/io_body_spec.rb
194
- - spec/lib/http/response/status_spec.rb
195
- - spec/lib/http/response/string_body_spec.rb
196
- - spec/lib/http/response_spec.rb
197
- - spec/lib/http_spec.rb
198
- - spec/spec_helper.rb
199
- - spec/support/black_hole.rb
200
- - spec/support/capture_warning.rb
201
- - spec/support/connection_reuse_shared.rb
202
- - spec/support/dummy_server.rb
203
- - spec/support/dummy_server/servlet.rb
204
- - spec/support/http_handling_shared.rb
205
- - spec/support/proxy_server.rb
206
- - spec/support/servers/config.rb
207
- - spec/support/servers/runner.rb
208
- - spec/support/ssl_helper.rb
187
+ test_files: []
209
188
  has_rdoc: