Skip to content

Commit

Permalink
feat(cors): Dynamically determine allowed methods
Browse files Browse the repository at this point in the history
  • Loading branch information
elpete committed Aug 8, 2019
1 parent 97cae05 commit 1e33450
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 6 deletions.
4 changes: 3 additions & 1 deletion ModuleConfig.cfc
Expand Up @@ -9,7 +9,9 @@ component {
allowOrigins = function( event ) {
return event.getHTTPHeader( "Origin", "*" );
},
allowMethods = [ "DELETE", "GET", "PATCH", "POST", "PUT", "OPTIONS" ],
allowMethods = function( event ) {
return event.getHTTPMethod();
},
allowHeaders = [ "Content-Type", "X-Auth-Token", "Origin", "Authorization" ],
maxAge = 60 * 60 * 24, // 1 day
allowCredentials = true,
Expand Down
22 changes: 19 additions & 3 deletions interceptors/CORS.cfc
Expand Up @@ -61,8 +61,17 @@ component {

log.debug( "Setting the 'Access-Control-Allow-Headers' header to #allowedHeaders#." );
event.setHTTPHeader( name = "Access-Control-Allow-Headers", value = allowedHeaders );
log.debug( "Setting the 'Access-Control-Allow-Methods' header to #arrayToList( settings.allowMethods, ", " )#." );
event.setHTTPHeader( name = "Access-Control-Allow-Methods", value = arrayToList( settings.allowMethods, ", " ) );

var allowedMethods = settings.allowMethods;
if ( isClosure( allowedMethods ) || isCustomFunction( allowedMethods ) ) {
allowedMethods = allowedMethods( event );
}
if ( isArray( allowedMethods ) ) {
allowedMethods = arrayToList( allowedMethods, ", " );
}
log.debug( "Setting the 'Access-Control-Allow-Methods' header to #allowedMethods#." );
event.setHTTPHeader( name = "Access-Control-Allow-Methods", value = allowedMethods );

log.debug( "Setting the 'Access-Control-Max-Age' header to #settings.maxAge#." );
event.setHTTPHeader( name = "Access-Control-Max-Age", value = settings.maxAge );

Expand Down Expand Up @@ -142,7 +151,14 @@ component {
}

private function isAllowed( event, settings ) {
if ( ! arrayContains( settings.allowMethods, event.getHTTPMethod() ) ) {
var allowedMethods = settings.allowMethods;
if ( isClosure( allowedMethods ) || isCustomFunction( allowedMethods ) ) {
allowedMethods = allowedMethods( event );
}
if ( isSimpleValue( allowedMethods ) ) {
allowedMethods = listToArray( allowedMethods, "," );
}
if ( ! arrayContains( allowedMethods, event.getHTTPMethod() ) ) {
return false;
}

Expand Down
25 changes: 23 additions & 2 deletions tests/specs/integration/CORSSpec.cfc
Expand Up @@ -39,7 +39,7 @@ component extends="tests.resources.ModuleIntegrationSpec" appMapping="/app" {
.$results( "example.com" )
.$( "getHTTPHeader" )
.$args( "Origin", "*" )
.$results( "example.com" );;
.$results( "example.com" );
var event = execute( route = "/", renderResults = true );

var responseHeaders = getHeaders( event );
Expand All @@ -48,7 +48,7 @@ component extends="tests.resources.ModuleIntegrationSpec" appMapping="/app" {
expect( responseHeaders[ "Access-Control-Allow-Origin" ] ).toBe( "example.com" );

expect( responseHeaders ).toHaveKey( "Access-Control-Allow-Methods" );
expect( responseHeaders[ "Access-Control-Allow-Methods" ] ).toBe( "DELETE, GET, PATCH, POST, PUT, OPTIONS" );
expect( responseHeaders[ "Access-Control-Allow-Methods" ] ).toBe( "OPTIONS" );

expect( responseHeaders ).toHaveKey( "Access-Control-Allow-Headers" );
expect( responseHeaders[ "Access-Control-Allow-Headers" ] ).toBe( "Content-Type, X-Auth-Token, Origin, Authorization" );
Expand Down Expand Up @@ -174,6 +174,27 @@ component extends="tests.resources.ModuleIntegrationSpec" appMapping="/app" {
expect( responseHeaders[ "Access-Control-Allow-Methods" ] ).toBe( "OPTIONS, GET, POST" );
} );

it( "can configure the allowed methods with a closure", function() {
getController().getConfigSettings().modules.cors.settings.allowMethods = function( event ) {
return event.getHTTPMethod();
};

prepareMock( getRequestContext() )
.$( "getHTTPMethod", "OPTIONS" )
.$( "getHTTPHeader" )
.$args( "Origin", "" )
.$results( "example.com" )
.$( "getHTTPHeader" )
.$args( "Origin", "*" )
.$results( "example.com" );
var event = execute( route = "/", renderResults = true );

var responseHeaders = getHeaders( event );

expect( responseHeaders ).toHaveKey( "Access-Control-Allow-Methods" );
expect( responseHeaders[ "Access-Control-Allow-Methods" ] ).toBe( "OPTIONS" );
} );

it( "can configure the allowed headers", function() {
getController().getConfigSettings().modules.cors.settings.allowHeaders = [ "Content-Type" ];

Expand Down

0 comments on commit 1e33450

Please sign in to comment.