Browse Source

Cone stream so we can do stuff with it at different times

cache-clone-stream
Luke Childs 8 years ago
parent
commit
0edfb324d9
  1. 119
      index.js
  2. 4568
      package-lock.json
  3. 24
      test/cache.js

119
index.js

@ -37,6 +37,56 @@ function requestAsEventEmitter(opts) {
const req = fn.request(opts, res => { const req = fn.request(opts, res => {
const statusCode = res.statusCode; const statusCode = res.statusCode;
if (revalidateCache) {
const cachedResponse = revalidateCache.response;
const {policy, modified} = CachePolicy.fromObject(revalidateCache.policy).revalidatedPolicy(opts, res);
if (!modified) {
const {statusCode, url} = res;
const headers = policy.responseHeaders();
const bodyBuffer = Buffer.from(cachedResponse.body.data, cachedResponse.body.encoding);
res = new Response(statusCode, headers, bodyBuffer, url);
res.cachePolicy = policy;
}
}
if (typeof res.cachePolicy === 'undefined') {
res.cachePolicy = new CachePolicy(opts, res);
}
if (opts.cache && res.cachePolicy.storable()) {
const stream = res;
const pass = require('stream').PassThrough;
res = new pass;
const clonedRes = new pass;
stream.pipe(res);
stream.pipe(clonedRes);
copyProps(stream, res);
copyProps(stream, clonedRes);
const encoding = 'buffer';
getStream(clonedRes, {encoding})
.then(body => {
res.body = body;
const key = cacheKey(opts);
const value = {
policy: res.cachePolicy.toObject(),
response: {
url: res.url,
statusCode: res.statusCode,
body: {
encoding: opts.encoding,
data: res.body
}
}
};
const ttl = res.cachePolicy.timeToLive();
opts.cache.set(key, value, ttl);
});
} else if (revalidateCache) {
const key = cacheKey(opts);
opts.cache.delete(key);
}
if (isRedirect(statusCode) && opts.followRedirect && 'location' in res.headers && (opts.method === 'GET' || opts.method === 'HEAD')) { if (isRedirect(statusCode) && opts.followRedirect && 'location' in res.headers && (opts.method === 'GET' || opts.method === 'HEAD')) {
res.resume(); res.resume();
@ -60,46 +110,6 @@ function requestAsEventEmitter(opts) {
setImmediate(() => { setImmediate(() => {
let response = typeof unzipResponse === 'function' && req.method !== 'HEAD' ? unzipResponse(res) : res; let response = typeof unzipResponse === 'function' && req.method !== 'HEAD' ? unzipResponse(res) : res;
if (revalidateCache) {
const cachedResponse = revalidateCache.response;
const {policy, modified} = CachePolicy.fromObject(revalidateCache.policy).revalidatedPolicy(opts, response);
if (!modified) {
const {statusCode, url} = response;
const headers = policy.responseHeaders();
const bodyBuffer = Buffer.from(cachedResponse.body.data, cachedResponse.body.encoding);
response = new Response(statusCode, headers, bodyBuffer, url);
response.cachePolicy = policy;
}
}
if (typeof response.cachePolicy === 'undefined') {
response.cachePolicy = new CachePolicy(opts, response);
}
if (opts.cache && response.cachePolicy.storable()) {
const encoding = opts.encoding === null ? 'buffer' : opts.encoding;
getStream(response, {encoding})
.then(body => {
response.body = body;
const key = cacheKey(opts);
const value = {
policy: response.cachePolicy.toObject(),
response: {
url: response.url,
statusCode: response.statusCode,
body: {
encoding: opts.encoding,
data: response.body
}
}
};
const ttl = response.cachePolicy.timeToLive();
opts.cache.set(key, value, ttl);
});
} else if (revalidateCache) {
const key = cacheKey(opts);
opts.cache.delete(key);
}
response.url = redirectUrl || requestUrl; response.url = redirectUrl || requestUrl;
response.requestUrl = requestUrl; response.requestUrl = requestUrl;
response.fromCache = false; response.fromCache = false;
@ -444,3 +454,32 @@ got.MaxRedirectsError = createErrorClass('MaxRedirectsError', function (statusCo
}); });
module.exports = got; module.exports = got;
const knownProps = [
'destroy',
'setTimeout',
'socket',
'headers',
'trailers',
'rawHeaders',
'statusCode',
'httpVersion',
'httpVersionMinor',
'httpVersionMajor',
'rawTrailers',
'statusMessage'
];
const copyProps = (fromStream, toStream) => {
const toProps = Object.keys(toStream);
const fromProps = new Set(Object.keys(fromStream).concat(knownProps));
for (const prop of fromProps) {
// Don't overwrite existing properties
if (toProps.indexOf(prop) !== -1) {
continue;
}
toStream[prop] = typeof prop === 'function' ? fromStream[prop].bind(fromStream) : fromStream[prop];
}
};

4568
package-lock.json

File diff suppressed because it is too large

24
test/cache.js

@ -56,6 +56,18 @@ test.before('setup', async () => {
res.end('cache-then-no-store-on-revalidate'); res.end('cache-then-no-store-on-revalidate');
}); });
s.on('/redirect-dest', (req, res) => {
res.end('reached');
});
s.on('/redirect', (req, res) => {
res.setHeader('Cache-Control', 'public, max-age=60');
res.writeHead(301, {
location: `${s.url}/redirect-dest`
});
res.end();
});
await s.listen(s.port); await s.listen(s.port);
}); });
@ -192,6 +204,18 @@ test('Response objects have fromCache property set correctly', async t => {
t.true(cachedResponse.fromCache); t.true(cachedResponse.fromCache);
}); });
test('Cached redirects work correctly', async t => {
const endpoint = '/redirect';
const cache = new Map();
const response = await got(s.url + endpoint, {cache});
// const cachedResponse = await got(s.url + endpoint, {cache});
console.log(cache);
t.is(response.body, 'reached');
});
test.after('cleanup', async () => { test.after('cleanup', async () => {
await s.close(); await s.close();
}); });

Loading…
Cancel
Save