Skip to content

Commit

Permalink
Add debug feature to always enable cors for emulated v2 https functio…
Browse files Browse the repository at this point in the history
…ns (#1099)

* Add debug feature to always enable cors.

* Add test cases.

* Fix tests.

* Add changelog.

* Format.

* Fix typo.

Co-authored-by: Thomas Bouldin <inlined@users.noreply.github.com>
  • Loading branch information
taeold and inlined committed May 10, 2022
1 parent e720145 commit 5fda331
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Add debug feature to enable cors option for v2 onRequest and onCall handlers. (#1099)
76 changes: 74 additions & 2 deletions spec/v2/providers/https.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import * as sinon from 'sinon';
import { expect } from 'chai';

import * as debug from '../../../src/common/debug';
import * as options from '../../../src/v2/options';
import * as https from '../../../src/v2/providers/https';
import {
Expand Down Expand Up @@ -166,7 +168,7 @@ describe('onRequest', () => {
{
'Access-Control-Request-Method': 'POST',
'Access-Control-Request-Headers': 'origin',
Origin: 'example.com',
origin: 'example.com',
}
);
req.method = 'OPTIONS';
Expand All @@ -181,6 +183,41 @@ describe('onRequest', () => {
Vary: 'Origin, Access-Control-Request-Headers',
});
});

it('should add CORS headers if debug feature is enabled', async () => {
sinon
.stub(debug, 'isDebugFeatureEnabled')
.withArgs('enableCors')
.returns(true);

const func = https.onRequest((req, res) => {
throw new Error('Should not reach here for OPTIONS preflight');
});

const req = new MockRequest(
{
data: {},
},
{
'Access-Control-Request-Method': 'POST',
'Access-Control-Request-Headers': 'origin',
origin: 'localhost',
}
);
req.method = 'OPTIONS';

const resp = await runHandler(func, req as any);
expect(resp.status).to.equal(204);
expect(resp.body).to.be.undefined;
expect(resp.headers).to.deep.equal({
'Access-Control-Allow-Methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
'Access-Control-Allow-Origin': 'localhost',
'Content-Length': '0',
Vary: 'Origin, Access-Control-Request-Headers',
});

sinon.restore();
});
});

describe('onCall', () => {
Expand Down Expand Up @@ -317,7 +354,7 @@ describe('onCall', () => {
{
'Access-Control-Request-Method': 'POST',
'Access-Control-Request-Headers': 'origin',
Origin: 'example.com',
origin: 'example.com',
}
);
req.method = 'OPTIONS';
Expand All @@ -333,6 +370,41 @@ describe('onCall', () => {
});
});

it('overrides CORS headers if debug feature is enabled', async () => {
sinon
.stub(debug, 'isDebugFeatureEnabled')
.withArgs('enableCors')
.returns(true);

const func = https.onCall({ cors: 'example.com' }, (request) => {
throw new Error('Should not reach here for OPTIONS preflight');
});
const req = new MockRequest(
{
data: {},
},
{
'Access-Control-Request-Method': 'POST',
'Access-Control-Request-Headers': 'origin',
origin: 'localhost',
}
);
req.method = 'OPTIONS';

const response = await runHandler(func, req as any);

expect(response.status).to.equal(204);
expect(response.body).to.be.undefined;
expect(response.headers).to.deep.equal({
'Access-Control-Allow-Methods': 'POST',
'Access-Control-Allow-Origin': 'localhost',
'Content-Length': '0',
Vary: 'Origin, Access-Control-Request-Headers',
});

sinon.restore();
});

it('adds CORS headers', async () => {
const func = https.onCall((request) => 42);
const req = new MockRequest(
Expand Down
1 change: 1 addition & 0 deletions src/common/debug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const debugMode = process.env.FIREBASE_DEBUG_MODE === 'true';

interface DebugFeatures {
skipTokenVerification?: boolean;
enableCors?: boolean;
}

function loadDebugFeatures(): DebugFeatures {
Expand Down
12 changes: 9 additions & 3 deletions src/v2/providers/https.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import {
import { ManifestEndpoint } from '../../runtime/manifest';
import * as options from '../options';
import { GlobalOptions, SupportedRegion } from '../options';
import { isDebugFeatureEnabled } from '../../common/debug';

export { Request, CallableRequest, FunctionsErrorCode, HttpsError };

Expand Down Expand Up @@ -218,12 +219,13 @@ export function onRequest(
opts = optsOrHandler as HttpsOptions;
}

if ('cors' in opts) {
if (isDebugFeatureEnabled('enableCors') || 'cors' in opts) {
const origin = isDebugFeatureEnabled('enableCors') ? true : opts.cors;
const userProvidedHandler = handler;
handler = (req: Request, res: express.Response): void | Promise<void> => {
return new Promise((resolve) => {
res.on('finish', resolve);
cors({ origin: opts.cors })(req, res, () => {
cors({ origin })(req, res, () => {
resolve(userProvidedHandler(req, res));
});
});
Expand Down Expand Up @@ -319,7 +321,11 @@ export function onCall<T = any, Return = any | Promise<any>>(
opts = optsOrHandler as HttpsOptions;
}

const origin = 'cors' in opts ? opts.cors : true;
const origin = isDebugFeatureEnabled('enableCors')
? true
: 'cors' in opts
? opts.cors
: true;

// onCallHandler sniffs the function length to determine which API to present.
// fix the length to prevent api versions from being mismatched.
Expand Down

0 comments on commit 5fda331

Please sign in to comment.