http 0.8.0.pre5 → 0.8.0

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