From 25401b68eb02bbbd9eaf0a10b8f01bb5e74ab9ab Mon Sep 17 00:00:00 2001 From: e3 Date: Wed, 14 Oct 2015 14:16:39 -0700 Subject: [PATCH 01/11] Test URI requested to respond with index.html if pushstate enabled. --- test/http-server-test.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/http-server-test.js b/test/http-server-test.js index a9240b28..5474278b 100644 --- a/test/http-server-test.js +++ b/test/http-server-test.js @@ -150,5 +150,23 @@ vows.describe('http-server').addBatch({ assert.equal(res.statusCode, 204); } } + }, + 'When push-state is enabled': { + topic: function () { + var server = httpServer.createServer({ + root: root, + pushstate: true + }); + server.listen(8081); + this.callback(null, server); + }, + 'and a non-index file is requested': { + topic: function () { + request('http://127.0.0.1:8081/404', this.callback); + }, + 'status code should be the enpoint code 200': function (res) { + assert.equal(res.statusCode, 200); + } + } } }).export(module); From 5c0c5a7263eee2ccc27cb99730bf48679ba4f052 Mon Sep 17 00:00:00 2001 From: e3 Date: Wed, 14 Oct 2015 14:30:08 -0700 Subject: [PATCH 02/11] Option to enable HTML5 Push State mode, by default it is false --- bin/http-server | 6 ++++-- lib/http-server.js | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/bin/http-server b/bin/http-server index a238603b..0b8eb542 100755 --- a/bin/http-server +++ b/bin/http-server @@ -31,7 +31,7 @@ if (argv.h || argv.help) { ' -U --utc Use UTC time format in log messages.', '', ' -P --proxy Fallback proxy if the request cannot be resolved. e.g.: http://someurl.com', - '', + ' --push-state Enable HTML5 push state mode where all URIs respond with index.html. [false]', ' -S --ssl Enable https.', ' -C --cert Path to ssl cert file (default: cert.pem).', ' -K --key Path to ssl key file (default: key.pem).', @@ -47,6 +47,7 @@ var port = argv.p || parseInt(process.env.PORT, 10), ssl = !!argv.S || !!argv.ssl, proxy = argv.P || argv.proxy, utc = argv.U || argv.utc, + pushState = argv["push-state"] || false, logger; if (!argv.s && !argv.silent) { @@ -98,7 +99,8 @@ function listen(port) { robots: argv.r || argv.robots, ext: argv.e || argv.ext, logFn: logger.request, - proxy: proxy + proxy: proxy, + pushState: pushState }; if (argv.cors) { diff --git a/lib/http-server.js b/lib/http-server.js index daddcaae..2ae0f95d 100644 --- a/lib/http-server.js +++ b/lib/http-server.js @@ -47,6 +47,7 @@ function HttpServer(options) { this.showDir = options.showDir !== 'false'; this.autoIndex = options.autoIndex !== 'false'; this.contentType = options.contentType || 'application/octet-stream'; + this.pushState = options.pushState || false; if (options.ext) { this.ext = options.ext === true From b5fa8ccac213590e2a6ec1c9670ba815aa93ad32 Mon Sep 17 00:00:00 2001 From: e3 Date: Wed, 14 Oct 2015 14:39:11 -0700 Subject: [PATCH 03/11] Fixing broken tests, using a new port for testing. --- bin/http-server | 2 +- test/http-server-test.js | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/bin/http-server b/bin/http-server index 0b8eb542..a34a5065 100755 --- a/bin/http-server +++ b/bin/http-server @@ -47,7 +47,7 @@ var port = argv.p || parseInt(process.env.PORT, 10), ssl = !!argv.S || !!argv.ssl, proxy = argv.P || argv.proxy, utc = argv.U || argv.utc, - pushState = argv["push-state"] || false, + pushState = argv['push-state'] || false, logger; if (!argv.s && !argv.silent) { diff --git a/test/http-server-test.js b/test/http-server-test.js index 5474278b..6785469a 100644 --- a/test/http-server-test.js +++ b/test/http-server-test.js @@ -154,18 +154,19 @@ vows.describe('http-server').addBatch({ 'When push-state is enabled': { topic: function () { var server = httpServer.createServer({ - root: root, - pushstate: true + root: root }); - server.listen(8081); + // NOTE: using 8083 because the 808[1-2] are both active and not yet shutdown. + server.listen(8083); + this.callback(null, server); }, 'and a non-index file is requested': { topic: function () { - request('http://127.0.0.1:8081/404', this.callback); + request('http://127.0.0.1:8083/404', this.callback); }, - 'status code should be the enpoint code 200': function (res) { - assert.equal(res.statusCode, 200); + 'status code should be 200': function (res) { + assert.equal(res.statusCode, 404); } } } From 0a8adb7d928a9933c4b6e1106d4cb3ff06dd324a Mon Sep 17 00:00:00 2001 From: e3 Date: Wed, 14 Oct 2015 14:46:25 -0700 Subject: [PATCH 04/11] Initial implementation which sends all push-state traffic to index.html. --- lib/http-server.js | 8 ++++++++ test/fixtures/pushStateRoot/index.html | 1 + test/http-server-test.js | 7 +++++-- 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 test/fixtures/pushStateRoot/index.html diff --git a/lib/http-server.js b/lib/http-server.js index 2ae0f95d..2f3fdca6 100644 --- a/lib/http-server.js +++ b/lib/http-server.js @@ -87,6 +87,14 @@ function HttpServer(options) { }); } + if (options.pushState) { + before.push(function (req, res) { + req.url = '/index.html'; + + res.emit('next'); + }); + } + before.push(ecstatic({ root: this.root, cache: this.cache, diff --git a/test/fixtures/pushStateRoot/index.html b/test/fixtures/pushStateRoot/index.html new file mode 100644 index 00000000..9f51cbe7 --- /dev/null +++ b/test/fixtures/pushStateRoot/index.html @@ -0,0 +1 @@ +pushState Enabled. diff --git a/test/http-server-test.js b/test/http-server-test.js index 6785469a..3ae4102e 100644 --- a/test/http-server-test.js +++ b/test/http-server-test.js @@ -153,8 +153,11 @@ vows.describe('http-server').addBatch({ }, 'When push-state is enabled': { topic: function () { + var pushStateRoot = path.join(__dirname, 'fixtures', 'pushStateRoot'); + var server = httpServer.createServer({ - root: root + root: pushStateRoot, + pushState: true }); // NOTE: using 8083 because the 808[1-2] are both active and not yet shutdown. server.listen(8083); @@ -166,7 +169,7 @@ vows.describe('http-server').addBatch({ request('http://127.0.0.1:8083/404', this.callback); }, 'status code should be 200': function (res) { - assert.equal(res.statusCode, 404); + assert.equal(res.statusCode, 200); } } } From b65e86de211b638737c2bd1d5c0d833d214af2e5 Mon Sep 17 00:00:00 2001 From: e3 Date: Wed, 14 Oct 2015 15:09:54 -0700 Subject: [PATCH 05/11] Check the body of responses to validate they are the index.html. --- test/http-server-test.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/http-server-test.js b/test/http-server-test.js index 3ae4102e..59334654 100644 --- a/test/http-server-test.js +++ b/test/http-server-test.js @@ -170,6 +170,19 @@ vows.describe('http-server').addBatch({ }, 'status code should be 200': function (res) { assert.equal(res.statusCode, 200); + }, + 'and file content': { + topic: function (res, body) { + var self = this; + var pushStateRoot = path.join(__dirname, 'fixtures', 'pushStateRoot'); + + fs.readFile(path.join(pushStateRoot, 'index.html'), 'utf8', function (err, data) { + self.callback(err, data, body); + }); + }, + 'should match content of served file': function (err, file, body) { + assert.equal(body.trim(), file.trim()); + } } } } From d8d4bde2e4c0236e366ea7d74baf91a642818bb9 Mon Sep 17 00:00:00 2001 From: e3 Date: Wed, 14 Oct 2015 15:10:23 -0700 Subject: [PATCH 06/11] Don't square URL parameters while reseting the index page. --- lib/http-server.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/http-server.js b/lib/http-server.js index 2f3fdca6..8bc09307 100644 --- a/lib/http-server.js +++ b/lib/http-server.js @@ -88,8 +88,12 @@ function HttpServer(options) { } if (options.pushState) { + // When push state is enabled, first rewrite all the URLs to be the index page. before.push(function (req, res) { - req.url = '/index.html'; + var currentURL = req.url; + var currentParameters = currentURL.slice(currentURL.indexOf("?")); + + req.url = '/index.html' + currentParameters; res.emit('next'); }); From a9c63b18155b394516a1eee78068102935464df3 Mon Sep 17 00:00:00 2001 From: e3 Date: Wed, 14 Oct 2015 15:15:02 -0700 Subject: [PATCH 07/11] Options log information when push-state is enabled. --- bin/http-server | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/bin/http-server b/bin/http-server index a34a5065..df2ff5ec 100755 --- a/bin/http-server +++ b/bin/http-server @@ -47,7 +47,6 @@ var port = argv.p || parseInt(process.env.PORT, 10), ssl = !!argv.S || !!argv.ssl, proxy = argv.P || argv.proxy, utc = argv.U || argv.utc, - pushState = argv['push-state'] || false, logger; if (!argv.s && !argv.silent) { @@ -99,10 +98,17 @@ function listen(port) { robots: argv.r || argv.robots, ext: argv.e || argv.ext, logFn: logger.request, - proxy: proxy, - pushState: pushState + proxy: proxy }; + if (argv['push-state']) { + options.pushState = true; + + if (options.proxy || options.autoIndex) { + logger.info('Proxy and Auto Indexing are not supported with Push State.'.red); + } + } + if (argv.cors) { options.cors = true; } @@ -137,6 +143,10 @@ function listen(port) { logger.info('Unhandled requests will be served from: ' + proxy); } + if (options.pushState) { + logger.info('HTML5 Push State is enabled, all URLs will be changed to the index page.'); + } + logger.info('Hit CTRL-C to stop the server'); if (argv.o) { opener( From b4be467214b9eca74097659f2b89e0f1d00ab3c3 Mon Sep 17 00:00:00 2001 From: e3 Date: Wed, 14 Oct 2015 15:32:58 -0700 Subject: [PATCH 08/11] Fixing bug when no parameters causing problems for routing. --- lib/http-server.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/http-server.js b/lib/http-server.js index 8bc09307..02eed553 100644 --- a/lib/http-server.js +++ b/lib/http-server.js @@ -91,9 +91,18 @@ function HttpServer(options) { // When push state is enabled, first rewrite all the URLs to be the index page. before.push(function (req, res) { var currentURL = req.url; - var currentParameters = currentURL.slice(currentURL.indexOf("?")); + var indexPage = '/index.html'; - req.url = '/index.html' + currentParameters; + // Only add paramters when they exist. + var parameterStartIndex = currentURL.indexOf('?'); + if (parameterStartIndex >= 0) { + var currentParameters = currentURL.slice(parameterStartIndex); + + req.url = indexPage + currentParameters; + } + else { + req.url = indexPage; + } res.emit('next'); }); From 0bda9799aaa22be54557590f73716019a7f95983 Mon Sep 17 00:00:00 2001 From: e3 Date: Wed, 14 Oct 2015 15:51:43 -0700 Subject: [PATCH 09/11] Including option in README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 0b699e50..7fab36c6 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,8 @@ This will install `http-server` globally so that it may be run from the command `-P` or `--proxy` Proxies all requests which can't be resolved locally to the given url. e.g.: -P http://someurl.com +`--push-state` Enable HTML5 push state mode where all URIs respond with index.html. (defaults to 'False') + `-S` or `--ssl` Enable https. `-C` or `--cert` Path to ssl cert file (default: cert.pem). From 750848fe6541258d0b92e45ffb632e16264a6b1e Mon Sep 17 00:00:00 2001 From: e3 Date: Thu, 15 Oct 2015 09:31:43 -0700 Subject: [PATCH 10/11] Broken test for existing files. --- test/fixtures/pushStateRoot/app.js | 1 + test/http-server-test.js | 20 +++++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 test/fixtures/pushStateRoot/app.js diff --git a/test/fixtures/pushStateRoot/app.js b/test/fixtures/pushStateRoot/app.js new file mode 100644 index 00000000..051f441e --- /dev/null +++ b/test/fixtures/pushStateRoot/app.js @@ -0,0 +1 @@ +// JavaScript File Exists diff --git a/test/http-server-test.js b/test/http-server-test.js index 59334654..5e5593ca 100644 --- a/test/http-server-test.js +++ b/test/http-server-test.js @@ -164,7 +164,7 @@ vows.describe('http-server').addBatch({ this.callback(null, server); }, - 'and a non-index file is requested': { + 'and a non-existant file is requested': { topic: function () { request('http://127.0.0.1:8083/404', this.callback); }, @@ -184,6 +184,24 @@ vows.describe('http-server').addBatch({ assert.equal(body.trim(), file.trim()); } } + }, + 'and a file exists': { + topic: function () { + request('http://127.0.0.1:8083/app.js', this.callback); + }, + 'and file content': { + topic: function (res, body) { + var self = this; + var pushStateRoot = path.join(__dirname, 'fixtures', 'pushStateRoot'); + + fs.readFile(path.join(pushStateRoot, 'app.js'), 'utf8', function (err, data) { + self.callback(err, data, body); + }); + }, + 'should match content of served file': function (err, file, body) { + assert.equal(body.trim(), file.trim()); + } + } } } }).export(module); From 5dd25b5677f79b42567eea2ed9098dde3999c108 Mon Sep 17 00:00:00 2001 From: e3 Date: Thu, 15 Oct 2015 10:21:25 -0700 Subject: [PATCH 11/11] Moving logic to be last in the request chain, calling the ecstatic --- lib/http-server.js | 48 ++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/lib/http-server.js b/lib/http-server.js index 02eed553..2e8963ef 100644 --- a/lib/http-server.js +++ b/lib/http-server.js @@ -87,28 +87,7 @@ function HttpServer(options) { }); } - if (options.pushState) { - // When push state is enabled, first rewrite all the URLs to be the index page. - before.push(function (req, res) { - var currentURL = req.url; - var indexPage = '/index.html'; - - // Only add paramters when they exist. - var parameterStartIndex = currentURL.indexOf('?'); - if (parameterStartIndex >= 0) { - var currentParameters = currentURL.slice(parameterStartIndex); - - req.url = indexPage + currentParameters; - } - else { - req.url = indexPage; - } - - res.emit('next'); - }); - } - - before.push(ecstatic({ + var ecstaticMiddleware = ecstatic({ root: this.root, cache: this.cache, showDir: this.showDir, @@ -116,7 +95,9 @@ function HttpServer(options) { defaultExt: this.ext, contentType: this.contentType, handleError: typeof options.proxy !== 'string' - })); + }); + + before.push(ecstaticMiddleware); if (typeof options.proxy === 'string') { var proxy = httpProxy.createProxyServer({}); @@ -128,6 +109,27 @@ function HttpServer(options) { }); } + if (options.pushState) { + // When push state is enabled, rewrite all the URLs to the index page if the status code is a 404. + before.push(function (req, res, next) { + var currentURL = req.url; + var indexPage = '/index.html'; + + // Only add paramters when they exist. + var parameterStartIndex = currentURL.indexOf('?'); + if (parameterStartIndex >= 0) { + var currentParameters = currentURL.slice(parameterStartIndex); + + req.url = indexPage + currentParameters; + } + else { + req.url = indexPage; + } + + ecstaticMiddleware(req, res, next); + }); + } + var serverOptions = { before: before, headers: this.headers,