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

Access-Control-Allow-Credentials and Access-Control-Allow-Origin #282

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
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
58 changes: 50 additions & 8 deletions lib/httpServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,62 @@ 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
92 changes: 90 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,92 @@ 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