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
data/spec/lib/http/cache_spec.rb
DELETED
@@ -1,182 +0,0 @@
|
|
1
|
-
require "support/dummy_server"
|
2
|
-
require "http/cache"
|
3
|
-
|
4
|
-
RSpec.describe HTTP::Cache do
|
5
|
-
describe "creation" do
|
6
|
-
subject { described_class }
|
7
|
-
|
8
|
-
it "allows metastore and entitystore" do
|
9
|
-
expect(subject.new(:metastore => "heap:/", :entitystore => "heap:/")).
|
10
|
-
to be_kind_of HTTP::Cache
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
let(:opts) { options }
|
15
|
-
let(:sn) { SecureRandom.urlsafe_base64(3) }
|
16
|
-
let(:request) { HTTP::Request.new(:get, "http://example.com/#{sn}") }
|
17
|
-
|
18
|
-
let(:origin_response) do
|
19
|
-
HTTP::Response.new(200,
|
20
|
-
"http/1.1",
|
21
|
-
{"Cache-Control" => "private"},
|
22
|
-
"origin")
|
23
|
-
end
|
24
|
-
|
25
|
-
subject { described_class.new(:metastore => "heap:/", :entitystore => "heap:/") }
|
26
|
-
|
27
|
-
describe "#perform" do
|
28
|
-
it "calls request_performer blocck when cache miss" do
|
29
|
-
expect do |b|
|
30
|
-
subject.perform(request, opts) do |*args|
|
31
|
-
b.to_proc.call(*args)
|
32
|
-
origin_response
|
33
|
-
end
|
34
|
-
end.to yield_with_args(request, opts)
|
35
|
-
end
|
36
|
-
|
37
|
-
context "cache hit" do
|
38
|
-
it "does not call request_performer block" do
|
39
|
-
subject.perform(request, opts) do |*_t|
|
40
|
-
origin_response
|
41
|
-
end
|
42
|
-
|
43
|
-
expect { |b| subject.perform(request, opts, &b) }.not_to yield_control
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
context "empty cache, cacheable request, cacheable response" do
|
49
|
-
let!(:response) { subject.perform(request, opts) { origin_response } }
|
50
|
-
|
51
|
-
it "returns origin servers response" do
|
52
|
-
expect(response).to eq origin_response
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
context "cache by-passing request, cacheable response" do
|
57
|
-
let(:request) do
|
58
|
-
headers = {"Cache-Control" => "no-cache"}
|
59
|
-
HTTP::Request.new(:get, "http://example.com/", headers)
|
60
|
-
end
|
61
|
-
let!(:response) { subject.perform(request, opts) { origin_response } }
|
62
|
-
|
63
|
-
it "returns origin servers response" do
|
64
|
-
expect(response).to eq origin_response
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
context "empty cache, cacheable request, 'no-cache' response" do
|
69
|
-
let(:origin_response) do
|
70
|
-
HTTP::Response.new(200,
|
71
|
-
"http/1.1",
|
72
|
-
{"Cache-Control" => "no-store"},
|
73
|
-
"")
|
74
|
-
end
|
75
|
-
let!(:response) { subject.perform(request, opts) { origin_response } }
|
76
|
-
|
77
|
-
it "returns origin servers response" do
|
78
|
-
expect(response).to eq origin_response
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
context "empty cache, cacheable request, 'no-store' response" do
|
83
|
-
let(:origin_response) do
|
84
|
-
HTTP::Response.new(200,
|
85
|
-
"http/1.1",
|
86
|
-
{"Cache-Control" => "no-store"},
|
87
|
-
"")
|
88
|
-
end
|
89
|
-
let!(:response) { subject.perform(request, opts) { origin_response } }
|
90
|
-
|
91
|
-
it "returns origin servers response" do
|
92
|
-
expect(response).to eq origin_response
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
context "warm cache, cacheable request, cacheable response" do
|
97
|
-
let(:cached_response) do
|
98
|
-
build_cached_response(200,
|
99
|
-
"1.1",
|
100
|
-
{"Cache-Control" => "max-age=100"},
|
101
|
-
"cached")
|
102
|
-
end
|
103
|
-
before do
|
104
|
-
subject.perform(request, opts) { cached_response }
|
105
|
-
end
|
106
|
-
|
107
|
-
let(:response) { subject.perform(request, opts) { origin_response } }
|
108
|
-
|
109
|
-
it "returns cached response" do
|
110
|
-
expect(response.body.to_s).to eq cached_response.body.to_s
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
context "stale cache, cacheable request, cacheable response" do
|
115
|
-
let(:cached_response) do
|
116
|
-
build_cached_response(200,
|
117
|
-
"1.1",
|
118
|
-
{"Cache-Control" => "private, max-age=1",
|
119
|
-
"Date" => (Time.now - 2).httpdate},
|
120
|
-
"cached") do |t|
|
121
|
-
t.requested_at = (Time.now - 2)
|
122
|
-
end
|
123
|
-
end
|
124
|
-
before do
|
125
|
-
subject.perform(request, opts) { cached_response }
|
126
|
-
end
|
127
|
-
let(:response) { subject.perform(request, opts) { origin_response } }
|
128
|
-
|
129
|
-
it "returns origin servers response" do
|
130
|
-
expect(response.body.to_s).to eq origin_response.body.to_s
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
context "stale cache, cacheable request, not modified response" do
|
135
|
-
let(:cached_response) do
|
136
|
-
build_cached_response(200,
|
137
|
-
"http/1.1",
|
138
|
-
{"Cache-Control" => "private, max-age=1",
|
139
|
-
"Etag" => "foo",
|
140
|
-
"Date" => (Time.now - 2).httpdate},
|
141
|
-
"") do |x|
|
142
|
-
x.requested_at = (Time.now - 2)
|
143
|
-
end
|
144
|
-
end
|
145
|
-
before do
|
146
|
-
subject.perform(request, opts) { cached_response }
|
147
|
-
end
|
148
|
-
|
149
|
-
let(:origin_response) { HTTP::Response.new(304, "http/1.1", {}, "") }
|
150
|
-
let(:response) { subject.perform(request, opts) { origin_response } }
|
151
|
-
|
152
|
-
it "makes request with conditional request headers" do
|
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"]
|
158
|
-
|
159
|
-
origin_response
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
it "returns cached servers response" do
|
164
|
-
expect(response.body.to_s).to eq cached_response.body.to_s
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
let(:cached_response) { nil } # cold cache by default
|
169
|
-
|
170
|
-
def build_cached_response(*args)
|
171
|
-
r = HTTP::Response.new(*args).caching
|
172
|
-
r.requested_at = r.received_at = Time.now
|
173
|
-
|
174
|
-
yield r if block_given?
|
175
|
-
|
176
|
-
r
|
177
|
-
end
|
178
|
-
|
179
|
-
def options
|
180
|
-
HTTP::Options.new
|
181
|
-
end
|
182
|
-
end
|
@@ -1,133 +0,0 @@
|
|
1
|
-
RSpec.describe HTTP::Request::Caching do
|
2
|
-
let(:request) { HTTP::Request.new(:get, "http://example.com/") }
|
3
|
-
|
4
|
-
subject(:caching_request) { described_class.new request }
|
5
|
-
|
6
|
-
describe "#cache_headers" do
|
7
|
-
subject { caching_request.cache_headers }
|
8
|
-
it { is_expected.to be_a HTTP::Cache::Headers }
|
9
|
-
end
|
10
|
-
|
11
|
-
context "basic GET request" do
|
12
|
-
it "is cacheable" do
|
13
|
-
expect(subject.cacheable?).to be_truthy
|
14
|
-
end
|
15
|
-
|
16
|
-
it "does not invalidate cache" do
|
17
|
-
expect(subject.invalidates_cache?).to be_falsy
|
18
|
-
end
|
19
|
-
|
20
|
-
it "does not skip cache" do
|
21
|
-
expect(subject.skips_cache?).to be_falsy
|
22
|
-
end
|
23
|
-
|
24
|
-
it "can construct a new conditional version of itself based on a caching response" do
|
25
|
-
mod_date = Time.now.httpdate
|
26
|
-
headers = {"Etag" => "foo", "Last-Modified" => mod_date}
|
27
|
-
cached_resp = HTTP::Response.new(200, "http/1.1", headers, "")
|
28
|
-
cond_req = subject.conditional_on_changes_to(cached_resp)
|
29
|
-
|
30
|
-
expect(cond_req.headers["If-None-Match"]).to eq "foo"
|
31
|
-
expect(cond_req.headers["If-Modified-Since"]).to eq mod_date
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
context "GET request w/ must-revalidate" do
|
36
|
-
let(:request) do
|
37
|
-
headers = {"cache-control" => "must-revalidate"}
|
38
|
-
HTTP::Request.new(:get, "http://example.com/", headers)
|
39
|
-
end
|
40
|
-
|
41
|
-
it "is cacheable" do
|
42
|
-
expect(subject.cacheable?).to be_truthy
|
43
|
-
end
|
44
|
-
|
45
|
-
it "does not invalidate cache" do
|
46
|
-
expect(subject.invalidates_cache?).to be_falsy
|
47
|
-
end
|
48
|
-
|
49
|
-
it "does not skip cache" do
|
50
|
-
expect(subject.skips_cache?).to be_truthy
|
51
|
-
end
|
52
|
-
|
53
|
-
it "can construct a condition version of itself based on a caching response" do
|
54
|
-
mod_date = Time.now.httpdate
|
55
|
-
headers = {"Etag" => "foo", "Last-Modified" => mod_date}
|
56
|
-
cached_resp = HTTP::Response.new(200, "http/1.1", headers, "")
|
57
|
-
cond_req = subject.conditional_on_changes_to(cached_resp)
|
58
|
-
|
59
|
-
expect(cond_req.headers["If-None-Match"]).to eq "foo"
|
60
|
-
expect(cond_req.headers["If-Modified-Since"]).to eq mod_date
|
61
|
-
expect(cond_req.cache_headers.max_age).to eq 0
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
context "basic POST request" do
|
66
|
-
let(:request) { HTTP::Request.new(:post, "http://example.com/") }
|
67
|
-
|
68
|
-
it "is cacheable" do
|
69
|
-
expect(subject.cacheable?).to be_falsy
|
70
|
-
end
|
71
|
-
|
72
|
-
it "does not invalidate cache" do
|
73
|
-
expect(subject.invalidates_cache?).to be_truthy
|
74
|
-
end
|
75
|
-
|
76
|
-
it "does not skip cache" do
|
77
|
-
expect(subject.skips_cache?).to be_falsy
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
context "basic PUT request" do
|
82
|
-
let(:request) { HTTP::Request.new(:put, "http://example.com/") }
|
83
|
-
|
84
|
-
it "is cacheable" do
|
85
|
-
expect(subject.cacheable?).to be_falsy
|
86
|
-
end
|
87
|
-
|
88
|
-
it "does not invalidate cache" do
|
89
|
-
expect(subject.invalidates_cache?).to be_truthy
|
90
|
-
end
|
91
|
-
|
92
|
-
it "does not skip cache" do
|
93
|
-
expect(subject.skips_cache?).to be_falsy
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
context "basic delete request" do
|
98
|
-
let(:request) { HTTP::Request.new(:delete, "http://example.com/") }
|
99
|
-
|
100
|
-
it "is cacheable" do
|
101
|
-
expect(subject.cacheable?).to be_falsy
|
102
|
-
end
|
103
|
-
|
104
|
-
it "does not invalidate cache" do
|
105
|
-
expect(subject.invalidates_cache?).to be_truthy
|
106
|
-
end
|
107
|
-
|
108
|
-
it "does not skip cache" do
|
109
|
-
expect(subject.skips_cache?).to be_falsy
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
context "basic patch request" do
|
114
|
-
let(:request) { HTTP::Request.new(:patch, "http://example.com/") }
|
115
|
-
|
116
|
-
it "is cacheable" do
|
117
|
-
expect(subject.cacheable?).to be_falsy
|
118
|
-
end
|
119
|
-
|
120
|
-
it "does not invalidate cache" do
|
121
|
-
expect(subject.invalidates_cache?).to be_truthy
|
122
|
-
end
|
123
|
-
|
124
|
-
it "does not skip cache" do
|
125
|
-
expect(subject.skips_cache?).to be_falsy
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
describe "#caching" do
|
130
|
-
subject(:caching_request) { request.caching }
|
131
|
-
it { is_expected.to be caching_request }
|
132
|
-
end
|
133
|
-
end
|
@@ -1,201 +0,0 @@
|
|
1
|
-
RSpec.describe HTTP::Response::Caching do
|
2
|
-
let(:cache_control) { "" }
|
3
|
-
let(:headers) { {"cache-control" => cache_control} }
|
4
|
-
let(:response) { HTTP::Response.new(200, "http/1.1", headers, "") }
|
5
|
-
|
6
|
-
subject(:caching_response) { described_class.new response }
|
7
|
-
|
8
|
-
describe "#cache_headers" do
|
9
|
-
subject { caching_response.cache_headers }
|
10
|
-
it { is_expected.to be_a HTTP::Cache::Headers }
|
11
|
-
end
|
12
|
-
|
13
|
-
it "allows requested_at to be set" do
|
14
|
-
subject.requested_at = Time.now
|
15
|
-
expect(subject.requested_at).to be_within(1).of(Time.now)
|
16
|
-
end
|
17
|
-
|
18
|
-
it "allows received_at to be set" do
|
19
|
-
subject.received_at = Time.now
|
20
|
-
expect(subject.received_at).to be_within(1).of(Time.now)
|
21
|
-
end
|
22
|
-
|
23
|
-
describe "basic 200 response w/ private cache control" do
|
24
|
-
let(:cache_control) { "private" }
|
25
|
-
|
26
|
-
it "is cacheable" do
|
27
|
-
expect(subject.cacheable?).to be_truthy
|
28
|
-
end
|
29
|
-
|
30
|
-
it "is not stale" do
|
31
|
-
expect(subject.stale?).to be_falsy
|
32
|
-
end
|
33
|
-
|
34
|
-
it "is not expired" do
|
35
|
-
expect(subject.expired?).to be_falsy
|
36
|
-
end
|
37
|
-
|
38
|
-
it "is expected to be 0 seconds old" do
|
39
|
-
expect(subject.current_age).to be_within(1).of(0)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
describe "basic 200 response w/ public cache control" do
|
44
|
-
let(:cache_control) { "public" }
|
45
|
-
|
46
|
-
it "is cacheable" do
|
47
|
-
expect(subject.cacheable?).to be_truthy
|
48
|
-
end
|
49
|
-
|
50
|
-
it "is not stale" do
|
51
|
-
expect(subject.stale?).to be_falsy
|
52
|
-
end
|
53
|
-
|
54
|
-
it "is not expired" do
|
55
|
-
expect(subject.expired?).to be_falsy
|
56
|
-
end
|
57
|
-
|
58
|
-
it "is expected to be 0 seconds old" do
|
59
|
-
expect(subject.current_age).to be_within(1).of(0)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
describe "basic 200 response w/ no-cache" do
|
64
|
-
let(:cache_control) { "no-cache" }
|
65
|
-
|
66
|
-
it "is not cacheable" do
|
67
|
-
expect(subject.cacheable?).to be_falsy
|
68
|
-
end
|
69
|
-
|
70
|
-
it "is not stale" do
|
71
|
-
expect(subject.stale?).to be_falsy
|
72
|
-
end
|
73
|
-
|
74
|
-
it "is not expired" do
|
75
|
-
expect(subject.expired?).to be_falsy
|
76
|
-
end
|
77
|
-
|
78
|
-
it "is expected to be 0 seconds old" do
|
79
|
-
expect(subject.current_age).to be_within(1).of(0)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
describe "basic 200 response w/ no-store" do
|
84
|
-
let(:cache_control) { "no-store" }
|
85
|
-
|
86
|
-
it "is not cacheable" do
|
87
|
-
expect(subject.cacheable?).to be_falsy
|
88
|
-
end
|
89
|
-
|
90
|
-
it "is not stale" do
|
91
|
-
expect(subject.stale?).to be_falsy
|
92
|
-
end
|
93
|
-
|
94
|
-
it "is not expired" do
|
95
|
-
expect(subject.expired?).to be_falsy
|
96
|
-
end
|
97
|
-
|
98
|
-
it "is expected to be 0 seconds old" do
|
99
|
-
expect(subject.current_age).to be_within(1).of(0)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
describe "basic 200 response w/ max age" do
|
104
|
-
let(:cache_control) { "max-age=100" }
|
105
|
-
|
106
|
-
it "is not cacheable" do
|
107
|
-
expect(subject.cacheable?).to be_truthy
|
108
|
-
end
|
109
|
-
|
110
|
-
it "is not stale" do
|
111
|
-
expect(subject.stale?).to be_falsy
|
112
|
-
end
|
113
|
-
|
114
|
-
it "is not expired" do
|
115
|
-
expect(subject.expired?).to be_falsy
|
116
|
-
end
|
117
|
-
|
118
|
-
it "is expected to be 0 seconds old" do
|
119
|
-
expect(subject.current_age).to be_within(1).of(0)
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
describe "basic 200 response w/ public & max age" do
|
124
|
-
let(:cache_control) { "public, max-age=100" }
|
125
|
-
|
126
|
-
it "is not cacheable" do
|
127
|
-
expect(subject.cacheable?).to be_truthy
|
128
|
-
end
|
129
|
-
|
130
|
-
it "is not stale" do
|
131
|
-
expect(subject.stale?).to be_falsy
|
132
|
-
end
|
133
|
-
|
134
|
-
it "is not expired" do
|
135
|
-
expect(subject.expired?).to be_falsy
|
136
|
-
end
|
137
|
-
|
138
|
-
it "is expected to be 0 seconds old" do
|
139
|
-
expect(subject.current_age).to be_within(1).of(0)
|
140
|
-
end
|
141
|
-
|
142
|
-
context "with age of max-age + 1 seconds" do
|
143
|
-
let(:headers) { {"cache-control" => cache_control, "age" => "101"} }
|
144
|
-
|
145
|
-
it "is stale" do
|
146
|
-
expect(subject.stale?).to be_truthy
|
147
|
-
end
|
148
|
-
|
149
|
-
it "is expired" do
|
150
|
-
expect(subject.expired?).to be_truthy
|
151
|
-
end
|
152
|
-
|
153
|
-
it "is expected to be max-age + 1 seconds old" do
|
154
|
-
expect(subject.current_age).to be_within(1).of(101)
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
context "after max-age + 1 seconds" do
|
159
|
-
before do
|
160
|
-
subject.received_at = subject.requested_at = (Time.now - 101)
|
161
|
-
end
|
162
|
-
|
163
|
-
it "is stale" do
|
164
|
-
expect(subject.stale?).to be_truthy
|
165
|
-
end
|
166
|
-
|
167
|
-
it "is expired" do
|
168
|
-
expect(subject.expired?).to be_truthy
|
169
|
-
end
|
170
|
-
|
171
|
-
it "is expected to be max-age + 1 seconds old" do
|
172
|
-
expect(subject.current_age).to be_within(1).of(101)
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
describe "basic 400 response " do
|
178
|
-
let(:response) { HTTP::Response.new(400, "http/1.1", {}, "") }
|
179
|
-
|
180
|
-
it "is not cacheable" do
|
181
|
-
expect(subject.cacheable?).to be_falsy
|
182
|
-
end
|
183
|
-
|
184
|
-
it "is not stale" do
|
185
|
-
expect(subject.stale?).to be_falsy
|
186
|
-
end
|
187
|
-
|
188
|
-
it "is not expired" do
|
189
|
-
expect(subject.expired?).to be_falsy
|
190
|
-
end
|
191
|
-
|
192
|
-
it "is expected to be 0 seconds old" do
|
193
|
-
expect(subject.current_age).to be_within(1).of(0)
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
describe "#caching" do
|
198
|
-
subject(:caching_response) { response.caching }
|
199
|
-
it { is_expected.to be_kind_of described_class }
|
200
|
-
end
|
201
|
-
end
|