mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
chore: Clean up code related to headers.
This commit is contained in:
parent
f08617b1c9
commit
30ee0f8dc6
@ -95,7 +95,7 @@ class WebSocketListener extends EventEmitter {
|
|||||||
throw new Error(`Mismatched protocol: ${resolved.protocol} instead of ${this.protocol}`);
|
throw new Error(`Mismatched protocol: ${resolved.protocol} instead of ${this.protocol}`);
|
||||||
}
|
}
|
||||||
// Subscribe to the URL
|
// Subscribe to the URL
|
||||||
const url = resolved.toString();
|
const url = resolved.href;
|
||||||
this.subscribedPaths.add(url);
|
this.subscribedPaths.add(url);
|
||||||
this.sendMessage('ack', url);
|
this.sendMessage('ack', url);
|
||||||
this.logger.debug(`WebSocket subscribed to changes on ${url}`);
|
this.logger.debug(`WebSocket subscribed to changes on ${url}`);
|
||||||
|
@ -13,23 +13,25 @@ import { TargetExtractor } from './TargetExtractor';
|
|||||||
export class BasicTargetExtractor extends TargetExtractor {
|
export class BasicTargetExtractor extends TargetExtractor {
|
||||||
protected readonly logger = getLoggerFor(this);
|
protected readonly logger = getLoggerFor(this);
|
||||||
|
|
||||||
public async handle(request: HttpRequest): Promise<ResourceIdentifier> {
|
public async handle({ url, headers: { host }, connection }: HttpRequest): Promise<ResourceIdentifier> {
|
||||||
if (!request.url) {
|
if (!url) {
|
||||||
this.logger.error('The request has no URL');
|
this.logger.error('The request has no URL');
|
||||||
throw new Error('Missing URL');
|
throw new Error('Missing URL');
|
||||||
}
|
}
|
||||||
if (!request.headers.host) {
|
if (!host) {
|
||||||
this.logger.error('The request has no Host header');
|
this.logger.error('The request has no Host header');
|
||||||
throw new Error('Missing Host header');
|
throw new Error('Missing Host header');
|
||||||
}
|
}
|
||||||
|
if (/[/\\*]/u.test(host)) {
|
||||||
|
throw new Error(`The request has an invalid Host header: ${host}`);
|
||||||
|
}
|
||||||
|
|
||||||
const isHttps = request.connection && (request.connection as TLSSocket).encrypted;
|
const isHttps = (connection as TLSSocket)?.encrypted;
|
||||||
this.logger.debug(`Request is using HTTPS: ${isHttps}`);
|
this.logger.debug(`Request is using HTTPS: ${isHttps}`);
|
||||||
|
|
||||||
// URL object applies punycode encoding to domain
|
// URL object applies punycode encoding to domain
|
||||||
const base = `http${isHttps ? 's' : ''}://${request.headers.host}`;
|
const base = `http${isHttps ? 's' : ''}://${host}`;
|
||||||
const url = toCanonicalUriPath(request.url);
|
const path = new URL(toCanonicalUriPath(url), base).href;
|
||||||
const path = new URL(url, base).href;
|
|
||||||
|
|
||||||
return { path };
|
return { path };
|
||||||
}
|
}
|
||||||
|
@ -15,18 +15,28 @@ describe('A BasicTargetExtractor', (): void => {
|
|||||||
await expect(extractor.handle({ url: 'url', headers: {}} as any)).rejects.toThrow('Missing Host header');
|
await expect(extractor.handle({ url: 'url', headers: {}} as any)).rejects.toThrow('Missing Host header');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('errors if the host is invalid.', async(): Promise<void> => {
|
||||||
|
await expect(extractor.handle({ url: 'url', headers: { host: 'test.com/forbidden' }} as any))
|
||||||
|
.rejects.toThrow('The request has an invalid Host header: test.com/forbidden');
|
||||||
|
});
|
||||||
|
|
||||||
it('returns the input URL.', async(): Promise<void> => {
|
it('returns the input URL.', async(): Promise<void> => {
|
||||||
await expect(extractor.handle({ url: 'url', headers: { host: 'test.com' }} as any))
|
await expect(extractor.handle({ url: 'url', headers: { host: 'test.com' }} as any))
|
||||||
.resolves.toEqual({ path: 'http://test.com/url' });
|
.resolves.toEqual({ path: 'http://test.com/url' });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('supports host:port combinations.', async(): Promise<void> => {
|
||||||
|
await expect(extractor.handle({ url: 'url', headers: { host: 'localhost:3000' }} as any))
|
||||||
|
.resolves.toEqual({ path: 'http://localhost:3000/url' });
|
||||||
|
});
|
||||||
|
|
||||||
it('uses https protocol if the connection is secure.', async(): Promise<void> => {
|
it('uses https protocol if the connection is secure.', async(): Promise<void> => {
|
||||||
await expect(extractor.handle(
|
await expect(extractor.handle(
|
||||||
{ url: 'url', headers: { host: 'test.com' }, connection: { encrypted: true } as any } as any,
|
{ url: 'url', headers: { host: 'test.com' }, connection: { encrypted: true } as any } as any,
|
||||||
)).resolves.toEqual({ path: 'https://test.com/url' });
|
)).resolves.toEqual({ path: 'https://test.com/url' });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('encodes relevant characters.', async(): Promise<void> => {
|
it('encodes paths.', async(): Promise<void> => {
|
||||||
await expect(extractor.handle({ url: '/a%20path%26/name', headers: { host: 'test.com' }} as any))
|
await expect(extractor.handle({ url: '/a%20path%26/name', headers: { host: 'test.com' }} as any))
|
||||||
.resolves.toEqual({ path: 'http://test.com/a%20path%26/name' });
|
.resolves.toEqual({ path: 'http://test.com/a%20path%26/name' });
|
||||||
|
|
||||||
@ -36,4 +46,9 @@ describe('A BasicTargetExtractor', (): void => {
|
|||||||
await expect(extractor.handle({ url: '/path&%26/name', headers: { host: 'test.com' }} as any))
|
await expect(extractor.handle({ url: '/path&%26/name', headers: { host: 'test.com' }} as any))
|
||||||
.resolves.toEqual({ path: 'http://test.com/path%26%26/name' });
|
.resolves.toEqual({ path: 'http://test.com/path%26%26/name' });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('encodes hosts.', async(): Promise<void> => {
|
||||||
|
await expect(extractor.handle({ url: '/', headers: { host: '點看' }} as any))
|
||||||
|
.resolves.toEqual({ path: 'http://xn--c1yn36f/' });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,27 +1,16 @@
|
|||||||
|
import { createResponse } from 'node-mocks-http';
|
||||||
import { LinkRelMetadataWriter } from '../../../../../src/ldp/http/metadata/LinkRelMetadataWriter';
|
import { LinkRelMetadataWriter } from '../../../../../src/ldp/http/metadata/LinkRelMetadataWriter';
|
||||||
import { RepresentationMetadata } from '../../../../../src/ldp/representation/RepresentationMetadata';
|
import { RepresentationMetadata } from '../../../../../src/ldp/representation/RepresentationMetadata';
|
||||||
import * as util from '../../../../../src/util/HeaderUtil';
|
|
||||||
import { LDP, RDF } from '../../../../../src/util/UriConstants';
|
import { LDP, RDF } from '../../../../../src/util/UriConstants';
|
||||||
import { toNamedNode } from '../../../../../src/util/UriUtil';
|
import { toNamedNode } from '../../../../../src/util/UriUtil';
|
||||||
|
|
||||||
describe('A LinkRelMetadataWriter', (): void => {
|
describe('A LinkRelMetadataWriter', (): void => {
|
||||||
const writer = new LinkRelMetadataWriter({ [RDF.type]: 'type', dummy: 'dummy' });
|
const writer = new LinkRelMetadataWriter({ [RDF.type]: 'type', dummy: 'dummy' });
|
||||||
let mock: jest.SpyInstance;
|
|
||||||
let addHeaderMock: jest.Mock;
|
|
||||||
|
|
||||||
beforeEach(async(): Promise<void> => {
|
|
||||||
addHeaderMock = jest.fn();
|
|
||||||
mock = jest.spyOn(util, 'addHeader').mockImplementation(addHeaderMock);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(async(): Promise<void> => {
|
|
||||||
mock.mockRestore();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('adds the correct link headers.', async(): Promise<void> => {
|
it('adds the correct link headers.', async(): Promise<void> => {
|
||||||
|
const response = createResponse();
|
||||||
const metadata = new RepresentationMetadata({ [RDF.type]: toNamedNode(LDP.Resource), unused: 'text' });
|
const metadata = new RepresentationMetadata({ [RDF.type]: toNamedNode(LDP.Resource), unused: 'text' });
|
||||||
await expect(writer.handle({ response: 'response' as any, metadata })).resolves.toBeUndefined();
|
await expect(writer.handle({ response, metadata })).resolves.toBeUndefined();
|
||||||
expect(addHeaderMock).toHaveBeenCalledTimes(1);
|
expect(response.getHeaders()).toEqual({ link: `<${LDP.Resource}>; rel="type"` });
|
||||||
expect(addHeaderMock).toHaveBeenLastCalledWith('response', 'link', [ `<${LDP.Resource}>; rel="type"` ]);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,26 +1,15 @@
|
|||||||
|
import { createResponse } from 'node-mocks-http';
|
||||||
import { MappedMetadataWriter } from '../../../../../src/ldp/http/metadata/MappedMetadataWriter';
|
import { MappedMetadataWriter } from '../../../../../src/ldp/http/metadata/MappedMetadataWriter';
|
||||||
import { RepresentationMetadata } from '../../../../../src/ldp/representation/RepresentationMetadata';
|
import { RepresentationMetadata } from '../../../../../src/ldp/representation/RepresentationMetadata';
|
||||||
import * as util from '../../../../../src/util/HeaderUtil';
|
|
||||||
import { CONTENT_TYPE } from '../../../../../src/util/UriConstants';
|
import { CONTENT_TYPE } from '../../../../../src/util/UriConstants';
|
||||||
|
|
||||||
describe('A MappedMetadataWriter', (): void => {
|
describe('A MappedMetadataWriter', (): void => {
|
||||||
const writer = new MappedMetadataWriter({ [CONTENT_TYPE]: 'content-type', dummy: 'dummy' });
|
const writer = new MappedMetadataWriter({ [CONTENT_TYPE]: 'content-type', dummy: 'dummy' });
|
||||||
let mock: jest.SpyInstance;
|
|
||||||
let addHeaderMock: jest.Mock;
|
|
||||||
|
|
||||||
beforeEach(async(): Promise<void> => {
|
|
||||||
addHeaderMock = jest.fn();
|
|
||||||
mock = jest.spyOn(util, 'addHeader').mockImplementation(addHeaderMock);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(async(): Promise<void> => {
|
|
||||||
mock.mockRestore();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('adds metadata to the corresponding header.', async(): Promise<void> => {
|
it('adds metadata to the corresponding header.', async(): Promise<void> => {
|
||||||
|
const response = createResponse();
|
||||||
const metadata = new RepresentationMetadata({ [CONTENT_TYPE]: 'text/turtle', unused: 'text' });
|
const metadata = new RepresentationMetadata({ [CONTENT_TYPE]: 'text/turtle', unused: 'text' });
|
||||||
await expect(writer.handle({ response: 'response' as any, metadata })).resolves.toBeUndefined();
|
await expect(writer.handle({ response, metadata })).resolves.toBeUndefined();
|
||||||
expect(addHeaderMock).toHaveBeenCalledTimes(1);
|
expect(response.getHeaders()).toEqual({ 'content-type': 'text/turtle' });
|
||||||
expect(addHeaderMock).toHaveBeenLastCalledWith('response', 'content-type', [ 'text/turtle' ]);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user