Some checks failed
Server CI / Postgres (shard 0) (push) Has been skipped
Server CI / Postgres (shard 3) (push) Has been skipped
BuildEnv Docker Image / build-image (push) Failing after 4s
BuildEnv Docker Image / build-image-fips (push) Failing after 4s
Migration Review & Release Notes / Generate migration review & release notes (push) Failing after 3s
Server CI / Build Environment (push) Failing after 3s
Server CI / Postgres (shard 1) (push) Has been skipped
Tools CI / check-style (mattermost-govet) (push) Failing after 4s
Server CI / Postgres (shard 2) (push) Has been skipped
Tools CI / check-style (mmgotool) (push) Failing after 3s
Server CI / Elasticsearch v8 Compatibility (push) Has been skipped
Server CI / OpenSearch v2 Compatibility (push) Has been skipped
Server CI / Postgres FIPS (shard 0) (push) Has been skipped
Tools CI / Test (mattermost-govet) (push) Failing after 3s
Server CI / Postgres FIPS (shard 1) (push) Has been skipped
Server CI / Postgres FIPS (shard 2) (push) Has been skipped
Tools CI / Test (mmgotool) (push) Failing after 3s
Server CI / Postgres FIPS (shard 3) (push) Has been skipped
Server CI / Run mmctl tests (push) Has been skipped
Server CI / Run mmctl tests (FIPS) (push) Has been skipped
Server CI / Merge Postgres Test Results (push) Has been skipped
Server CI / Merge Postgres FIPS Test Results (push) Has been skipped
Server CI / Check backport migrations (push) Has been skipped
Server CI / Check generated files (push) Has been skipped
Server CI / check-style (push) Has been skipped
Server CI / Vet API (push) Has been skipped
Server CI / Build mattermost server app (push) Has been skipped
Server CI / Server CI Complete (push) Failing after 2s
Server CI / Server CI Artifacts (push) Has been skipped
Server CI / Sentry Upload (push) Has been skipped
Server CI / Server CI Report (push) Failing after 5m1s
Server CI Nightly Race / Race Detector (push) Has been skipped
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Webapp CI Cache Warm / Warm Webapp node_modules Cache (push) Has been cancelled
E2E CI Cache Warm / Warm E2E npm Registry Cache (push) Has been cancelled
API / build (push) Has been cancelled
Web App CI / check-types (push) Has been cancelled
Web App CI / check-lint (push) Has been cancelled
Web App CI / check-i18n (push) Has been cancelled
Web App CI / check-external-links (push) Has been cancelled
Web App CI / test (platform) (push) Has been cancelled
Web App CI / test (mattermost-redux) (push) Has been cancelled
Web App CI / test (channels shard 1/4) (push) Has been cancelled
Web App CI / test (channels shard 2/4) (push) Has been cancelled
Web App CI / test (channels shard 3/4) (push) Has been cancelled
Web App CI / test (channels shard 4/4) (push) Has been cancelled
Web App CI / upload-coverage (push) Has been cancelled
Web App CI / build (push) Has been cancelled
YAML Lint / yamllint (push) Has been cancelled
Push mirrored docker images / cd/Push mirrored docker images (push) Has been cancelled
docs-cd / Build and deploy docs (push) Has been cancelled
Docs CI / build (push) Has been cancelled
E2E Cache Warm: Cypress deps / Warm Cypress deps cache (push) Has been cancelled
Scorecards supply-chain security / Scorecard analysis (push) Has been cancelled
Server CI Weekly / Postgres FIPS (push) Has been skipped
Server CI Weekly / Run mmctl tests (FIPS) (push) Has been skipped
Server CI Weekly / Postgres with binary parameters (push) Has been skipped
Server CI Weekly / Build Environment (push) Failing after 1s
Server CI Nightly Race / Build Environment (push) Failing after 1s
Server CI Cache Warm / Warm Go Module and Build Cache (push) Failing after 2s
116 lines
3.8 KiB
JavaScript
116 lines
3.8 KiB
JavaScript
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
/* eslint-disable no-console */
|
|
|
|
// A tiny file server that serves the contents of the `asset` directory for use by tests for things like link previews
|
|
// and Markdown images that need an external server which the MM server can contact.
|
|
//
|
|
// Run standalone with `npm run start:file-server-mock`, or fork it from a spec. When forked with an IPC channel,
|
|
// it posts a {type: 'listening', port} message once it is ready so the parent can learn the port (use PORT=0 to get
|
|
// an ephemeral one).
|
|
|
|
const {createServer} = require('http');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
// PORT=0 must request an ephemeral port — don't treat 0 as falsy and fall back to 3011.
|
|
const PORT = process.env.PORT !== undefined && process.env.PORT !== '' ? Number(process.env.PORT) : 3011;
|
|
const ASSET_DIR = process.env.ASSET_DIR || path.join(__dirname, 'asset');
|
|
|
|
if (process.argv[2]) {
|
|
process.title = process.argv[2];
|
|
}
|
|
|
|
const CONTENT_TYPES = {
|
|
'.png': 'image/png',
|
|
'.jpg': 'image/jpeg',
|
|
'.jpeg': 'image/jpeg',
|
|
'.gif': 'image/gif',
|
|
'.svg': 'image/svg+xml',
|
|
'.txt': 'text/plain; charset=utf-8',
|
|
'.html': 'text/html; charset=utf-8',
|
|
'.json': 'application/json',
|
|
'.zip': 'application/zip',
|
|
};
|
|
|
|
function setCorsHeaders(res) {
|
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
res.setHeader('Access-Control-Allow-Methods', 'GET, HEAD, OPTIONS');
|
|
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Range');
|
|
}
|
|
|
|
const server = createServer((req, res) => {
|
|
const method = req.method;
|
|
let requestPath;
|
|
try {
|
|
requestPath = decodeURIComponent(req.url.split('?')[0]);
|
|
} catch (err) {
|
|
console.log(`[mock-file-server] Invalid request URL ${req.url.split('?')[0]}:`, err);
|
|
res.writeHead(400);
|
|
res.end();
|
|
return;
|
|
}
|
|
|
|
// Handle CORS preflight
|
|
if (method === 'OPTIONS') {
|
|
setCorsHeaders(res);
|
|
res.writeHead(204);
|
|
res.end();
|
|
return;
|
|
}
|
|
|
|
console.log(`[mock-file-server] ${method} ${requestPath}`);
|
|
|
|
if (method !== 'GET' && method !== 'HEAD') {
|
|
res.writeHead(405);
|
|
res.end('Method not allowed');
|
|
return;
|
|
}
|
|
|
|
// Resolve the requested file within ASSET_DIR, rejecting anything that escapes it (path traversal).
|
|
const relativePath = requestPath.replace(/^\/+/, '');
|
|
const filePath = path.join(ASSET_DIR, relativePath);
|
|
if (filePath !== ASSET_DIR && !filePath.startsWith(ASSET_DIR + path.sep)) {
|
|
res.writeHead(403);
|
|
res.end('Forbidden');
|
|
return;
|
|
}
|
|
|
|
fs.stat(filePath, (err, stats) => {
|
|
if (err || !stats.isFile()) {
|
|
console.log(`[mock-file-server] 404: ${requestPath}`);
|
|
res.writeHead(404);
|
|
res.end('Not found');
|
|
return;
|
|
}
|
|
|
|
setCorsHeaders(res);
|
|
const ext = path.extname(filePath).toLowerCase();
|
|
res.setHeader('Content-Type', CONTENT_TYPES[ext] || 'application/octet-stream');
|
|
res.setHeader('Content-Length', stats.size);
|
|
|
|
if (method === 'HEAD') {
|
|
res.writeHead(200);
|
|
res.end();
|
|
return;
|
|
}
|
|
|
|
res.writeHead(200);
|
|
fs.createReadStream(filePath).pipe(res);
|
|
});
|
|
});
|
|
|
|
// Bind to all interfaces, not just loopback, so the Mattermost server container can reach this
|
|
// over the Docker network in `testcontainers` mode.
|
|
server.listen(PORT, () => {
|
|
const address = server.address();
|
|
const actualPort = typeof address === 'object' && address ? address.port : PORT;
|
|
console.log(`File server serving ${ASSET_DIR} on port ${actualPort}!`);
|
|
|
|
// Let the parent process know the server is ready and which port it's on
|
|
if (process.send) {
|
|
process.send({type: 'listening', port: actualPort});
|
|
}
|
|
});
|