Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ logs/
.nyc_output
yarn.lock
package-lock.json
.DS_Store
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#nit: Ditto to what I said on the other PR - global .gitignore. :)

27 changes: 27 additions & 0 deletions functions/cors/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<img src="https://avatars2.githubusercontent.com/u/2810941?v=3&s=96" alt="Google Cloud Platform logo" title="Google Cloud Platform" align="right" height="96" width="96"/>

# Google Cloud Functions - CORS (Cross-Origin Resource Sharing) sample

See:

* [Cloud Functions CORS tutorial][tutorial]
* [Cloud Functions CORS sample source code][code]

[tutorial]: https://cloud.google.com/functions/docs/writing/http#handling_cors_requests
[code]: index.js

## Deploy and run the sample

See the [Cloud Functions CORS tutorial][tutorial].

## Run the tests

1. Read and follow the [prerequisites](../../#how-to-run-the-tests).

2. Install dependencies:

npm install

3. Run the tests:

npm test
63 changes: 63 additions & 0 deletions functions/cors/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* Copyright 2018, Google, LLC.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

// [START functions_cors]
exports.corsEnabledFunction = (req, res) => {
// Set CORS headers for preflight requests
// e.g. allow GETs from any origin with the Content-Type header
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can/should we put these headers in one big if block, instead of removing them when they don't apply?

cc @stew-r

// and cache preflight response for an 3600s
res.set('Access-Control-Allow-Origin', '*');
res.set('Access-Control-Allow-Methods', 'GET');
res.set('Access-Control-Allow-Headers', 'Content-Type');
res.set('Access-Control-Max-Age', '3600');

// Send response to OPTIONS requests and terminate the function execution
if (req.method === 'OPTIONS') {
res.status(204).send('');
}

// Set CORS headers for the main request
res.removeHeader('Access-Control-Allow-Methods');
res.removeHeader('Access-Control-Allow-Headers');
res.removeHeader('Access-Control-Max-Age');

res.send('Hello World!');
};
// [END functions_cors]

// [START functions_cors_auth]
exports.corsEnabledFunctionAuth = (req, res) => {
// Set CORS headers for preflight requests
// allows GETS from origin https://mydomain.com with Authorization header
res.set('Access-Control-Allow-Origin', 'https://mydomain.com');
res.set('Access-Control-Allow-Methods', 'GET');
res.set('Access-Control-Allow-Headers', 'Authorization');
res.set('Access-Control-Allow-Credentials', 'true');
res.set('Access-Control-Max-Age', '3600');

// Send response to OPTIONS requests and terminate the function execution
if (req.method === 'OPTIONS') {
res.status(204).send('');
}

res.removeHeader('Access-Control-Allow-Methods');
res.removeHeader('Access-Control-Allow-Headers');
res.removeHeader('Access-Control-Max-Age');

res.send('Hello World!');
};
// [END functions_cors_auth]
30 changes: 30 additions & 0 deletions functions/cors/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "nodejs-docs-samples-functions-cors",
"version": "0.0.1",
"private": true,
"license": "Apache-2.0",
"author": "Google Inc.",
"repository": {
"type": "git",
"url": "https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git"
},
"engines": {
"node": ">=4.3.2"
},
"scripts": {
"lint": "repo-tools lint",
"pretest": "npm run lint",
"test": "ava -T 20s --verbose test/*.test.js"
},
"dependencies": {},
"devDependencies": {
"@google-cloud/nodejs-repo-tools": "2.2.1",
"ava": "0.25.0",
"semistandard": "^12.0.1",
"sinon": "4.4.2"
},
"cloud-repo-tools": {
"requiresKeyFile": true,
"requiresProjectId": true
}
}
77 changes: 77 additions & 0 deletions functions/cors/test/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/**
* Copyright 2018, Google, LLC.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

const sinon = require(`sinon`);
const test = require(`ava`);
const functions = require(`../`);

function getMocks () {
const mainReq = {
method: 'GET'
};

const preflightReq = {
method: 'OPTIONS'
};

const res = {
set: sinon.stub(),
removeHeader: sinon.stub(),
send: sinon.stub().returnsThis(),
status: sinon.stub().returnsThis()
};

return {
mainReq: mainReq,
preflightReq: preflightReq,
res: res
};
}

test.serial(`should respond to preflight request (no auth)`, (t) => {
const mocks = getMocks();

functions.corsEnabledFunction(mocks.preflightReq, mocks.res);

t.true(mocks.res.status.calledOnceWith(204));
t.true(mocks.res.send.called);
});

test.serial(`should respond to main request (no auth)`, (t) => {
const mocks = getMocks();

functions.corsEnabledFunction(mocks.mainReq, mocks.res);

t.true(mocks.res.send.calledOnceWith(`Hello World!`));
});

test.serial(`should respond to preflight request (auth)`, (t) => {
const mocks = getMocks();

functions.corsEnabledFunctionAuth(mocks.preflightReq, mocks.res);

t.true(mocks.res.status.calledOnceWith(204));
t.true(mocks.res.send.called);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: check that it was called a certain number of times?

});

test.serial(`should respond to main request (auth)`, (t) => {
const mocks = getMocks();

functions.corsEnabledFunctionAuth(mocks.mainReq, mocks.res);

t.true(mocks.res.send.calledOnceWith(`Hello World!`));
});