UNPKG

12.7 kBJavaScriptView Raw
1'use strict';
2
3const assert = require('assert');
4const CachePolicy = require('..');
5
6const req = {method:'GET', headers:{}};
7
8describe('Response headers', function() {
9 it('simple miss', function() {
10 const cache = new CachePolicy(req, {headers:{}});
11 assert(cache.stale());
12 });
13
14 it('simple hit', function() {
15 const cache = new CachePolicy(req, {headers:{'cache-control': 'public, max-age=999999'}});
16 assert(!cache.stale());
17 assert.equal(cache.maxAge(), 999999);
18 });
19
20 it('weird syntax', function() {
21 const cache = new CachePolicy(req, {headers:{'cache-control': ',,,,max-age = 456 ,'}});
22 assert(!cache.stale());
23 assert.equal(cache.maxAge(), 456);
24
25 const cache2 = CachePolicy.fromObject(JSON.parse(JSON.stringify(cache.toObject())));
26 assert(cache2 instanceof CachePolicy);
27 assert(!cache2.stale());
28 assert.equal(cache2.maxAge(), 456);
29 });
30
31 it('quoted syntax', function() {
32 const cache = new CachePolicy(req, {headers:{'cache-control': ' max-age = "678" '}});
33 assert(!cache.stale());
34 assert.equal(cache.maxAge(), 678);
35 });
36
37 it('pre-check tolerated', function() {
38 const cc = 'pre-check=0, post-check=0, no-store, no-cache, max-age=100';
39 const cache = new CachePolicy(req, {headers:{'cache-control': cc}});
40 assert(cache.stale());
41 assert(!cache.storable());
42 assert.equal(cache.maxAge(), 0);
43 assert.equal(cache.responseHeaders()['cache-control'], cc);
44 });
45
46 it('pre-check poison', function() {
47 const origCC = 'pre-check=0, post-check=0, no-cache, no-store, max-age=100, custom, foo=bar';
48 const res = {headers:{'cache-control': origCC, pragma: 'no-cache'}};
49 const cache = new CachePolicy(req, res, {ignoreCargoCult:true});
50 assert(!cache.stale());
51 assert(cache.storable());
52 assert.equal(cache.maxAge(), 100);
53
54 const cc = cache.responseHeaders()['cache-control'];
55 assert(!/pre-check/.test(cc), cc);
56 assert(!/post-check/.test(cc), cc);
57 assert(!/no-store/.test(cc), cc);
58
59 assert(/max-age=100/.test(cc));
60 assert(/custom(,|$)/.test(cc));
61 assert(/foo=bar/.test(cc));
62
63 assert.equal(res.headers['cache-control'], origCC);
64 assert(res.headers['pragma']);
65 assert(!cache.responseHeaders()['pragma']);
66 });
67
68 it('pre-check poison undefined header', function() {
69 const origCC = 'pre-check=0, post-check=0, no-cache, no-store';
70 const res = {headers:{'cache-control': origCC, expires: 'yesterday!'}};
71 const cache = new CachePolicy(req, res, {ignoreCargoCult:true});
72 assert(cache.stale());
73 assert(cache.storable());
74 assert.equal(cache.maxAge(), 0);
75
76 const cc = cache.responseHeaders()['cache-control'];
77 assert(!cc);
78
79 assert(res.headers['expires']);
80 assert(!cache.responseHeaders()['expires']);
81 });
82
83 it('cache with expires', function() {
84 const cache = new CachePolicy(req, {headers:{
85 'date': new Date().toGMTString(),
86 'expires': new Date(Date.now() + 2000).toGMTString(),
87 }});
88 assert(!cache.stale());
89 assert.equal(2, cache.maxAge());
90 });
91
92 it('cache expires no date', function() {
93 const cache = new CachePolicy(req, {headers:{
94 'cache-control': 'public',
95 'expires': new Date(Date.now()+3600*1000).toGMTString(),
96 }});
97 assert(!cache.stale());
98 assert(cache.maxAge() > 3595);
99 assert(cache.maxAge() < 3605);
100 });
101
102 it('Ages', function() {
103 let now = 1000;
104 class TimeTravellingPolicy extends CachePolicy {
105 now() {
106 return now;
107 }
108 }
109 const cache = new TimeTravellingPolicy(req, {headers:{
110 'cache-control':'max-age=100',
111 'age': '50',
112 }});
113 assert(cache.storable());
114
115 assert.equal(50*1000, cache.timeToLive());
116 assert(!cache.stale());
117 now += 48*1000;
118 assert.equal(2*1000, cache.timeToLive());
119 assert(!cache.stale());
120 now += 5*1000;
121 assert(cache.stale());
122 assert.equal(0, cache.timeToLive());
123 });
124
125 it('Age can make stale', function() {
126 const cache = new CachePolicy(req, {headers:{
127 'cache-control':'max-age=100',
128 'age': '101',
129 }});
130 assert(cache.stale());
131 assert(cache.storable());
132 });
133
134 it('Age not always stale', function() {
135 const cache = new CachePolicy(req, {headers:{
136 'cache-control':'max-age=20',
137 'age': '15',
138 }});
139 assert(!cache.stale());
140 assert(cache.storable());
141 });
142
143 it('Bogus age ignored', function() {
144 const cache = new CachePolicy(req, {headers:{
145 'cache-control':'max-age=20',
146 'age': 'golden',
147 }});
148 assert(!cache.stale());
149 assert(cache.storable());
150 });
151
152 it('cache old files', function() {
153 const cache = new CachePolicy(req, {headers:{
154 'date': new Date().toGMTString(),
155 'last-modified': 'Mon, 07 Mar 2016 11:52:56 GMT',
156 }});
157 assert(!cache.stale());
158 assert(cache.maxAge() > 100);
159 });
160
161 it('immutable simple hit', function() {
162 const cache = new CachePolicy(req, {headers:{'cache-control': 'immutable, max-age=999999'}});
163 assert(!cache.stale());
164 assert.equal(cache.maxAge(), 999999);
165 });
166
167 it('immutable can expire', function() {
168 const cache = new CachePolicy(req, {headers:{'cache-control': 'immutable, max-age=0'}});
169 assert(cache.stale());
170 assert.equal(cache.maxAge(), 0);
171 });
172
173 it('cache immutable files', function() {
174 const cache = new CachePolicy(req, {headers:{
175 'date': new Date().toGMTString(),
176 'cache-control':'immutable',
177 'last-modified': new Date().toGMTString(),
178 }});
179 assert(!cache.stale());
180 assert(cache.maxAge() > 100);
181 });
182
183 it('immutable can be off', function() {
184 const cache = new CachePolicy(req, {headers:{
185 'date': new Date().toGMTString(),
186 'cache-control':'immutable',
187 'last-modified': new Date().toGMTString(),
188 }}, {immutableMinTimeToLive: 0});
189 assert(cache.stale());
190 assert.equal(cache.maxAge(), 0);
191 });
192
193 it('pragma: no-cache', function() {
194 const cache = new CachePolicy(req, {headers:{
195 'pragma': 'no-cache',
196 'last-modified': 'Mon, 07 Mar 2016 11:52:56 GMT',
197 }});
198 assert(cache.stale());
199 });
200
201 it('no-store', function() {
202 const cache = new CachePolicy(req, {headers:{
203 'cache-control': 'no-store, public, max-age=1',
204 }});
205 assert(cache.stale());
206 assert.equal(0, cache.maxAge());
207 });
208
209 it('observe private cache', function() {
210 const privateHeader = {
211 'cache-control': 'private, max-age=1234',
212 };
213 const proxyCache = new CachePolicy(req, {headers:privateHeader});
214 assert(proxyCache.stale());
215 assert.equal(0, proxyCache.maxAge());
216
217 const uaCache = new CachePolicy(req, {headers:privateHeader}, {shared:false});
218 assert(!uaCache.stale());
219 assert.equal(1234, uaCache.maxAge());
220 });
221
222 it('don\'t share cookies', function() {
223 const cookieHeader = {
224 'set-cookie': 'foo=bar',
225 'cache-control': 'max-age=99',
226 };
227 const proxyCache = new CachePolicy(req, {headers:cookieHeader}, {shared:true});
228 assert(proxyCache.stale());
229 assert.equal(0, proxyCache.maxAge());
230
231 const uaCache = new CachePolicy(req, {headers:cookieHeader}, {shared:false});
232 assert(!uaCache.stale());
233 assert.equal(99, uaCache.maxAge());
234 });
235
236 it('do share cookies if immutable', function() {
237 const cookieHeader = {
238 'set-cookie': 'foo=bar',
239 'cache-control': 'immutable, max-age=99',
240 };
241 const proxyCache = new CachePolicy(req, {headers:cookieHeader}, {shared:true});
242 assert(!proxyCache.stale());
243 assert.equal(99, proxyCache.maxAge());
244 });
245
246 it('cache explicitly public cookie', function() {
247 const cookieHeader = {
248 'set-cookie': 'foo=bar',
249 'cache-control': 'max-age=5, public',
250 };
251 const proxyCache = new CachePolicy(req, {headers:cookieHeader}, {shared:true});
252 assert(!proxyCache.stale());
253 assert.equal(5, proxyCache.maxAge());
254 });
255
256 it('miss max-age=0', function() {
257 const cache = new CachePolicy(req, {headers:{
258 'cache-control': 'public, max-age=0',
259 }});
260 assert(cache.stale());
261 assert.equal(0, cache.maxAge());
262 });
263
264 it('uncacheable 503', function() {
265 const cache = new CachePolicy(req, {
266 status: 503,
267 headers:{
268 'cache-control': 'public, max-age=1000',
269 }});
270 assert(cache.stale());
271 assert.equal(0, cache.maxAge());
272 });
273
274 it('cacheable 301', function() {
275 const cache = new CachePolicy(req, {
276 status: 301,
277 headers:{
278 'last-modified': 'Mon, 07 Mar 2016 11:52:56 GMT',
279 }});
280 assert(!cache.stale());
281 });
282
283 it('uncacheable 303', function() {
284 const cache = new CachePolicy(req, {
285 status: 303,
286 headers:{
287 'last-modified': 'Mon, 07 Mar 2016 11:52:56 GMT',
288 }});
289 assert(cache.stale());
290 assert.equal(0, cache.maxAge());
291 });
292
293 it('cacheable 303', function() {
294 const cache = new CachePolicy(req, {
295 status: 303,
296 headers:{
297 'cache-control': 'max-age=1000',
298 }});
299 assert(!cache.stale());
300 });
301
302 it('uncacheable 412', function() {
303 const cache = new CachePolicy(req, {
304 status: 412,
305 headers:{
306 'cache-control': 'public, max-age=1000',
307 }});
308 assert(cache.stale());
309 assert.equal(0, cache.maxAge());
310 });
311
312 it('expired expires cached with max-age', function() {
313 const cache = new CachePolicy(req, {headers:{
314 'cache-control': 'public, max-age=9999',
315 'expires': 'Sat, 07 May 2016 15:35:18 GMT',
316 }});
317 assert(!cache.stale());
318 assert.equal(9999, cache.maxAge());
319 });
320
321 it('expired expires cached with s-maxage', function() {
322 const sMaxAgeHeaders = {
323 'cache-control': 'public, s-maxage=9999',
324 'expires': 'Sat, 07 May 2016 15:35:18 GMT',
325 };
326 const proxyCache = new CachePolicy(req, {headers:sMaxAgeHeaders});
327 assert(!proxyCache.stale());
328 assert.equal(9999, proxyCache.maxAge());
329
330 const uaCache = new CachePolicy(req, {headers:sMaxAgeHeaders}, {shared:false});
331 assert(uaCache.stale());
332 assert.equal(0, uaCache.maxAge());
333 });
334
335 it('max-age wins over future expires', function() {
336 const cache = new CachePolicy(req, {headers:{
337 'cache-control': 'public, max-age=333',
338 'expires': new Date(Date.now()+3600*1000).toGMTString(),
339 }});
340 assert(!cache.stale());
341 assert.equal(333, cache.maxAge());
342 });
343
344 it('remove hop headers', function() {
345 let now = 10000;
346 class TimeTravellingPolicy extends CachePolicy {
347 now() {
348 return now;
349 }
350 }
351
352 const res = {headers:{
353 'te': 'deflate',
354 'date': 'now',
355 'custom': 'header',
356 'oompa': 'lumpa',
357 'connection': 'close, oompa, header',
358 'age': '10',
359 'cache-control': 'public, max-age=333',
360 }};
361 const cache = new TimeTravellingPolicy(req, res);
362
363 now += 1005;
364 const h = cache.responseHeaders();
365 assert(!h.connection);
366 assert(!h.te);
367 assert(!h.oompa);
368 assert.equal(h['cache-control'], 'public, max-age=333');
369 assert.equal(h.date, 'now', "date must stay the same for expires, age, etc");
370 assert.equal(h.custom, 'header');
371 assert.equal(h.age, '11');
372 assert.equal(res.headers.age, '10');
373
374 const cache2 = TimeTravellingPolicy.fromObject(JSON.parse(JSON.stringify(cache.toObject())));
375 assert(cache2 instanceof TimeTravellingPolicy);
376 const h2 = cache2.responseHeaders();
377 assert.deepEqual(h, h2);
378 });
379});