Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 35 additions & 2 deletions lib/response.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,39 @@ var res = Object.create(http.ServerResponse.prototype)

module.exports = res

/**
* The results of `mime.contentType`, by the value it was given: a response
* sets one of a handful of types, and each lookup through the mime database
* costs a few hundred nanoseconds.
* @private
*/

var contentTypeCache = new Map();

/**
* `mime.contentType`, memoised.
*
* @param {String} value
* @return {String|Boolean}
* @private
*/

function cachedContentType(value) {
var resolved = contentTypeCache.get(value);

if (resolved === undefined) {
resolved = mime.contentType(value);

if (contentTypeCache.size >= 100) {
contentTypeCache.clear();
}

contentTypeCache.set(value, resolved);
}

return resolved;
}

/**
* Set the HTTP status code for the response.
*
Expand Down Expand Up @@ -507,7 +540,7 @@ res.download = function download (path, filename, options, callback) {
res.contentType =
res.type = function contentType(type) {
var ct = type.indexOf('/') === -1
? (mime.contentType(type) || 'application/octet-stream')
? (cachedContentType(type) || 'application/octet-stream')
: type;

return this.set('Content-Type', ct);
Expand Down Expand Up @@ -678,7 +711,7 @@ res.header = function header(field, val) {
if (Array.isArray(value)) {
throw new TypeError('Content-Type cannot be set to an Array');
}
value = mime.contentType(value)
value = cachedContentType(value)
}

this.setHeader(field, value);
Expand Down
41 changes: 35 additions & 6 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,16 @@ exports.compileTrust = function(val) {
return proxyaddr.compile(val || []);
}

/**
* The results of setCharset, a map of type to result per charset: the same
* few types come through on every response, and parsing and formatting each
* costs a few hundred nanoseconds. One map per charset, since a key made by
* joining the two strings would be hashed again on every call.
* @private
*/

var setCharsetCache = new Map();

/**
* Set the charset in a given Content-Type string.
*
Expand All @@ -227,14 +237,33 @@ exports.setCharset = function setCharset(type, charset) {
return type;
}

// parse type
var parsed = contentType.parse(type);
var byType = setCharsetCache.get(charset);

if (byType === undefined) {
byType = new Map();
setCharsetCache.set(charset, byType);
}

var formatted = byType.get(type);

if (formatted === undefined) {
// parse type
var parsed = contentType.parse(type);

// set charset
parsed.parameters.charset = charset;

// format type
formatted = contentType.format(parsed);

// set charset
parsed.parameters.charset = charset;
if (byType.size >= 100) {
byType.clear();
}

byType.set(type, formatted);
}

// format type
return contentType.format(parsed);
return formatted;
};

/**
Expand Down