From 30f4d1e008b3d707a764eb06ad4c1ac2becd9e96 Mon Sep 17 00:00:00 2001 From: Paul Melnikow Date: Thu, 4 Sep 2014 21:03:02 -0400 Subject: [PATCH] Get CORS support working with XHR preflight Without this patch, http-server returns 404 on the preflight request (method: 'OPTIONS'). You can see the problem by loading an XHR request in Firefox. --- bin/http-server | 5 +--- lib/http-server.js | 59 +++++++++++++++++++++++----------------- package.json | 3 +- test/http-server-test.js | 26 ++++++++++++++++++ 4 files changed, 63 insertions(+), 30 deletions(-) diff --git a/bin/http-server b/bin/http-server index 04b3c7db..3438a2dc 100755 --- a/bin/http-server +++ b/bin/http-server @@ -70,10 +70,7 @@ function listen(port) { }; if (argv.cors) { - options.headers = { - 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept' - }; + options.cors = true; } if (ssl) { diff --git a/lib/http-server.js b/lib/http-server.js index 9ccb023d..fcc0f4f1 100644 --- a/lib/http-server.js +++ b/lib/http-server.js @@ -2,7 +2,8 @@ var fs = require('fs'), util = require('util'), union = require('union'), ecstatic = require('ecstatic'), - httpProxy = require('http-proxy'); + httpProxy = require('http-proxy'), + corser = require('corser'); var HTTPServer = exports.HTTPServer = function (options) { options = options || {}; @@ -20,9 +21,7 @@ var HTTPServer = exports.HTTPServer = function (options) { } } - if (options.headers) { - this.headers = options.headers; - } + this.headers = options.headers || {}; this.cache = options.cache || 3600; // in seconds. this.showDir = options.showDir !== 'false'; @@ -34,30 +33,35 @@ var HTTPServer = exports.HTTPServer = function (options) { : options.ext; } - var serverOptions = { - before: (options.before || []).concat([ - function (req, res) { - if (options.logFn) { - options.logFn(req, res); - } - - res.emit('next'); - }, - ecstatic({ - root: this.root, - cache: this.cache, - showDir: this.showDir, - autoIndex: this.autoIndex, - defaultExt: this.ext, - handleError: typeof options.proxy !== 'string' - }) - ]), - headers: this.headers || {} - }; + var before = options.before ? options.before.slice() : []; + + before.push(function (req, res) { + if (options.logFn) { + options.logFn(req, res); + } + + res.emit('next'); + }); + + if (options.cors) { + this.headers['Access-Control-Allow-Origin'] = '*'; + this.headers['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept'; + + before.push(corser.create()); + } + + before.push(ecstatic({ + root: this.root, + cache: this.cache, + showDir: this.showDir, + autoIndex: this.autoIndex, + defaultExt: this.ext, + handleError: typeof options.proxy !== 'string' + })); if (typeof options.proxy === 'string') { var proxy = httpProxy.createProxyServer({}); - serverOptions.before.push(function (req, res) { + before.push(function (req, res) { proxy.web(req, res, { target: options.proxy, changeOrigin: true @@ -65,6 +69,11 @@ var HTTPServer = exports.HTTPServer = function (options) { }); } + var serverOptions = { + before: before, + headers: this.headers + }; + if (options.https) { serverOptions.https = options.https; } diff --git a/package.json b/package.json index bf8a535d..3f3af75e 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,8 @@ "ecstatic": "~0.6.1", "http-proxy": "^1.8.1", "portfinder": "0.2.x", - "opener": "~1.4.0" + "opener": "~1.4.0", + "corser": "~2.0.0" }, "devDependencies": { "vows": "0.7.x", diff --git a/test/http-server-test.js b/test/http-server-test.js index 6efbfb89..3cdc8a73 100644 --- a/test/http-server-test.js +++ b/test/http-server-test.js @@ -114,5 +114,31 @@ vows.describe('http-server').addBatch({ } } } + }, + 'When cors is enabled': { + topic: function () { + var server = httpServer.createServer({ + root: root, + cors: true + }); + server.listen(8082); + this.callback(null, server); + }, + 'and given OPTIONS request': { + topic: function () { + request({ + method: 'OPTIONS', + uri: 'http://127.0.0.1:8082/', + headers: { + 'Access-Control-Request-Method': 'GET', + Origin: 'http://example.com', + 'Access-Control-Request-Headers': 'Foobar' + } + }, this.callback); + }, + 'status code should be 204': function (err, res, body) { + assert.equal(res.statusCode, 204); + } + } } }).export(module);