feat: allow server to bind to Unix Domain Sockets

This commit is contained in:
Koen Luyten
2022-11-17 16:57:20 +01:00
committed by Joachim Van Herwegen
parent 0eb50891ec
commit bf0e35be37
15 changed files with 186 additions and 14 deletions

View File

@@ -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();

View File

@@ -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/');
});

View File

@@ -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,
});
});
});
});
});