Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ with the provided Dockerfile.
|`-b` or `--brotli`|When enabled it will serve `./public/some-file.js.br` in place of `./public/some-file.js` when a brotli compressed version of the file exists and the request accepts `br` encoding. If gzip is also enabled, it will try to serve brotli first. |`false`|
|`-e` or `--ext` |Default file extension if none supplied |`html` |
|`-s` or `--silent` |Suppress log messages from output | |
|`--coop` |Enable COOP via the `Cross-Origin-Opener-Policy` header | |
|`--cors` |Enable CORS via the `Access-Control-Allow-Origin` header | |
|`-H` or `--header` |Add an extra response header (can be used several times) | |
|`-o [path]` |Open browser window after starting the server. Optionally provide a URL path to open. e.g.: -o /other/dir/ | |
Expand Down Expand Up @@ -136,6 +137,7 @@ This is what should be output if successful:
Starting up http-server, serving ./ through https

http-server settings:
COOP: disabled
CORS: disabled
Cache: 3600 seconds
Connection Timeout: 120 seconds
Expand Down
10 changes: 10 additions & 0 deletions bin/http-server
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ if (argv.h || argv.help) {
' If both brotli and gzip are enabled, brotli takes precedence',
' -e --ext Default file extension if none supplied [none]',
' -s --silent Suppress log messages from output',
' --coop[=mode] Enable COOP via the "Cross-Origin-Opener-Policy" header',
' Optionally provide COOP mode.',
' --cors[=headers] Enable CORS via the "Access-Control-Allow-Origin" header',
' Optionally provide CORS headers list separated by commas',
' -H',
Expand Down Expand Up @@ -173,6 +175,13 @@ function listen(port) {
}
}

if (argv.coop) {
options.coop = true;
if (typeof argv.coop === 'string') {
options.coopHeader = argv.coop;
}
}

