Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

Commit

Permalink
Ensure requests.headers.origin is returned instead of "*" for COR…
Browse files Browse the repository at this point in the history
…S requests and that we set the `access-control-allow-credentials` to `"true"`
  • Loading branch information
dgendill authored and davidmurdoch committed Jan 26, 2019
1 parent e13effd commit 9633943
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 10 deletions.
59 changes: 51 additions & 8 deletions lib/httpServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,63 @@ module.exports = function(provider, logger) {
// At this point, we have the headers, method, url and body, and can now
// do whatever we need to in order to respond to this request.

var headers = {
"Access-Control-Allow-Origin": "*"
};
var headers = {};

// https://fetch.spec.whatwg.org/#http-requests
let isCORSRequest = request.headers.hasOwnProperty("origin");
let isCORSPreflight =
isCORSRequest &&
method === "OPTIONS" &&
request.headers.hasOwnProperty("access-control-request-headers") &&
request.headers.hasOwnProperty("access-control-request-method");

if (isCORSRequest) {
// From the spec: "It cannot be reliably identified as participating in the CORS protocol
// as the `Origin` header is also included for all requests whose method is neither
// `GET` nor `HEAD`."
headers["Access-Control-Allow-Origin"] = request.headers.origin;

// Based on https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials,
// it doesn't look like there will be an HTTP Request header that tells you whether or not to
// include this. Since web3 now sets Request.withCredentials this header needs to be set.
// https://github.com/ethereum/web3.js/pull/1722
headers["Access-Control-Allow-Credentials"] = "true";
} else {
// There is no origin so we'll default to wildcard.
headers["Access-Control-Allow-Origin"] = "*";
}

switch (method) {
// The options request will always be used to handle the preflight request.
case "OPTIONS":
if (request.headers.hasOwnProperty("access-control-request-headers")) {
if (isCORSPreflight) {
// Explicitly set the origin instead of using *, since credentials
// can't be used in conjunction with *. This will always be set
// for valid preflight requests.
headers["Access-Control-Allow-Origin"] = request.headers.origin;

// From the spec: https://fetch.spec.whatwg.org/#http-responses
// "For a CORS-preflight request, request’s credentials mode is always "omit",
// but for any subsequent CORS requests it might not be. Support therefore
// needs to be indicated as part of the HTTP response to the CORS-preflight request as well."
headers["Access-Control-Allow-Credentials"] = "true";

headers["Access-Control-Allow-Headers"] = request.headers["access-control-request-headers"];
headers["Vary"] = "Access-Control-Request-Headers";

headers["Access-Control-Allow-Methods"] = "POST";

headers["Content-Length"] = 0;
response.writeHead(204, headers);
response.end();
} else {
let errorMessage = "OPTIONS preflight request is missing at least on of the required ";
errorMessage += "fields: Origin, Access-Control-Request-Headers, Access-Control-Request-Method";
headers["Content-Length"] = errorMessage.length;
response.writeHead(400, headers);
response.end(errorMessage);
}
headers["Access-Control-Allow-Methods"] = "POST";
headers["Content-Length"] = 0;
response.writeHead(204, headers);
response.end();

break;
case "POST":
// console.log("Request coming in:", body);
Expand Down
93 changes: 91 additions & 2 deletions test/cors.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ const customRequestHeader = "X-PINGOTHER";

function test(host, port) {
describe("CORS", () => {
it("should request headers equals to response headers in a preflight request", (done) => {
it("should set request headers equals to response headers in a preflight request", (done) => {
let req = request.options(
{
url: "http://" + host + ":" + port,
headers: {
"Access-Control-Request-Headers": customRequestHeader
"Access-Control-Request-Headers": customRequestHeader,
"Access-Control-Request-Method": "POST",
Origin: "https://localhost:3000"
}
},
function(error, response) {
Expand All @@ -38,6 +40,93 @@ function test(host, port) {

req.destroy();
});

it("should return an error message if the OPTIONS request is not a valid preflight request.", (done) => {
let origin = "https://localhost:3000";
let req = request.options(
{
url: "http://" + host + ":" + port,
headers: {
Origin: origin
}
},
function(error, response) {
if (error) {
return done(error);
}

assert.strictEqual(
response.statusCode,
400,
"A an OPTIONS request that isn't a preflight request should return an error."
);

done();
}
);

req.destroy();
});

it("should set response.Access-Control-Allow-Origin to equal request.Origin if request.Origin is set", (done) => {
let origin = "https://localhost:3000";
let req = request.options(
{
url: "http://" + host + ":" + port,
headers: {
Origin: origin
}
},
function(error, response) {
if (error) {
return done(error);
}

let accessControlAllowOrigin = "";

if (response.headers.hasOwnProperty("access-control-allow-origin")) {
accessControlAllowOrigin = response.headers["access-control-allow-origin"];
}

assert.strictEqual(
accessControlAllowOrigin,
origin,
"response.Access-Control-Allow-Origin should equal request.Origin if request.Origin is set."
);

done();
}
);

req.destroy();
});

it("should set Access-Control-Allow-Credentials=true if the Origin is set.", (done) => {
let origin = "https://localhost:3000";
let req = request.options(
{
url: "http://" + host + ":" + port,
headers: {
Origin: origin
}
},
function(error, response) {
if (error) {
return done(error);
}

assert.strictEqual(
response.headers["access-control-allow-credentials"],
"true",
"response.Access-Control-Allow-Origin should equal request.Origin if request.Origin is set."
);

done();
}
);

req.destroy();
});
});
}

Expand Down

0 comments on commit 9633943

Please sign in to comment.