Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
refactor: reuse functions and improve readability
  • Loading branch information
anonrig committed Oct 4, 2022
commit 1beeff78f04322c291beb4bfac0bc4a0be1be428
78 changes: 16 additions & 62 deletions lib/_http_server.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ const {
const {
validateInteger,
validateBoolean,
validateLinkHeaderValue
validateLinkHeaderValue,
} = require('internal/validators');
const Buffer = require('buffer').Buffer;
const { setInterval, clearInterval } = require('timers');
Expand Down Expand Up @@ -296,81 +296,35 @@ ServerResponse.prototype.writeProcessing = function writeProcessing(cb) {
this._writeRaw('HTTP/1.1 102 Processing\r\n\r\n', 'ascii', cb);
};

ServerResponse.prototype.writeEarlyHints = function writeEarlyHints(links, cb) {
ServerResponse.prototype.writeEarlyHints = function writeEarlyHints(hints, cb) {
let head = 'HTTP/1.1 103 Early Hints\r\n';

if (typeof links === 'string') {
validateLinkHeaderValue(links, 'links');
head += 'Link: ' + links + '\r\n';
} else if (ArrayIsArray(links)) {
if (!links.length) {
if (!ArrayIsArray(hints) && typeof hints === 'object') {
if (hints.link === null || hints.link === undefined) {
return;
}

head += 'Link: ';
const link = validateLinkHeaderValue(hints.link);

for (let i = 0; i < links.length; i++) {
const link = links[i];
validateLinkHeaderValue(link, 'links');
head += link;

if (i !== links.length - 1) {
head += ', ';
}
}

head += '\r\n';
} else if (typeof links === 'object') {
const keys = ObjectKeys(links);

if (!keys.length) {
if (link.length === 0) {
return;
}

const link = links.link;
head += 'Link: ' + link + '\r\n';

if (typeof link === 'string') {
validateLinkHeaderValue(link, 'links');
head += 'Link: ' + link + '\r\n';
} else if (ArrayIsArray(link)) {
const linkLength = link.length;
if (!linkLength) {
return;
}

head += 'Link: ';

for (let i = 0; i < linkLength; i++) {
validateLinkHeaderValue(link[i], 'links');
head += link[i];

if (i !== linkLength - 1) {
head += ', ';
}
for (const key of ObjectKeys(hints)) {
if (key !== 'link') {
head += key + ': ' + hints[key] + '\r\n';
}

head += '\r\n';
} else {
throw new ERR_INVALID_ARG_VALUE(
'links',
links,
'must be an array, object or string of format "</styles.css>; rel=preload; as=style"'
);
}
} else {
const link = validateLinkHeaderValue(hints);

for (const key of keys) {
if (key === 'link') {
continue;
}

head += key + ': ' + links[key] + '\r\n';
if (link.length === 0) {
return;
}
} else {
throw new ERR_INVALID_ARG_VALUE(
'links',
links,
'must be an array, object or string of format "</styles.css>; rel=preload; as=style"'
);

head += 'Link: ' + link + '\r\n';
}

head += '\r\n';
Expand Down
75 changes: 12 additions & 63 deletions lib/internal/http2/compat.js
Original file line number Diff line number Diff line change
Expand Up @@ -847,75 +847,24 @@ class Http2ServerResponse extends Stream {
return true;
}

writeEarlyHints(links) {
writeEarlyHints(hints) {
const headers = ObjectCreate(null);
let linkHeaderValue = '';

if (typeof links === 'string') {
validateLinkHeaderValue(links, 'links');
linkHeaderValue += links;
} else if (ArrayIsArray(links)) {
if (!links.length) {
return;
}

linkHeaderValue += '';

for (let i = 0; i < links.length; i++) {
const link = links[i];
validateLinkHeaderValue(link, 'links');
linkHeaderValue += link;

if (i !== links.length - 1) {
linkHeaderValue += ', ';
}
}
} else if (typeof links === 'object') {
const keys = ObjectKeys(links);

if (!keys.length) {
return;
}

const link = links.link;
if (!ArrayIsArray(hints) && typeof hints === 'object') {
linkHeaderValue += validateLinkHeaderValue(hints.link);

if (typeof link === 'string') {
validateLinkHeaderValue(link, 'links');
linkHeaderValue += link;
} else if (ArrayIsArray(link)) {
if (!link.length) {
return;
for (const key of ObjectKeys(hints)) {
if (key !== 'link') {
headers[key] = hints[key];
}

for (let i = 0; i < link.length; i++) {
validateLinkHeaderValue(link[i]);
linkHeaderValue += link;

if (i !== link.length - 1) {
linkHeaderValue += ', ';
}
}
} else {
throw new ERR_INVALID_ARG_VALUE(
'links',
links,
'must be an array, object or string of format "</styles.css>; rel=preload; as=style"'
);
}

for (const key of keys) {
if (key === 'link') {
continue;
}

headers[key] = links[key];
}
} else {
throw new ERR_INVALID_ARG_VALUE(
'links',
links,
'must be an array, object or string of format "</styles.css>; rel=preload; as=style"'
);
linkHeaderValue += validateLinkHeaderValue(hints);
}

if (linkHeaderValue.length === 0) {
return false;
}

const stream = this[kStream];
Expand All @@ -924,9 +873,9 @@ class Http2ServerResponse extends Stream {
return false;

stream.additionalHeaders({
...headers,
[HTTP2_HEADER_STATUS]: HTTP_STATUS_EARLY_HINTS,
'Link': linkHeaderValue,
...headers
});

return true;
Expand Down
44 changes: 42 additions & 2 deletions lib/internal/validators.js
Original file line number Diff line number Diff line change
Expand Up @@ -403,9 +403,13 @@ function validateUnion(value, name, union) {
}
}

function validateLinkHeaderValue(value, name) {
const linkValueRegExp = /^(?:<[^>]*>;)\s*(?:rel=(")?[^;"]*\1;?)\s*(?:(?:as|anchor|title)=(")?[^;"]*\2)?$/;
const linkValueRegExp = /^(?:<[^>]*>;)\s*(?:rel=(")?[^;"]*\1;?)\s*(?:(?:as|anchor|title)=(")?[^;"]*\2)?$/;
Comment thread
anonrig marked this conversation as resolved.

/**
* @param {any} value
* @param {string} name
*/
function validateLinkHeaderFormat(value, name) {
if (
typeof value === 'undefined' ||
!RegExpPrototypeExec(linkValueRegExp, value)
Expand All @@ -424,6 +428,42 @@ const validateInternalField = hideStackFrames((object, fieldKey, className) => {
}
});

/**
* @param {any} hints
* @return {string}
*/
function validateLinkHeaderValue(hints) {
if (typeof hints === 'string') {
validateLinkHeaderFormat(hints, 'hints');
return hints;
} else if (ArrayIsArray(hints)) {
const hintsLength = hints.length;
let result = '';

if (hintsLength === 0) {
return result;
}

for (let i = 0; i < hintsLength; i++) {
const link = hints[i];
validateLinkHeaderFormat(link, 'hints');
result += link;

if (i !== hintsLength - 1) {
result += ', ';
}
}

return result;
}

throw new ERR_INVALID_ARG_VALUE(
'hints',
hints,
'must be an array or string of format "</styles.css>; rel=preload; as=style"'
);
}

module.exports = {
isInt32,
isUint32,
Expand Down