if (argv.cors) {
options.cors = true;
if (typeof argv.cors === 'string') {
Expand Down Expand Up @@ -236,6 +245,7 @@ function listen(port) {

logger.info([
chalk.yellow('\nhttp-server settings: '),
([chalk.yellow('COOP: '), argv.coop ? chalk.cyan(argv.coop) : chalk.red('disabled')].join('')),
([chalk.yellow('CORS: '), argv.cors ? chalk.cyan(argv.cors) : chalk.red('disabled')].join('')),
([chalk.yellow('Cache: '), argv.c ? (argv.c === '-1' ? chalk.red('disabled') : chalk.cyan(argv.c + ' seconds')) : chalk.cyan('3600 seconds')].join('')),
([chalk.yellow('Connection Timeout: '), argv.t === '0' ? chalk.red('disabled') : (argv.t ? chalk.cyan(argv.t + ' seconds') : chalk.cyan('120 seconds'))].join('')),
Expand Down
6 changes: 6 additions & 0 deletions doc/http-server.1
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ Default file extension is none is provided.
.BI \-s ", " \-\-silent
Suppress log messages from output.

.TP
.BI \-\-coop " " [\fIMODE\fR]
Enable COOP via the "Cross-Origin-Opener-Policy" header and sets
the "Cross-Origin-Embedder-Policy" header to "require-corp".
Optionally provide COOP mode which defaults to "same-origin".

.TP
.BI \-\-cors " " [\fIHEADERS\fR]
Enable CORS via the "Access-Control-Allow-Origin" header.
Expand Down
1 change: 1 addition & 0 deletions lib/core/aliases.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"hidePermissions": ["hidePermissions", "hidepermissions", "hide-permissions"],
"si": [ "si", "index" ],
"handleError": [ "handleError", "handleerror" ],
"coop": [ "coop", "COOP" ],
"cors": [ "cors", "CORS" ],
"headers": [ "H", "header", "headers" ],
"contentType": [ "contentType", "contenttype", "content-type" ],
Expand Down
1 change: 1 addition & 0 deletions lib/core/defaults.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"hidePermissions": false,
"si": false,
"cache": "max-age=3600",
"coop": false,
"cors": false,
"gzip": true,
"brotli": false,
Expand Down
8 changes: 8 additions & 0 deletions lib/core/opts.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,14 @@ module.exports = (opts) => {
return false;
});

aliases.coop.forEach((k) => {
if (isDeclared(k) && opts[k]) {
handleOptionsMethod = true;
headers['Cross-Origin-Opener-Policy'] = 'same-origin';
headers['Cross-Origin-Embedder-Policy'] = 'require-corp';
}
});

aliases.cors.forEach((k) => {
if (isDeclared(k) && opts[k]) {
handleOptionsMethod = true;
Expand Down
5 changes: 5 additions & 0 deletions lib/http-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ function HttpServer(options) {
});
}

if (options.coop) {
this.headers['Cross-Origin-Opener-Policy'] = options.coopHeader || 'same-origin';
this.headers['Cross-Origin-Embedder-Policy'] = 'require-corp';
}

if (options.cors) {
this.headers['Access-Control-Allow-Origin'] = '*';
this.headers['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept, Range';
Expand Down
118 changes: 118 additions & 0 deletions test/coop.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
'use strict';

const test = require('tap').test;
const server = require('../lib/core');
const http = require('http');
const path = require('path');
const request = require('request');

const root = path.join(__dirname, 'public');

test('coop defaults to false', (t) => {
t.plan(4);

const httpServer = http.createServer(
server({
root,
autoIndex: true,
defaultExt: 'html',
})
);

httpServer.listen(() => {
const port = httpServer.address().port;
const uri = `http://localhost:${port}/subdir/index.html`;

request.get({ uri }, (err, res) => {
t.error(err);
t.equal(res.statusCode, 200);
t.type(res.headers['cross-origin-opener-policy'], 'undefined');
t.type(res.headers['cross-origin-embedder-policy'], 'undefined');
});
});
t.once('end', () => {
httpServer.close();
});
});

test('coop set to false', (t) => {
t.plan(4);

const httpServer = http.createServer(
server({
root,
coop: false,
autoIndex: true,
defaultExt: 'html',
})
);

httpServer.listen(() => {
const port = httpServer.address().port;
const uri = `http://localhost:${port}/subdir/index.html`;

request.get({ uri }, (err, res) => {
t.error(err);
t.equal(res.statusCode, 200);
t.type(res.headers['cross-origin-opener-policy'], 'undefined');
t.type(res.headers['cross-origin-embedder-policy'], 'undefined');
});
});
t.once('end', () => {
httpServer.close();
});
});

test('coop set to true', (t) => {
t.plan(4);

const httpServer = http.createServer(
server({
root,
coop: true,
autoIndex: true,
defaultExt: 'html',
})
);

httpServer.listen(() => {
const port = httpServer.address().port;
const uri = `http://localhost:${port}/subdir/index.html`;
request.get({ uri }, (err, res) => {
t.error(err);
t.equal(res.statusCode, 200);
t.equal(res.headers['cross-origin-opener-policy'], 'same-origin');
t.equal(res.headers['cross-origin-embedder-policy'], 'require-corp');
});
});
t.once('end', () => {
httpServer.close();
});
});

test('COOP set to true', (t) => {
t.plan(4);

const httpServer = http.createServer(
server({
root,
COOP: true,
autoIndex: true,
defaultExt: 'html',
})
);

httpServer.listen(() => {
const port = httpServer.address().port;
const uri = `http://localhost:${port}/subdir/index.html`;
request.get({ uri }, (err, res) => {
t.error(err);
t.equal(res.statusCode, 200);
t.equal(res.headers['cross-origin-opener-policy'], 'same-origin');
t.equal(res.headers['cross-origin-embedder-policy'], 'require-corp');
});
});
t.once('end', () => {
httpServer.close();
});
});
3 changes: 3 additions & 0 deletions test/main.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ test('http-server main', (t) => {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': 'true'
},
coop: true,
cors: true,
corsHeaders: 'X-Test',
ext: true,
Expand Down Expand Up @@ -63,6 +64,8 @@ test('http-server main', (t) => {
// Custom headers
t.equal(res.headers['access-control-allow-origin'], '*');
t.equal(res.headers['access-control-allow-credentials'], 'true');
t.equal(res.headers['cross-origin-opener-policy'], 'same-origin');
t.equal(res.headers['cross-origin-embedder-policy'], 'require-corp');
}).catch(err => t.fail(err.toString())),

// Get robots
Expand Down