Skip to content

Commit 54a5565

Browse files
pcattoriMichaelDeBoey
authored andcommitted
Add support for HTTP2 pseudo headers (#55)
* fix(headers): do not depend on `http` for header name validation Node internally uses undici instead anyway * fix(headers): support HTTP2 pseudo-headers which begin with `:` e.g. `:authority`, `:method`, etc. * test(headers): check that pseudo-headers are allowed
1 parent e55e8cf commit 54a5565

File tree

3 files changed

+36
-20
lines changed

3 files changed

+36
-20
lines changed

.changeset/wise-dogs-clean.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@remix-run/web-fetch": patch
3+
---
4+
5+
Support HTTP2 pseudo-headers like `:authority`, `:method`, etc.

packages/fetch/src/headers.js

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,25 @@ import {types} from 'util';
88
import http from 'http';
99
import { isIterable } from './utils/is.js'
1010

11-
const validators = /** @type {{validateHeaderName?:(name:string) => any, validateHeaderValue?:(name:string, value:string) => any}} */
12-
(http)
11+
/** @type {{validateHeaderValue?:(name:string, value:string) => any}} */
12+
const validators = (http)
1313

14-
const validateHeaderName = typeof validators.validateHeaderName === 'function' ?
15-
validators.validateHeaderName :
16-
/**
17-
* @param {string} name
18-
*/
19-
name => {
20-
if (!/^[\^`\-\w!#$%&'*+.|~]+$/.test(name)) {
21-
const err = new TypeError(`Header name must be a valid HTTP token [${name}]`);
22-
Object.defineProperty(err, 'code', {value: 'ERR_INVALID_HTTP_TOKEN'});
23-
throw err;
24-
}
25-
};
14+
/**
15+
* @param {string} name
16+
*/
17+
const validateHeaderName = name => {
18+
if (!/^[\^`\-\w!#$%&'*+.|~:]+$/.test(name)) {
19+
const err = new TypeError(`Header name must be a valid HTTP token [${name}]`);
20+
Object.defineProperty(err, 'code', {value: 'ERR_INVALID_HTTP_TOKEN'});
21+
throw err;
22+
}
23+
};
2624

2725
const validateHeaderValue = typeof validators.validateHeaderValue === 'function' ?
2826
validators.validateHeaderValue :
2927
/**
30-
* @param {string} name
31-
* @param {string} value
28+
* @param {string} name
29+
* @param {string} value
3230
*/
3331
(name, value) => {
3432
if (/[^\t\u0020-\u007E\u0080-\u00FF]/.test(value)) {
@@ -166,8 +164,8 @@ export default class Headers extends URLSearchParams {
166164
}
167165

168166
/**
169-
*
170-
* @param {string} name
167+
*
168+
* @param {string} name
171169
*/
172170
get(name) {
173171
const values = this.getAll(name);
@@ -184,8 +182,8 @@ export default class Headers extends URLSearchParams {
184182
}
185183

186184
/**
187-
* @param {(value: string, key: string, parent: this) => void} callback
188-
* @param {any} thisArg
185+
* @param {(value: string, key: string, parent: this) => void} callback
186+
* @param {any} thisArg
189187
* @returns {void}
190188
*/
191189
forEach(callback, thisArg = undefined) {

packages/fetch/test/headers.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,19 @@ describe('Headers', () => {
216216
expect(() => headers.append('', 'ok')).to.throw(TypeError);
217217
});
218218

219+
it('should allow HTTP2 pseudo-headers', () => {
220+
let headers = new Headers({':authority': 'something'});
221+
headers.append(":method", "something else")
222+
223+
const result = [];
224+
for (const pair of headers) {
225+
result.push(pair);
226+
}
227+
228+
expect(result).to.deep.equal([[':authority', 'something'], [':method', 'something else']]);
229+
230+
})
231+
219232
it('should ignore unsupported attributes while reading headers', () => {
220233
const FakeHeader = function () { };
221234
// Prototypes are currently ignored

0 commit comments

Comments
 (0)