Skip to content

Commit

Permalink
fix: use undecoded @path, @query and @query-param according to the spec
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexanderTar committed Jan 15, 2024
1 parent f52b0ee commit c086d9f
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 4 deletions.
10 changes: 6 additions & 4 deletions src/httpbis/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,9 @@ export function deriveComponent(component: string, params: Map<string, string |
throw new Error('Cannot derive @scheme on response');
}
const { pathname } = typeof context.url === 'string' ? new URL(context.url) : context.url;
return [decodeURI(pathname)];
// https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-message-signatures#section-2.2.6
// empty path means use `/`
return [pathname || '/'];
}
case '@query': {
if (!isRequest(context)) {
Expand All @@ -102,7 +104,7 @@ export function deriveComponent(component: string, params: Map<string, string |
const { search } = typeof context.url === 'string' ? new URL(context.url) : context.url;
// https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-message-signatures#section-2.2.7
// absent query params means use `?`
return [decodeURI(search) || '?'];
return [search || '?'];
}
case '@query-param': {
if (!isRequest(context)) {
Expand All @@ -112,11 +114,11 @@ export function deriveComponent(component: string, params: Map<string, string |
if (!params.has('name')) {
throw new Error('@query-param must have a named parameter');
}
const name = (params.get('name') as BareItem).toString();
const name = decodeURIComponent((params.get('name') as BareItem).toString());
if (!searchParams.has(name)) {
throw new Error(`Expected query parameter "${name}" not found`);
}
return searchParams.getAll(name);
return searchParams.getAll(name).map((value) => encodeURIComponent(value));
}
case '@status': {
if (isRequest(context)) {
Expand Down
92 changes: 92 additions & 0 deletions test/httpbis/httpbis.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,12 +168,36 @@ describe('httpbis', () => {
expect(httpbis.deriveComponent('@path', new Map(), req)).to.deep.equal([
'/path',
]);
expect(httpbis.deriveComponent('@path', new Map(), {
...req,
url: 'https://www.example.com/path%7D?param=value',
})).to.deep.equal([
'/path%7D',
]);
expect(httpbis.deriveComponent('@path', new Map(), {
...req,
url: 'https://www.example.com',
})).to.deep.equal([
'/',
]);
expect(httpbis.deriveComponent('@path', new Map(), {
...req,
url: new URL(req.url as string),
})).to.deep.equal([
'/path',
]);
expect(httpbis.deriveComponent('@path', new Map(), {
...req,
url: new URL('https://www.example.com/path%7D?param=value'),
})).to.deep.equal([
'/path%7D',
]);
expect(httpbis.deriveComponent('@path', new Map(), {
...req,
url: new URL('https://www.example.com'),
})).to.deep.equal([
'/',
]);
});
it('derives @query', () => {
const req: Request = {
Expand All @@ -198,6 +222,18 @@ describe('httpbis', () => {
})).to.deep.equal([
'?',
]);
expect(httpbis.deriveComponent('@query', new Map(), {
...req,
url: 'https://www.example.com//path?param=value&foo=bar&baz=bat%2Dman',
})).to.deep.equal([
'?param=value&foo=bar&baz=bat%2Dman',
]);
expect(httpbis.deriveComponent('@query', new Map(), {
...req,
url: 'https://www.example.com/path',
})).to.deep.equal([
'?',
]);
// with URL objects
expect(httpbis.deriveComponent('@query', new Map(), {
...req,
Expand All @@ -211,6 +247,12 @@ describe('httpbis', () => {
})).to.deep.equal([
'?queryString',
]);
expect(httpbis.deriveComponent('@query', new Map(), {
...req,
url: new URL('https://www.example.com//path?param=value&foo=bar&baz=bat%2Dman'),
})).to.deep.equal([
'?param=value&foo=bar&baz=bat%2Dman',
]);
expect(httpbis.deriveComponent('@query', new Map(), {
...req,
url: new URL('https://www.example.com/path'),
Expand Down Expand Up @@ -242,6 +284,31 @@ describe('httpbis', () => {
'value',
'value2',
]);
expect(httpbis.deriveComponent('@query-param', new Map([['name', 'param']]), {
...req,
url: 'https://example.com/path?param=value%7D&param=value2%7D',
})).to.deep.equal([
'value%7D',
'value2%7D',
]);
expect(httpbis.deriveComponent('@query-param', new Map([['name', 'var']]), {
...req,
url: 'https://example.com/parameters?var=this%20is%20a%20big%0Amultiline%20value&bar=with+plus+whitespace&fa%C3%A7ade%22%3A%20=something',
})).to.deep.equal([
'this%20is%20a%20big%0Amultiline%20value',
]);
expect(httpbis.deriveComponent('@query-param', new Map([['name', 'bar']]), {
...req,
url: 'https://example.com/parameters?var=this%20is%20a%20big%0Amultiline%20value&bar=with+plus+whitespace&fa%C3%A7ade%22%3A%20=something',
})).to.deep.equal([
'with%20plus%20whitespace',
]);
expect(httpbis.deriveComponent('@query-param', new Map([['name', 'fa%C3%A7ade%22%3A%20']]), {
...req,
url: 'https://example.com/parameters?var=this%20is%20a%20big%0Amultiline%20value&bar=with+plus+whitespace&fa%C3%A7ade%22%3A%20=something',
})).to.deep.equal([
'something',
]);
// with URL objects
expect(httpbis.deriveComponent('@query-param', new Map([['name', 'baz']]), {
...req,
Expand All @@ -268,6 +335,31 @@ describe('httpbis', () => {
'value',
'value2',
]);
expect(httpbis.deriveComponent('@query-param', new Map([['name', 'param']]), {
...req,
url: new URL('https://example.com/path?param=value%7D&param=value2%7D'),
})).to.deep.equal([
'value%7D',
'value2%7D',
]);
expect(httpbis.deriveComponent('@query-param', new Map([['name', 'var']]), {
...req,
url: new URL('https://example.com/parameters?var=this%20is%20a%20big%0Amultiline%20value&bar=with+plus+whitespace&fa%C3%A7ade%22%3A%20=something'),
})).to.deep.equal([
'this%20is%20a%20big%0Amultiline%20value',
]);
expect(httpbis.deriveComponent('@query-param', new Map([['name', 'bar']]), {
...req,
url: new URL('https://example.com/parameters?var=this%20is%20a%20big%0Amultiline%20value&bar=with+plus+whitespace&fa%C3%A7ade%22%3A%20=something'),
})).to.deep.equal([
'with%20plus%20whitespace',
]);
expect(httpbis.deriveComponent('@query-param', new Map([['name', 'fa%C3%A7ade%22%3A%20']]), {
...req,
url: new URL('https://example.com/parameters?var=this%20is%20a%20big%0Amultiline%20value&bar=with+plus+whitespace&fa%C3%A7ade%22%3A%20=something'),
})).to.deep.equal([
'something',
]);
});
it('derives @status', () => {
const req: Request = {
Expand Down

0 comments on commit c086d9f

Please sign in to comment.