Skip to content
Merged
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
2 changes: 1 addition & 1 deletion system/web/services/ModuleService.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -843,7 +843,7 @@ component extends="coldbox.system.web.services.BaseService" accessors="true" {
var conventionsRouteExists = mConfig.router
.getRoutes()
.findAll( ( item ) => {
return ( item.pattern == "/:handler/:action" || item.pattern == ":handler/:action" )
return reFindNoCase( "^/?\:handler/\:action\??/?$", item.pattern )
} )
if ( arrayLen( conventionsRouteExists ) == 0 ) {
mConfig.router.route( "/:handler/:action?" ).end()
Expand Down
8 changes: 7 additions & 1 deletion system/web/services/RoutingService.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,7 @@ component extends="coldbox.system.web.services.BaseService" accessors="true" {
// build routing argument struct based on module/namespace context
var contextRouting = {
action : reReplaceNoCase( requestString, results.route.regexpattern, "" ),
domain : arguments.domain,
event : arguments.event,
excludedPatterns : arguments.excludedPatterns
};
Expand All @@ -659,10 +660,14 @@ component extends="coldbox.system.web.services.BaseService" accessors="true" {
// process context discovery of incoming pattern
var contextRoute = findRoute( argumentCollection = contextRouting );

// Return if route Not found.
if ( !contextRoute.route.isEmpty() ) {
return contextRoute;
}

// A module or namespace mount point is not itself an executable route.
// Return the empty nested result so a failed domain or condition match
// cannot fall back to the mount point.
return contextRoute;
}

// Save current routed details in PRC
Expand Down Expand Up @@ -695,6 +700,7 @@ component extends="coldbox.system.web.services.BaseService" accessors="true" {
// Return found Route recursively.
return findRoute(
action = packagedRequestString,
domain = arguments.domain,
event = arguments.event,
module = arguments.module,
excludedPatterns = arguments.excludedPatterns
Expand Down
10 changes: 10 additions & 0 deletions tests/specs/integration/ModuleSpec.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,16 @@ component extends="tests.resources.BaseIntegrationTest" {

expect( routing ).notToBeEmpty();
} );

then( "an explicit convention route should not be registered twice", () => {
var routingService = getController().getRoutingService();
var routing = routingService.getModuleRoutes( "resourcesTest" );
var conventionRoutes = routing.filter( ( item ) => {
return reFindNoCase( "^/?\:handler/\:action\??/?$", item.pattern );
} );

expect( conventionRoutes ).toHaveLength( 1 );
} );
} );
} );

Expand Down
47 changes: 47 additions & 0 deletions tests/specs/web/routing/RoutingServiceTest.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,53 @@

expect( discoveredEventPOST ).toBe( "api-v1:MyOtherHandler.create" );
} );

it( "preserves the request domain when resolving module routes", function(){
var moduleName = "domainRoutingTest";
var router = getController().getRoutingService().getRouter();
var modules = getController().getSetting( "modules" );
var mockEvent = createMock( "coldbox.system.web.context.RequestContext" ).init(
controller = getController(),
properties = {
defaultLayout : "Main.cfm",
defaultView : "",
eventName : "event",
modules : {}
}
);

modules[ moduleName ] = { resources : [], routes : [] };

try {
router.addModuleRoutes(
pattern = "/domain-module",
module = moduleName,
append = false
);
router.addRoute(
pattern = "/ceremony",
event = "Passkeys.authenticate",
domain = "allowed.example",
module = moduleName
);
var allowed = routingService.findRoute(
action = "/domain-module/ceremony",
domain = "allowed.example",
event = mockEvent
);
var denied = routingService.findRoute(
action = "/domain-module/ceremony",
domain = "denied.example",
event = mockEvent
);

expect( allowed.route.event ).toBe( "Passkeys.authenticate" );
expect( denied.route ).toBeEmpty();
} finally {
router.removeModuleRoutes( moduleName );
structDelete( modules, moduleName );
}
} );
} );

describe( "route-scoped middleware (runRouteMiddleware())", function(){
Expand Down
Loading