hapi
Version:
HTTP Server framework
201 lines (143 loc) • 5.55 kB
JavaScript
;
const Stream = require('stream');
const Boom = require('boom');
const Response = require('./response');
const internals = {};
exports.cache = function (request) {
const response = request.response;
if (response.headers['cache-control']) {
return;
}
const settings = request.route.settings.cache;
const policy = settings && request._route._cache && (settings._statuses.has(response.statusCode) || (response.statusCode === 304 && settings._statuses.has(200)));
if (policy ||
response.settings.ttl) {
const ttl = (response.settings.ttl !== null ? response.settings.ttl : request._route._cache.ttl());
const privacy = (request.auth.isAuthenticated || response.headers['set-cookie'] ? 'private' : settings.privacy || 'default');
response._header('cache-control', 'max-age=' + Math.floor(ttl / 1000) + ', must-revalidate' + (privacy !== 'default' ? ', ' + privacy : ''));
}
else if (settings) {
response._header('cache-control', settings.otherwise);
}
};
exports.content = async function (request) {
const response = request.response;
if (response._isPayloadSupported() ||
request.method === 'head') {
await response._marshal();
if (request.jsonp &&
response._payload.jsonp) {
response._header('content-type', 'text/javascript' + (response.settings.charset ? '; charset=' + response.settings.charset : ''));
response._header('x-content-type-options', 'nosniff');
response._payload.jsonp(request.jsonp);
}
if (response._payload.size &&
typeof response._payload.size === 'function') {
response._header('content-length', response._payload.size(), { override: false });
}
if (!response._isPayloadSupported()) {
response._close(request); // Close unused file streams
response._payload = new internals.Empty(); // Set empty stream
}
exports.type(request, true);
}
else {
// Set empty stream
response._close(request); // Close unused file streams
response._payload = new internals.Empty();
delete response.headers['content-length'];
}
};
exports.state = async function (request) {
const response = request.response;
const states = [];
for (const stateName in request._states) {
states.push(request._states[stateName]);
}
try {
for (const name in request._core.states.cookies) {
const autoValue = request._core.states.cookies[name].autoValue;
if (!autoValue || name in request._states || name in request.state) {
continue;
}
if (typeof autoValue !== 'function') {
states.push({ name, value: autoValue });
continue;
}
const value = await autoValue(request);
states.push({ name, value });
}
if (!states.length) {
return;
}
let header = await request._core.states.format(states);
const existing = response.headers['set-cookie'];
if (existing) {
header = (Array.isArray(existing) ? existing : [existing]).concat(header);
}
response._header('set-cookie', header);
}
catch (err) {
const error = Boom.boomify(err);
request._log(['state', 'response', 'error'], error);
request._states = {}; // Clear broken state
throw error;
}
};
exports.type = function (request, postMarshal) {
const response = request.response;
let type = response.headers['content-type'];
if (!type) {
if (response._contentType) {
const charset = (response.settings.charset && response._contentType !== 'application/octet-stream' ? '; charset=' + response.settings.charset : '');
response.type(response._contentType + charset);
}
}
else {
type = type.trim();
if ((!response._contentType || !postMarshal) &&
response.settings.charset &&
type.match(/^(?:text\/)|(?:application\/(?:json)|(?:javascript))/)) {
if (!type.match(/; *charset=/)) {
const semi = (type[type.length - 1] === ';');
response.type(type + (semi ? ' ' : '; ') + 'charset=' + (response.settings.charset));
}
}
}
};
exports.entity = function (request) {
if (!request._entity) {
return;
}
const response = request.response;
if (request._entity.etag &&
!response.headers.etag) {
response.etag(request._entity.etag, { vary: request._entity.vary });
}
if (request._entity.modified &&
!response.headers['last-modified']) {
response.header('last-modified', request._entity.modified);
}
};
exports.unmodified = function (request) {
const response = request.response;
if (response.statusCode === 304) {
return;
}
const entity = {
etag: response.headers.etag,
vary: response.settings.varyEtag,
modified: response.headers['last-modified']
};
if (Response.unmodified(request, entity)) {
response.code(304);
}
};
internals.Empty = class extends Stream.Readable {
_read(/* size */) {
this.push(null);
}
writeToStream(stream) {
stream.end();
}
};