source: trip-planner-front/node_modules/make-fetch-happen/lib/cache/policy.js@ 76712b2

Last change on this file since 76712b2 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 4.8 KB
Line 
1const CacheSemantics = require('http-cache-semantics')
2const Negotiator = require('negotiator')
3const ssri = require('ssri')
4
5// HACK: negotiator lazy loads several of its own modules
6// as a micro optimization. we need to be sure that they're
7// in memory as soon as possible at startup so that we do
8// not try to lazy load them after the directory has been
9// retired during a self update of the npm CLI, we do this
10// by calling all of the methods that trigger a lazy load
11// on a fake instance.
12const preloadNegotiator = new Negotiator({ headers: {} })
13preloadNegotiator.charsets()
14preloadNegotiator.encodings()
15preloadNegotiator.languages()
16preloadNegotiator.mediaTypes()
17
18// options passed to http-cache-semantics constructor
19const policyOptions = {
20 shared: false,
21 ignoreCargoCult: true,
22}
23
24// a fake empty response, used when only testing the
25// request for storability
26const emptyResponse = { status: 200, headers: {} }
27
28// returns a plain object representation of the Request
29const requestObject = (request) => {
30 const _obj = {
31 method: request.method,
32 url: request.url,
33 headers: {},
34 }
35
36 request.headers.forEach((value, key) => {
37 _obj.headers[key] = value
38 })
39
40 return _obj
41}
42
43// returns a plain object representation of the Response
44const responseObject = (response) => {
45 const _obj = {
46 status: response.status,
47 headers: {},
48 }
49
50 response.headers.forEach((value, key) => {
51 _obj.headers[key] = value
52 })
53
54 return _obj
55}
56
57class CachePolicy {
58 constructor ({ entry, request, response, options }) {
59 this.entry = entry
60 this.request = requestObject(request)
61 this.response = responseObject(response)
62 this.options = options
63 this.policy = new CacheSemantics(this.request, this.response, policyOptions)
64
65 if (this.entry) {
66 // if we have an entry, copy the timestamp to the _responseTime
67 // this is necessary because the CacheSemantics constructor forces
68 // the value to Date.now() which means a policy created from a
69 // cache entry is likely to always identify itself as stale
70 this.policy._responseTime = this.entry.metadata.time
71 }
72 }
73
74 // static method to quickly determine if a request alone is storable
75 static storable (request, options) {
76 // no cachePath means no caching
77 if (!options.cachePath)
78 return false
79
80 // user explicitly asked not to cache
81 if (options.cache === 'no-store')
82 return false
83
84 // we only cache GET and HEAD requests
85 if (!['GET', 'HEAD'].includes(request.method))
86 return false
87
88 // otherwise, let http-cache-semantics make the decision
89 // based on the request's headers
90 const policy = new CacheSemantics(requestObject(request), emptyResponse, policyOptions)
91 return policy.storable()
92 }
93
94 // returns true if the policy satisfies the request
95 satisfies (request) {
96 const _req = requestObject(request)
97 if (this.request.headers.host !== _req.headers.host)
98 return false
99
100 const negotiatorA = new Negotiator(this.request)
101 const negotiatorB = new Negotiator(_req)
102
103 if (JSON.stringify(negotiatorA.mediaTypes()) !== JSON.stringify(negotiatorB.mediaTypes()))
104 return false
105
106 if (JSON.stringify(negotiatorA.languages()) !== JSON.stringify(negotiatorB.languages()))
107 return false
108
109 if (JSON.stringify(negotiatorA.encodings()) !== JSON.stringify(negotiatorB.encodings()))
110 return false
111
112 if (this.options.integrity)
113 return ssri.parse(this.options.integrity).match(this.entry.integrity)
114
115 return true
116 }
117
118 // returns true if the request and response allow caching
119 storable () {
120 return this.policy.storable()
121 }
122
123 // NOTE: this is a hack to avoid parsing the cache-control
124 // header ourselves, it returns true if the response's
125 // cache-control contains must-revalidate
126 get mustRevalidate () {
127 return !!this.policy._rescc['must-revalidate']
128 }
129
130 // returns true if the cached response requires revalidation
131 // for the given request
132 needsRevalidation (request) {
133 const _req = requestObject(request)
134 // force method to GET because we only cache GETs
135 // but can serve a HEAD from a cached GET
136 _req.method = 'GET'
137 return !this.policy.satisfiesWithoutRevalidation(_req)
138 }
139
140 responseHeaders () {
141 return this.policy.responseHeaders()
142 }
143
144 // returns a new object containing the appropriate headers
145 // to send a revalidation request
146 revalidationHeaders (request) {
147 const _req = requestObject(request)
148 return this.policy.revalidationHeaders(_req)
149 }
150
151 // returns true if the request/response was revalidated
152 // successfully. returns false if a new response was received
153 revalidated (request, response) {
154 const _req = requestObject(request)
155 const _res = responseObject(response)
156 const policy = this.policy.revalidatedPolicy(_req, _res)
157 return !policy.modified
158 }
159}
160
161module.exports = CachePolicy
Note: See TracBrowser for help on using the repository browser.