only allow body to be consumed once, add some tests

This commit is contained in:
Randall Schmidt 2021-06-10 11:11:33 -04:00
parent c3071e3059
commit f92bd99968
3 changed files with 58 additions and 4 deletions

@ -7,22 +7,32 @@ class Response {
this.cacheFilePath = cacheFilePath; this.cacheFilePath = cacheFilePath;
this.headers = new Headers(raw.headers); this.headers = new Headers(raw.headers);
this.fromCache = fromCache; this.fromCache = fromCache;
this.consumed = false;
if (this.bodyBuffer.type === 'Buffer') { if (this.bodyBuffer.type === 'Buffer') {
this.bodyBuffer = Buffer.from(this.bodyBuffer); this.bodyBuffer = Buffer.from(this.bodyBuffer);
} }
} }
consumeBody() {
if (this.consumed) {
throw new Error('Error: body used already');
}
this.consumed = true;
return this.bodyBuffer;
}
text() { text() {
return this.bodyBuffer.toString(); return this.consumeBody().toString();
} }
json() { json() {
return JSON.parse(this.bodyBuffer.toString()); return JSON.parse(this.consumeBody().toString());
} }
buffer() { buffer() {
return this.bodyBuffer; return this.consumeBody();
} }
async ejectFromCache() { async ejectFromCache() {

@ -3,7 +3,6 @@ const fs = require('fs');
const { URLSearchParams } = require('url'); const { URLSearchParams } = require('url');
const crypto = require('crypto'); const crypto = require('crypto');
const path = require('path'); const path = require('path');
const Response = require('./classes/response.js'); const Response = require('./classes/response.js');
const CACHE_VERSION = 2; const CACHE_VERSION = 2;
@ -12,6 +11,9 @@ function md5(str) {
return crypto.createHash('md5').update(str).digest('hex'); return crypto.createHash('md5').update(str).digest('hex');
} }
// Since the bounday in FormData is random,
// we ignore it for purposes of calculating
// the cache key.
function getFormDataCacheKey(formData) { function getFormDataCacheKey(formData) {
const cacheKey = { ...formData }; const cacheKey = { ...formData };

@ -7,11 +7,15 @@ const FetchCache = require('../index.js');
const { URLSearchParams } = require('url'); const { URLSearchParams } = require('url');
const CACHE_PATH = path.join(__dirname, '..', '.cache'); const CACHE_PATH = path.join(__dirname, '..', '.cache');
const expectedPngBuffer = fs.readFileSync(path.join(__dirname, 'expected_png.png'));
const TWO_HUNDRED_URL = 'https://httpbin.org/status/200'; const TWO_HUNDRED_URL = 'https://httpbin.org/status/200';
const FOUR_HUNDRED_URL = 'https://httpbin.org/status/400'; const FOUR_HUNDRED_URL = 'https://httpbin.org/status/400';
const THREE_HUNDRED_TWO_URL = 'https://httpbin.org/status/302'; const THREE_HUNDRED_TWO_URL = 'https://httpbin.org/status/302';
const TEXT_BODY_URL = 'https://httpbin.org/robots.txt'; const TEXT_BODY_URL = 'https://httpbin.org/robots.txt';
const JSON_BODY_URL = 'https://httpbin.org/json';
const PNG_BODY_URL = 'https://httpbin.org/image/png';
const TEXT_BODY_EXPECTED = 'User-agent: *\nDisallow: /deny\n'; const TEXT_BODY_EXPECTED = 'User-agent: *\nDisallow: /deny\n';
let fetch; let fetch;
@ -195,13 +199,51 @@ describe('Cache tests', function() {
}).timeout(10000); }).timeout(10000);
describe('Data tests', function() { describe('Data tests', function() {
it('Refuses to consume body twice', async function() {
res = await fetch(TEXT_BODY_URL);
await res.text();
try {
await res.text();
throw new Error('The above line should have thrown.');
} catch (err) {
// It threw
}
});
it('Can get text body', async function() { it('Can get text body', async function() {
res = await fetch(TEXT_BODY_URL); res = await fetch(TEXT_BODY_URL);
body = await res.text(); body = await res.text();
assert.strictEqual(body, TEXT_BODY_EXPECTED); assert.strictEqual(body, TEXT_BODY_EXPECTED);
assert.strictEqual(res.fromCache, false);
res = await fetch(TEXT_BODY_URL); res = await fetch(TEXT_BODY_URL);
body = await res.text(); body = await res.text();
assert.strictEqual(body, TEXT_BODY_EXPECTED); assert.strictEqual(body, TEXT_BODY_EXPECTED);
assert.strictEqual(res.fromCache, true);
});
it('Can get JSON body', async function() {
res = await fetch(JSON_BODY_URL);
body = await res.json();
assert(body.slideshow);
assert.strictEqual(res.fromCache, false);
res = await fetch(JSON_BODY_URL);
body = await res.json();
assert(body.slideshow);
assert.strictEqual(res.fromCache, true);
});
it('Can get PNG buffer body', async function() {
res = await fetch(PNG_BODY_URL);
body = await res.buffer();
assert.strictEqual(expectedPngBuffer.equals(body), true);
assert.strictEqual(res.fromCache, false);
res = await fetch(PNG_BODY_URL);
body = await res.buffer();
assert.strictEqual(expectedPngBuffer.equals(body), true);
assert.strictEqual(res.fromCache, true);
}); });
}).timeout(10000); }).timeout(10000);