mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
feat: allow server to bind to Unix Domain Sockets
This commit is contained in:
committed by
Joachim Van Herwegen
parent
0eb50891ec
commit
bf0e35be37
@@ -51,6 +51,7 @@ export function getDefaultVariables(port: number, baseUrl?: string): Record<stri
|
||||
return {
|
||||
'urn:solid-server:default:variable:baseUrl': baseUrl ?? `http://localhost:${port}/`,
|
||||
'urn:solid-server:default:variable:port': port,
|
||||
'urn:solid-server:default:variable:socket': null,
|
||||
'urn:solid-server:default:variable:loggingLevel': 'off',
|
||||
'urn:solid-server:default:variable:showStackTrace': true,
|
||||
'urn:solid-server:default:variable:seededPodConfigJson': null,
|
||||
|
||||
@@ -22,6 +22,18 @@ describe('ServerInitializer', (): void => {
|
||||
expect(serverFactory.startServer).toHaveBeenCalledWith(3000);
|
||||
});
|
||||
|
||||
it('starts a server on the specified Unix Domain Socket.', async(): Promise<void> => {
|
||||
initializer = new ServerInitializer(serverFactory, undefined, '/tmp/css.sock');
|
||||
await initializer.handle();
|
||||
expect(serverFactory.startServer).toHaveBeenCalledWith('/tmp/css.sock');
|
||||
});
|
||||
|
||||
it('throws when neither port or socket are set.', async(): Promise<void> => {
|
||||
expect((): void => {
|
||||
initializer = new ServerInitializer(serverFactory, undefined, undefined);
|
||||
}).toThrow('Either Port or Socket arguments must be set');
|
||||
});
|
||||
|
||||
it('can stop the server.', async(): Promise<void> => {
|
||||
await initializer.handle();
|
||||
await expect(initializer.finalize()).resolves.toBeUndefined();
|
||||
|
||||
@@ -16,6 +16,11 @@ describe('A BaseUrlExtractor', (): void => {
|
||||
await expect(computer.handle({ port: 3333 })).resolves.toBe('http://localhost:3333/');
|
||||
});
|
||||
|
||||
it('throws when a Unix Socket Path is provided without a baseUrl.', async(): Promise<void> => {
|
||||
await expect(computer.handle({ socket: '/tmp/css.sock' })).rejects
|
||||
.toThrow('BaseUrl argument should be provided when using Unix Domain Sockets.');
|
||||
});
|
||||
|
||||
it('defaults to port 3000.', async(): Promise<void> => {
|
||||
await expect(computer.handle({})).resolves.toBe('http://localhost:3000/');
|
||||
});
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { mkdirSync } from 'fs';
|
||||
import type { Server } from 'http';
|
||||
import request from 'supertest';
|
||||
import type { BaseHttpServerOptions } from '../../../src/server/BaseHttpServerFactory';
|
||||
@@ -5,7 +6,8 @@ import { BaseHttpServerFactory } from '../../../src/server/BaseHttpServerFactory
|
||||
import type { HttpHandler } from '../../../src/server/HttpHandler';
|
||||
import type { HttpResponse } from '../../../src/server/HttpResponse';
|
||||
import { joinFilePath } from '../../../src/util/PathUtil';
|
||||
import { getPort } from '../../util/Util';
|
||||
import { getTestFolder, removeFolder } from '../../integration/Config';
|
||||
import { getPort, getSocket } from '../../util/Util';
|
||||
|
||||
const port = getPort('BaseHttpServerFactory');
|
||||
|
||||
@@ -125,4 +127,91 @@ describe('A BaseHttpServerFactory', (): void => {
|
||||
expect(res.text).toBe(`${error.stack}\n`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('A Base HttpServerFactory (With Unix Sockets)', (): void => {
|
||||
const socketFolder = getTestFolder('sockets');
|
||||
const socket = joinFilePath(socketFolder, getSocket('BaseHttpServerFactory'));
|
||||
const httpOptions = {
|
||||
http: true,
|
||||
showStackTrace: true,
|
||||
};
|
||||
|
||||
beforeAll(async(): Promise<void> => {
|
||||
mkdirSync(socketFolder, { recursive: true });
|
||||
});
|
||||
|
||||
afterAll(async(): Promise<void> => {
|
||||
server.close();
|
||||
await removeFolder(socketFolder);
|
||||
});
|
||||
|
||||
beforeEach(async(): Promise<void> => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
describe('On linux', (): void => {
|
||||
if (process.platform === 'win32') {
|
||||
return;
|
||||
}
|
||||
it('sends incoming requests to the handler.', async(): Promise<void> => {
|
||||
const factory = new BaseHttpServerFactory(handler, httpOptions);
|
||||
server = factory.startServer(socket);
|
||||
await request(`http+unix://${socket.replace(/\//gui, '%2F')}`).get('/').set('Host', 'test.com').expect(200);
|
||||
|
||||
expect(handler.handleSafe).toHaveBeenCalledTimes(1);
|
||||
expect(handler.handleSafe).toHaveBeenLastCalledWith({
|
||||
request: expect.objectContaining({
|
||||
headers: expect.objectContaining({ host: 'test.com' }),
|
||||
}),
|
||||
response: expect.objectContaining({}),
|
||||
});
|
||||
});
|
||||
|
||||
it('throws an error on windows.', async(): Promise<void> => {
|
||||
const prevPlatform = process.platform;
|
||||
Object.defineProperty(process, 'platform', {
|
||||
value: 'win32',
|
||||
});
|
||||
|
||||
const factory = new BaseHttpServerFactory(handler, httpOptions);
|
||||
expect((): void => {
|
||||
factory.startServer(socket);
|
||||
}).toThrow();
|
||||
|
||||
Object.defineProperty(process, 'platform', {
|
||||
value: prevPlatform,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('On Windows', (): void => {
|
||||
if (process.platform !== 'win32') {
|
||||
return;
|
||||
}
|
||||
it('throws an error when trying to start the server on windows.', async(): Promise<void> => {
|
||||
const factory = new BaseHttpServerFactory(handler, httpOptions);
|
||||
expect((): void => {
|
||||
factory.startServer(socket);
|
||||
}).toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('On any platform', (): void => {
|
||||
it('throws an error when trying to start with an invalid socket Path.', async(): Promise<void> => {
|
||||
const prevPlatform = process.platform;
|
||||
Object.defineProperty(process, 'platform', {
|
||||
value: 'linux',
|
||||
});
|
||||
|
||||
const factory = new BaseHttpServerFactory(handler, httpOptions);
|
||||
factory.startServer('/fake/path')
|
||||
.on('error', (error): void => {
|
||||
expect(error).toHaveProperty('code', 'EACCES');
|
||||
});
|
||||
|
||||
Object.defineProperty(process, 'platform', {
|
||||
value: prevPlatform,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -33,6 +33,11 @@ const portNames = [
|
||||
'BaseHttpServerFactory',
|
||||
] as const;
|
||||
|
||||
const socketNames = [
|
||||
// Unit
|
||||
'BaseHttpServerFactory',
|
||||
];
|
||||
|
||||
export function getPort(name: typeof portNames[number]): number {
|
||||
const idx = portNames.indexOf(name);
|
||||
// Just in case something doesn't listen to the typings
|
||||
@@ -42,6 +47,15 @@ export function getPort(name: typeof portNames[number]): number {
|
||||
return 6000 + idx;
|
||||
}
|
||||
|
||||
export function getSocket(name: typeof socketNames[number]): string {
|
||||
const idx = socketNames.indexOf(name);
|
||||
// Just in case something doesn't listen to the typings
|
||||
if (idx < 0) {
|
||||
throw new Error(`Unknown socket name ${name}`);
|
||||
}
|
||||
return `css${idx}.sock`;
|
||||
}
|
||||
|
||||
export function describeIf(envFlag: string): Describe {
|
||||
const flag = `TEST_${envFlag.toUpperCase()}`;
|
||||
const enabled = !/^(|0|false)$/iu.test(process.env[flag] ?? '');
|
||||
|
||||
Reference in New Issue
Block a user