aboutsummaryrefslogtreecommitdiff
path: root/sandbox/testAppNevena/Front/node_modules/make-fetch-happen/lib/cache/policy.js
blob: e0959f64ddf9df9be2d25d7c26853bb5d388883c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
const CacheSemantics = require('http-cache-semantics')
const Negotiator = require('negotiator')
const ssri = require('ssri')

// HACK: negotiator lazy loads several of its own modules
// as a micro optimization. we need to be sure that they're
// in memory as soon as possible at startup so that we do
// not try to lazy load them after the directory has been
// retired during a self update of the npm CLI, we do this
// by calling all of the methods that trigger a lazy load
// on a fake instance.
const preloadNegotiator = new Negotiator({ headers: {} })
preloadNegotiator.charsets()
preloadNegotiator.encodings()
preloadNegotiator.languages()
preloadNegotiator.mediaTypes()

// options passed to http-cache-semantics constructor
const policyOptions = {
  shared: false,
  ignoreCargoCult: true,
}

// a fake empty response, used when only testing the
// request for storability
const emptyResponse = { status: 200, headers: {} }

// returns a plain object representation of the Request
const requestObject = (request) => {
  const _obj = {
    method: request.method,
    url: request.url,
    headers: {},
  }

  request.headers.forEach((value, key) => {
    _obj.headers[key] = value
  })

  return _obj
}

// returns a plain object representation of the Response
const responseObject = (response) => {
  const _obj = {
    status: response.status,
    headers: {},
  }

  response.headers.forEach((value, key) => {
    _obj.headers[key] = value
  })

  return _obj
}

class CachePolicy {
  constructor ({ entry, request, response, options }) {
    this.entry = entry
    this.request = requestObject(request)
    this.response = responseObject(response)
    this.options = options
    this.policy = new CacheSemantics(this.request, this.response, policyOptions)

    if (this.entry) {
      // if we have an entry, copy the timestamp to the _responseTime
      // this is necessary because the CacheSemantics constructor forces
      // the value to Date.now() which means a policy created from a
      // cache entry is likely to always identify itself as stale
      this.policy._responseTime = this.entry.metadata.time
    }
  }

  // static method to quickly determine if a request alone is storable
  static storable (request, options) {
    // no cachePath means no caching
    if (!options.cachePath)
      return false

    // user explicitly asked not to cache
    if (options.cache === 'no-store')
      return false

    // we only cache GET and HEAD requests
    if (!['GET', 'HEAD'].includes(request.method))
      return false

    // otherwise, let http-cache-semantics make the decision
    // based on the request's headers
    const policy = new CacheSemantics(requestObject(request), emptyResponse, policyOptions)
    return policy.storable()
  }

  // returns true if the policy satisfies the request
  satisfies (request) {
    const _req = requestObject(request)
    if (this.request.headers.host !== _req.headers.host)
      return false

    const negotiatorA = new Negotiator(this.request)
    const negotiatorB = new Negotiator(_req)

    if (JSON.stringify(negotiatorA.mediaTypes()) !== JSON.stringify(negotiatorB.mediaTypes()))
      return false

    if (JSON.stringify(negotiatorA.languages()) !== JSON.stringify(negotiatorB.languages()))
      return false

    if (JSON.stringify(negotiatorA.encodings()) !== JSON.stringify(negotiatorB.encodings()))
      return false

    if (this.options.integrity)
      return ssri.parse(this.options.integrity).match(this.entry.integrity)

    return true
  }

  // returns true if the request and response allow caching
  storable () {
    return this.policy.storable()
  }

  // NOTE: this is a hack to avoid parsing the cache-control
  // header ourselves, it returns true if the response's
  // cache-control contains must-revalidate
  get mustRevalidate () {
    return !!this.policy._rescc['must-revalidate']
  }

  // returns true if the cached response requires revalidation
  // for the given request
  needsRevalidation (request) {
    const _req = requestObject(request)
    // force method to GET because we only cache GETs
    // but can serve a HEAD from a cached GET
    _req.method = 'GET'
    return !this.policy.satisfiesWithoutRevalidation(_req)
  }

  responseHeaders () {
    return this.policy.responseHeaders()
  }

  // returns a new object containing the appropriate headers
  // to send a revalidation request
  revalidationHeaders (request) {
    const _req = requestObject(request)
    return this.policy.revalidationHeaders(_req)
  }

  // returns true if the request/response was revalidated
  // successfully. returns false if a new response was received
  revalidated (request, response) {
    const _req = requestObject(request)
    const _res = responseObject(response)
    const policy = this.policy.revalidatedPolicy(_req, _res)
    return !policy.modified
  }
}

module.exports = CachePolicy