http 0.8.14 → 0.9.0.pre
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 +4 -4
- data/CHANGES.md +3 -7
- data/Gemfile +3 -6
- data/README.md +12 -22
- data/lib/http/chainable.rb +0 -8
- data/lib/http/client.rb +9 -11
- data/lib/http/errors.rb +0 -3
- data/lib/http/options.rb +12 -27
- data/lib/http/request.rb +2 -21
- data/lib/http/response.rb +0 -6
- data/lib/http/timeout/null.rb +24 -1
- data/lib/http/timeout/per_operation.rb +8 -24
- data/lib/http/uri.rb +2 -7
- data/lib/http/version.rb +1 -1
- data/spec/lib/http/client_spec.rb +1 -31
- data/spec/lib/http/options/merge_spec.rb +0 -1
- data/spec/lib/http/request_spec.rb +2 -7
- data/spec/lib/http/response_spec.rb +0 -5
- data/spec/lib/http_spec.rb +0 -8
- data/spec/spec_helper.rb +5 -0
- data/spec/support/connection_reuse_shared.rb +2 -0
- data/spec/support/http_handling_shared.rb +7 -0
- metadata +36 -19
- data/lib/http/cache.rb +0 -146
- data/lib/http/cache/headers.rb +0 -100
- data/lib/http/cache/null_cache.rb +0 -13
- data/lib/http/request/caching.rb +0 -95
- data/lib/http/response/caching.rb +0 -143
- data/lib/http/response/io_body.rb +0 -63
- data/lib/http/response/string_body.rb +0 -53
- data/spec/lib/http/cache/headers_spec.rb +0 -77
- data/spec/lib/http/cache_spec.rb +0 -182
- data/spec/lib/http/request/caching_spec.rb +0 -133
- data/spec/lib/http/response/caching_spec.rb +0 -201
- data/spec/lib/http/response/io_body_spec.rb +0 -35
- data/spec/lib/http/response/string_body_spec.rb +0 -35
@@ -55,7 +55,6 @@ RSpec.describe HTTP::Options, "merge" do
|
|
55
55
|
:socket_class => described_class.default_socket_class,
|
56
56
|
:ssl_socket_class => described_class.default_ssl_socket_class,
|
57
57
|
:ssl_context => nil,
|
58
|
-
:cache => described_class.default_cache,
|
59
58
|
:cookies => {})
|
60
59
|
end
|
61
60
|
end
|
@@ -133,19 +133,14 @@ RSpec.describe HTTP::Request do
|
|
133
133
|
end
|
134
134
|
end
|
135
135
|
|
136
|
-
describe "#caching" do
|
137
|
-
subject { request.caching }
|
138
|
-
it { is_expected.to be_a HTTP::Request::Caching }
|
139
|
-
end
|
140
|
-
|
141
136
|
describe "#headline" do
|
142
137
|
subject { request.headline }
|
143
138
|
|
144
|
-
it { is_expected.to eq "GET /foo?bar=baz HTTP/1.1" }
|
139
|
+
it { is_expected.to eq "GET /foo?bar=baz#moo HTTP/1.1" }
|
145
140
|
|
146
141
|
context "with proxy" do
|
147
142
|
let(:proxy) { {:user => "user", :pass => "pass"} }
|
148
|
-
it { is_expected.to eq "GET http://example.com/foo?bar=baz HTTP/1.1" }
|
143
|
+
it { is_expected.to eq "GET http://example.com/foo?bar=baz#moo HTTP/1.1" }
|
149
144
|
end
|
150
145
|
end
|
151
146
|
end
|
@@ -109,11 +109,6 @@ RSpec.describe HTTP::Response do
|
|
109
109
|
end
|
110
110
|
end
|
111
111
|
|
112
|
-
describe "#caching" do
|
113
|
-
subject { response.caching }
|
114
|
-
it { is_expected.to be_a HTTP::Response::Caching }
|
115
|
-
end
|
116
|
-
|
117
112
|
describe "#cookies" do
|
118
113
|
let(:cookies) { ["a=1", "b=2; domain=example.com", "c=3; domain=bad.org"] }
|
119
114
|
let(:headers) { {"Set-Cookie" => cookies} }
|
data/spec/lib/http_spec.rb
CHANGED
@@ -204,14 +204,6 @@ RSpec.describe HTTP do
|
|
204
204
|
end
|
205
205
|
end
|
206
206
|
|
207
|
-
describe ".cache" do
|
208
|
-
it "sets cache option" do
|
209
|
-
cache = double(:cache, :perform => nil)
|
210
|
-
client = HTTP.cache cache
|
211
|
-
expect(client.default_options[:cache]).to eq cache
|
212
|
-
end
|
213
|
-
end
|
214
|
-
|
215
207
|
describe ".persistent" do
|
216
208
|
let(:host) { "https://api.github.com" }
|
217
209
|
|
data/spec/spec_helper.rb
CHANGED
@@ -17,6 +17,11 @@ require "http"
|
|
17
17
|
require "rspec/its"
|
18
18
|
require "support/capture_warning"
|
19
19
|
|
20
|
+
# Are we in a flaky environment?
|
21
|
+
def flaky_env?
|
22
|
+
defined?(JRUBY_VERSION) && ENV["CI"]
|
23
|
+
end
|
24
|
+
|
20
25
|
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
21
26
|
RSpec.configure do |config|
|
22
27
|
config.expect_with :rspec do |expectations|
|
@@ -42,6 +42,8 @@ RSpec.shared_context "handles shared connections" do
|
|
42
42
|
|
43
43
|
context "with a socket issue" do
|
44
44
|
it "transparently reopens" do
|
45
|
+
skip "flaky environment" if flaky_env?
|
46
|
+
|
45
47
|
first_socket = client.get("#{server.endpoint}/socket").body.to_s
|
46
48
|
expect(first_socket).to_not eq("")
|
47
49
|
|
@@ -50,6 +50,7 @@ RSpec.shared_context "HTTP handling" do
|
|
50
50
|
let(:read_timeout) { 0 }
|
51
51
|
|
52
52
|
it "times out" do
|
53
|
+
skip "flaky environment" if flaky_env?
|
53
54
|
expect { response }.to raise_error(HTTP::TimeoutError, /Read/i)
|
54
55
|
end
|
55
56
|
end
|
@@ -123,6 +124,8 @@ RSpec.shared_context "HTTP handling" do
|
|
123
124
|
|
124
125
|
context "on a mixed state" do
|
125
126
|
it "re-opens the connection" do
|
127
|
+
skip "flaky environment" if flaky_env?
|
128
|
+
|
126
129
|
first_socket_id = client.get("#{server.endpoint}/socket/1").body.to_s
|
127
130
|
|
128
131
|
client.instance_variable_set(:@state, :dirty)
|
@@ -154,6 +157,8 @@ RSpec.shared_context "HTTP handling" do
|
|
154
157
|
|
155
158
|
context "with a socket issue" do
|
156
159
|
it "transparently reopens" do
|
160
|
+
skip "flaky environment" if flaky_env?
|
161
|
+
|
157
162
|
first_socket_id = client.get("#{server.endpoint}/socket").body.to_s
|
158
163
|
expect(first_socket_id).to_not eq("")
|
159
164
|
# Kill off the sockets we used
|
@@ -184,6 +189,8 @@ RSpec.shared_context "HTTP handling" do
|
|
184
189
|
let(:options) { {} }
|
185
190
|
|
186
191
|
it "opens new sockets" do
|
192
|
+
skip "flaky environment" if flaky_env?
|
193
|
+
|
187
194
|
expect(sockets_used).to_not include("")
|
188
195
|
expect(sockets_used.uniq.length).to eq(2)
|
189
196
|
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.
|
4
|
+
version: 0.9.0.pre
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tony Arcieri
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2015-
|
14
|
+
date: 2015-07-22 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: http_parser.rb
|
@@ -107,9 +107,6 @@ files:
|
|
107
107
|
- examples/parallel_requests_with_celluloid.rb
|
108
108
|
- http.gemspec
|
109
109
|
- lib/http.rb
|
110
|
-
- lib/http/cache.rb
|
111
|
-
- lib/http/cache/headers.rb
|
112
|
-
- lib/http/cache/null_cache.rb
|
113
110
|
- lib/http/chainable.rb
|
114
111
|
- lib/http/client.rb
|
115
112
|
- lib/http/connection.rb
|
@@ -124,24 +121,18 @@ files:
|
|
124
121
|
- lib/http/options.rb
|
125
122
|
- lib/http/redirector.rb
|
126
123
|
- lib/http/request.rb
|
127
|
-
- lib/http/request/caching.rb
|
128
124
|
- lib/http/request/writer.rb
|
129
125
|
- lib/http/response.rb
|
130
126
|
- lib/http/response/body.rb
|
131
|
-
- lib/http/response/caching.rb
|
132
|
-
- lib/http/response/io_body.rb
|
133
127
|
- lib/http/response/parser.rb
|
134
128
|
- lib/http/response/status.rb
|
135
129
|
- lib/http/response/status/reasons.rb
|
136
|
-
- lib/http/response/string_body.rb
|
137
130
|
- lib/http/timeout/global.rb
|
138
131
|
- lib/http/timeout/null.rb
|
139
132
|
- lib/http/timeout/per_operation.rb
|
140
133
|
- lib/http/uri.rb
|
141
134
|
- lib/http/version.rb
|
142
135
|
- logo.png
|
143
|
-
- spec/lib/http/cache/headers_spec.rb
|
144
|
-
- spec/lib/http/cache_spec.rb
|
145
136
|
- spec/lib/http/client_spec.rb
|
146
137
|
- spec/lib/http/content_type_spec.rb
|
147
138
|
- spec/lib/http/headers/mixin_spec.rb
|
@@ -155,14 +146,10 @@ files:
|
|
155
146
|
- spec/lib/http/options/proxy_spec.rb
|
156
147
|
- spec/lib/http/options_spec.rb
|
157
148
|
- spec/lib/http/redirector_spec.rb
|
158
|
-
- spec/lib/http/request/caching_spec.rb
|
159
149
|
- spec/lib/http/request/writer_spec.rb
|
160
150
|
- spec/lib/http/request_spec.rb
|
161
151
|
- spec/lib/http/response/body_spec.rb
|
162
|
-
- spec/lib/http/response/caching_spec.rb
|
163
|
-
- spec/lib/http/response/io_body_spec.rb
|
164
152
|
- spec/lib/http/response/status_spec.rb
|
165
|
-
- spec/lib/http/response/string_body_spec.rb
|
166
153
|
- spec/lib/http/response_spec.rb
|
167
154
|
- spec/lib/http_spec.rb
|
168
155
|
- spec/spec_helper.rb
|
@@ -191,14 +178,44 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
191
178
|
version: '0'
|
192
179
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
193
180
|
requirements:
|
194
|
-
- - "
|
181
|
+
- - ">"
|
195
182
|
- !ruby/object:Gem::Version
|
196
|
-
version:
|
183
|
+
version: 1.3.1
|
197
184
|
requirements: []
|
198
185
|
rubyforge_project:
|
199
|
-
rubygems_version: 2.
|
186
|
+
rubygems_version: 2.4.6
|
200
187
|
signing_key:
|
201
188
|
specification_version: 4
|
202
189
|
summary: HTTP should be easy
|
203
|
-
test_files:
|
190
|
+
test_files:
|
191
|
+
- spec/lib/http/client_spec.rb
|
192
|
+
- spec/lib/http/content_type_spec.rb
|
193
|
+
- spec/lib/http/headers/mixin_spec.rb
|
194
|
+
- spec/lib/http/headers_spec.rb
|
195
|
+
- spec/lib/http/options/body_spec.rb
|
196
|
+
- spec/lib/http/options/form_spec.rb
|
197
|
+
- spec/lib/http/options/headers_spec.rb
|
198
|
+
- spec/lib/http/options/json_spec.rb
|
199
|
+
- spec/lib/http/options/merge_spec.rb
|
200
|
+
- spec/lib/http/options/new_spec.rb
|
201
|
+
- spec/lib/http/options/proxy_spec.rb
|
202
|
+
- spec/lib/http/options_spec.rb
|
203
|
+
- spec/lib/http/redirector_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/status_spec.rb
|
208
|
+
- spec/lib/http/response_spec.rb
|
209
|
+
- spec/lib/http_spec.rb
|
210
|
+
- spec/spec_helper.rb
|
211
|
+
- spec/support/black_hole.rb
|
212
|
+
- spec/support/capture_warning.rb
|
213
|
+
- spec/support/connection_reuse_shared.rb
|
214
|
+
- spec/support/dummy_server.rb
|
215
|
+
- spec/support/dummy_server/servlet.rb
|
216
|
+
- spec/support/http_handling_shared.rb
|
217
|
+
- spec/support/proxy_server.rb
|
218
|
+
- spec/support/servers/config.rb
|
219
|
+
- spec/support/servers/runner.rb
|
220
|
+
- spec/support/ssl_helper.rb
|
204
221
|
has_rdoc:
|
data/lib/http/cache.rb
DELETED
@@ -1,146 +0,0 @@
|
|
1
|
-
require "time"
|
2
|
-
require "rack-cache"
|
3
|
-
|
4
|
-
module HTTP
|
5
|
-
class Cache
|
6
|
-
# NoOp logger.
|
7
|
-
class NullLogger
|
8
|
-
def error(_msg = nil)
|
9
|
-
end
|
10
|
-
|
11
|
-
def debug(_msg = nil)
|
12
|
-
end
|
13
|
-
|
14
|
-
def info(_msg = nil)
|
15
|
-
end
|
16
|
-
|
17
|
-
def warn(_msg = nil)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
# @return [Response] a cached response that is valid for the request or
|
22
|
-
# the result of executing the provided block
|
23
|
-
#
|
24
|
-
# @yield [request, options] on cache miss so that an actual
|
25
|
-
# request can be made
|
26
|
-
def perform(request, options, &request_performer)
|
27
|
-
req = request.caching
|
28
|
-
|
29
|
-
invalidate_cache(req) if req.invalidates_cache?
|
30
|
-
|
31
|
-
get_response(req, options, request_performer)
|
32
|
-
end
|
33
|
-
|
34
|
-
protected
|
35
|
-
|
36
|
-
# @return [Response] the response to the request, either from the
|
37
|
-
# cache or by actually making the request
|
38
|
-
def get_response(req, options, request_performer)
|
39
|
-
cached_resp = cache_lookup(req)
|
40
|
-
return cached_resp if cached_resp && !cached_resp.stale?
|
41
|
-
|
42
|
-
# cache miss
|
43
|
-
logger.debug { "Cache miss for <#{req.uri}>, making request" }
|
44
|
-
actual_req = if cached_resp
|
45
|
-
req.conditional_on_changes_to(cached_resp)
|
46
|
-
else
|
47
|
-
req
|
48
|
-
end
|
49
|
-
actual_resp = make_request(actual_req, options, request_performer)
|
50
|
-
|
51
|
-
handle_response(cached_resp, actual_resp, req)
|
52
|
-
end
|
53
|
-
|
54
|
-
# @return [Response] the most useful of the responses after
|
55
|
-
# updating the cache as appropriate
|
56
|
-
def handle_response(cached_resp, actual_resp, req)
|
57
|
-
if actual_resp.status.not_modified? && cached_resp
|
58
|
-
logger.debug { "<#{req.uri}> not modified, using cached version." }
|
59
|
-
cached_resp.validated!(actual_resp)
|
60
|
-
store_in_cache(req, cached_resp)
|
61
|
-
return cached_resp
|
62
|
-
|
63
|
-
elsif req.cacheable? && actual_resp.cacheable?
|
64
|
-
store_in_cache(req, actual_resp)
|
65
|
-
return actual_resp
|
66
|
-
|
67
|
-
else
|
68
|
-
return actual_resp
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
# @return [HTTP::Response::Caching] the actual response returned
|
73
|
-
# by request_performer
|
74
|
-
def make_request(req, options, request_performer)
|
75
|
-
req.sent_at = Time.now
|
76
|
-
|
77
|
-
request_performer.call(req, options).caching.tap do |res|
|
78
|
-
res.received_at = Time.now
|
79
|
-
res.requested_at = req.sent_at
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
# @return [HTTP::Response::Caching, nil] the cached response for the request
|
84
|
-
def cache_lookup(request)
|
85
|
-
return nil if request.skips_cache?
|
86
|
-
|
87
|
-
rack_resp = metastore.lookup(request, entitystore)
|
88
|
-
return if rack_resp.nil?
|
89
|
-
|
90
|
-
HTTP::Response.new(
|
91
|
-
rack_resp.status, "1.1", rack_resp.headers, stringify(rack_resp.body)
|
92
|
-
).caching
|
93
|
-
end
|
94
|
-
|
95
|
-
# Store response in cache
|
96
|
-
#
|
97
|
-
# @return [nil]
|
98
|
-
#
|
99
|
-
# ---
|
100
|
-
#
|
101
|
-
# We have to convert the response body in to a string body so
|
102
|
-
# that the cache store reading the body will not prevent the
|
103
|
-
# original requester from doing so.
|
104
|
-
def store_in_cache(request, response)
|
105
|
-
response.body = response.body.to_s
|
106
|
-
metastore.store(request, response, entitystore)
|
107
|
-
nil
|
108
|
-
end
|
109
|
-
|
110
|
-
# Invalidate all response from the requested resource
|
111
|
-
#
|
112
|
-
# @return [nil]
|
113
|
-
def invalidate_cache(request)
|
114
|
-
metastore.invalidate(request, entitystore)
|
115
|
-
end
|
116
|
-
|
117
|
-
# Inits a new instance
|
118
|
-
#
|
119
|
-
# @option opts [String] :metastore URL to the metastore location
|
120
|
-
# @option opts [String] :entitystore URL to the entitystore location
|
121
|
-
# @option opts [Logger] :logger logger to use
|
122
|
-
def initialize(opts)
|
123
|
-
@metastore = storage.resolve_metastore_uri(opts.fetch(:metastore))
|
124
|
-
@entitystore = storage.resolve_entitystore_uri(opts.fetch(:entitystore))
|
125
|
-
@logger = opts.fetch(:logger) { NullLogger.new }
|
126
|
-
end
|
127
|
-
|
128
|
-
attr_reader :metastore, :entitystore, :logger
|
129
|
-
|
130
|
-
def storage
|
131
|
-
@@storage ||= Rack::Cache::Storage.new # rubocop:disable Style/ClassVars
|
132
|
-
end
|
133
|
-
|
134
|
-
def stringify(body)
|
135
|
-
if body.respond_to?(:each)
|
136
|
-
"".tap do |buf|
|
137
|
-
body.each do |part|
|
138
|
-
buf << part
|
139
|
-
end
|
140
|
-
end
|
141
|
-
else
|
142
|
-
body.to_s
|
143
|
-
end
|
144
|
-
end
|
145
|
-
end
|
146
|
-
end
|
data/lib/http/cache/headers.rb
DELETED
@@ -1,100 +0,0 @@
|
|
1
|
-
require "delegate"
|
2
|
-
|
3
|
-
require "http/errors"
|
4
|
-
require "http/headers"
|
5
|
-
|
6
|
-
module HTTP
|
7
|
-
class Cache
|
8
|
-
# Convenience methods around cache control headers.
|
9
|
-
class Headers < ::SimpleDelegator
|
10
|
-
def initialize(headers)
|
11
|
-
if headers.is_a? HTTP::Headers
|
12
|
-
super headers
|
13
|
-
else
|
14
|
-
super HTTP::Headers.coerce headers
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
# @return [Boolean] does this message force revalidation
|
19
|
-
def forces_revalidation?
|
20
|
-
must_revalidate? || max_age == 0
|
21
|
-
end
|
22
|
-
|
23
|
-
# @return [Boolean] does the cache control include 'must-revalidate'
|
24
|
-
def must_revalidate?
|
25
|
-
matches?(/\bmust-revalidate\b/i)
|
26
|
-
end
|
27
|
-
|
28
|
-
# @return [Boolean] does the cache control include 'no-cache'
|
29
|
-
def no_cache?
|
30
|
-
matches?(/\bno-cache\b/i)
|
31
|
-
end
|
32
|
-
|
33
|
-
# @return [Boolean] does the cache control include 'no-stor'
|
34
|
-
def no_store?
|
35
|
-
matches?(/\bno-store\b/i)
|
36
|
-
end
|
37
|
-
|
38
|
-
# @return [Boolean] does the cache control include 'public'
|
39
|
-
def public?
|
40
|
-
matches?(/\bpublic\b/i)
|
41
|
-
end
|
42
|
-
|
43
|
-
# @return [Boolean] does the cache control include 'private'
|
44
|
-
def private?
|
45
|
-
matches?(/\bprivate\b/i)
|
46
|
-
end
|
47
|
-
|
48
|
-
# @return [Numeric] the max number of seconds this message is
|
49
|
-
# considered fresh.
|
50
|
-
def max_age
|
51
|
-
explicit_max_age || seconds_til_expires || Float::INFINITY
|
52
|
-
end
|
53
|
-
|
54
|
-
# @return [Boolean] is the vary header set to '*'
|
55
|
-
def vary_star?
|
56
|
-
get(HTTP::Headers::VARY).any? { |v| "*" == v.strip }
|
57
|
-
end
|
58
|
-
|
59
|
-
private
|
60
|
-
|
61
|
-
# @return [Boolean] true when cache-control header matches the pattern
|
62
|
-
def matches?(pattern)
|
63
|
-
get(HTTP::Headers::CACHE_CONTROL).any? { |v| v =~ pattern }
|
64
|
-
end
|
65
|
-
|
66
|
-
# @return [Numeric] number of seconds until the time in the
|
67
|
-
# expires header is reached.
|
68
|
-
#
|
69
|
-
# ---
|
70
|
-
# Some servers send a "Expires: -1" header which must be treated as expired
|
71
|
-
def seconds_til_expires
|
72
|
-
get(HTTP::Headers::EXPIRES).
|
73
|
-
map { |e| http_date_to_ttl(e) }.
|
74
|
-
max
|
75
|
-
end
|
76
|
-
|
77
|
-
def http_date_to_ttl(t_str)
|
78
|
-
ttl = to_time_or_epoch(t_str) - Time.now
|
79
|
-
|
80
|
-
ttl < 0 ? 0 : ttl
|
81
|
-
end
|
82
|
-
|
83
|
-
# @return [Time] parses t_str at a time; if that fails returns epoch time
|
84
|
-
def to_time_or_epoch(t_str)
|
85
|
-
Time.httpdate(t_str)
|
86
|
-
rescue ArgumentError
|
87
|
-
Time.at(0)
|
88
|
-
end
|
89
|
-
|
90
|
-
# @return [Numeric] the value of the max-age component of cache control
|
91
|
-
def explicit_max_age
|
92
|
-
get(HTTP::Headers::CACHE_CONTROL).
|
93
|
-
map { |v| (/max-age=(\d+)/i).match(v) }.
|
94
|
-
compact.
|
95
|
-
map { |m| m[1].to_i }.
|
96
|
-
max
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|