From f079dcd59f44ac43db696078742300a3b8e87382 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 19 Jun 2026 23:29:17 +0000 Subject: [PATCH 1/3] perf: eliminate hot-path filesystem and regex costs in handler/routing layer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Four targeted optimizations on the per-request execution path: 1. HandlerService: cache ImplicitViews setting `getSetting("ImplicitViews")` was called on every handler dispatch where the requested action was missing. It is now cached to variables scope in onConfigurationLoad() alongside every other already-cached setting. 2. HandlerService.isViewDispatch: drop redundant fileExists(expandPath()) locateView/locateModuleView already verify file existence and return the path with a .cfm/.bxm extension only when the file is confirmed present. The follow-up fileExists() call was re-doing answered work. Replaced with a cheap string suffix check — zero filesystem I/O. 3. RoutingService.findRoute: use cached canDebug local variable consistently canDebug was already stored in a local variable at the top of findRoute() but three spots inside the same method re-called getLogger().canDebug() instead of using it. All three now use the cached local variable. 4. Router/RoutingService: pre-parse response string placeholders at registration renderResponse() was running reMatchNoCase + reReplaceNoCase on the route's static response string on every request. Tokens are now parsed once in addRoute() into a responsePlaceholders array; renderResponse() iterates the pre-parsed list with no regex at runtime. Also fixes a latent bug where multiple placeholders were not all applied (original always replaced into the original string rather than the accumulated result). Co-Authored-By: Claude Sonnet 4.6 Claude-Session: https://claude.ai/code/session_01MUinjJLvJod1u9s2e9T6zc --- system/web/routing/Router.cfc | 8 +++ system/web/services/HandlerService.cfc | 8 ++- system/web/services/RoutingService.cfc | 20 +++---- tests/specs/web/routing/RouterTest.cfc | 55 +++++++++++++++++++ .../specs/web/services/HandlerServiceTest.cfc | 25 +++++++++ 5 files changed, 102 insertions(+), 14 deletions(-) diff --git a/system/web/routing/Router.cfc b/system/web/routing/Router.cfc index a08aaed0f..f3593b39f 100644 --- a/system/web/routing/Router.cfc +++ b/system/web/routing/Router.cfc @@ -1065,6 +1065,13 @@ component } } + // Pre-parse response string placeholders so renderResponse() skips regex on every request + if ( isSimpleValue( thisRoute.response ) && len( thisRoute.response ) ) { + thisRoute.responsePlaceholders = reMatchNoCase( "{[^{]+?}", thisRoute.response ).map( function( token ){ + return { token : token, key : reReplaceNoCase( token, "({|})", "", "all" ) }; + } ); + } + // Add it to the corresponding routing table // MODULES if ( len( arguments.module ) ) { @@ -1133,6 +1140,7 @@ component "rc" : {}, // The RC params to add incorporate if matched "redirect" : "", // The redirection location "response" : "", // Do we have an inline response closure + "responsePlaceholders" : [], // Pre-parsed {token} list for string responses "ssl" : false, // Are we forcing SSL "statusCode" : 200, // The response status code "valuePairTranslation" : true, // If we translate name-value pairs in the URL by convention diff --git a/system/web/services/HandlerService.cfc b/system/web/services/HandlerService.cfc index a5d56d87b..9934db30e 100644 --- a/system/web/services/HandlerService.cfc +++ b/system/web/services/HandlerService.cfc @@ -82,6 +82,7 @@ component extends="coldbox.system.web.services.BaseService" accessors="true" { variables.handlersPath = variables.controller.getSetting( "handlersPath" ) variables.interceptorService = variables.controller.getInterceptorService() variables.invalidEventHandler = variables.controller.getSetting( "invalidEventHandler" ) + variables.implicitViews = variables.controller.getSetting( "ImplicitViews" ) variables.modules = variables.controller.getSetting( "modules" ) variables.templateCache = variables.controller.getCache( "template" ) variables.wirebox = variables.controller.getWireBox() @@ -155,7 +156,7 @@ component extends="coldbox.system.web.services.BaseService" accessors="true" { // Test for Implicit View Dispatch if ( - controller.getSetting( "ImplicitViews" ) AND + variables.implicitViews AND isViewDispatch( arguments.ehBean.getFullEvent(), arguments.ehBean ) ) { return oEventHandler; @@ -404,8 +405,9 @@ component extends="coldbox.system.web.services.BaseService" accessors="true" { targetView = renderer.locateView( cEvent ); } - // CFML View - if ( fileExists( expandPath( targetView ) ) ) { + // locateView/locateModuleView return a path with .cfm/.bxm extension only when + // the file was verified to exist — no need for a redundant filesystem call here. + if ( right( targetView, 4 ) == ".cfm" || right( targetView, 4 ) == ".bxm" ) { arguments.ehBean.setViewDispatch( true ); return true; } diff --git a/system/web/services/RoutingService.cfc b/system/web/services/RoutingService.cfc index 70ff60e4d..39b277243 100644 --- a/system/web/services/RoutingService.cfc +++ b/system/web/services/RoutingService.cfc @@ -533,7 +533,7 @@ component extends="coldbox.system.web.services.BaseService" accessors="true" { // Check if we found a route, else just return empty params struct if ( results.route.isEmpty() ) { - if ( getLogger().canDebug() ) { + if ( canDebug ) { getLogger().debug( "No URL routes matched on routed string: #requestString#" ); } return results; @@ -599,7 +599,7 @@ component extends="coldbox.system.web.services.BaseService" accessors="true" { // reset pattern matching, if packages found. if ( compare( packagedRequestString, requestString ) NEQ 0 ) { // Log package resolved - if ( getLogger().canDebug() ) { + if ( canDebug ) { getLogger().debug( "URL Routing Package Resolved: #packagedRequestString#" ); } // Return found Route recursively. @@ -781,16 +781,14 @@ component extends="coldbox.system.web.services.BaseService" accessors="true" { // simple values if ( isSimpleValue( aRoute.response ) ) { // setup default response - theResponse = aRoute.response; - // String replacements - var replacements = reMatchNoCase( "{[^{]+?}", aRoute.response ); - for ( var thisReplacement in replacements ) { - var thisKey = reReplaceNoCase( thisReplacement, "({|})", "", "all" ); - if ( event.valueExists( thisKey ) ) { + theResponse = aRoute.response; + // Apply pre-parsed placeholders (tokens resolved once at route registration) + for ( var placeholder in aRoute.responsePlaceholders ) { + if ( event.valueExists( placeholder.key ) ) { theResponse = replace( - aRoute.response, - thisReplacement, - event.getValue( thisKey ), + theResponse, + placeholder.token, + event.getValue( placeholder.key ), "all" ); } diff --git a/tests/specs/web/routing/RouterTest.cfc b/tests/specs/web/routing/RouterTest.cfc index b39aac485..808557c91 100644 --- a/tests/specs/web/routing/RouterTest.cfc +++ b/tests/specs/web/routing/RouterTest.cfc @@ -666,6 +666,61 @@ component extends="coldbox.system.testing.BaseModelTest" { } ); } ); } ); + + describe( "Response placeholder pre-parsing", function(){ + beforeEach( function( currentSpec ){ + router = createMock( "coldbox.system.web.routing.Router" ) + .init() + .setController( controller ) + .setLogBox( controller.getLogBox() ) + .setLog( controller.getLogBox().getLogger( this ) ) + .setCacheBox( controller.getCacheBox() ) + .setWireBox( controller.getWireBox() ); + } ); + + it( "a route with a static string response pre-parses placeholders at registration", function(){ + router.addRoute( pattern = "/hello/:name", response = "Hello {name}!" ); + var routes = router.getRoutes(); + expect( routes ).toHaveLength( 1 ); + expect( routes[ 1 ] ).toHaveKey( "responsePlaceholders" ); + expect( routes[ 1 ].responsePlaceholders ).toHaveLength( 1 ); + expect( routes[ 1 ].responsePlaceholders[ 1 ].token ).toBe( "{name}" ); + expect( routes[ 1 ].responsePlaceholders[ 1 ].key ).toBe( "name" ); + } ); + + it( "a route with multiple placeholders pre-parses all of them", function(){ + router.addRoute( pattern = "/greet/:name/:mod", response = "Hello {name} from {mod}" ); + var routes = router.getRoutes(); + expect( routes[ 1 ].responsePlaceholders ).toHaveLength( 2 ); + expect( routes[ 1 ].responsePlaceholders[ 1 ].key ).toBe( "name" ); + expect( routes[ 1 ].responsePlaceholders[ 2 ].key ).toBe( "mod" ); + } ); + + it( "a route with no placeholders has an empty responsePlaceholders array", function(){ + router.addRoute( pattern = "/static", response = "No placeholders here" ); + var routes = router.getRoutes(); + expect( routes[ 1 ].responsePlaceholders ).toBeArray(); + expect( routes[ 1 ].responsePlaceholders ).toHaveLength( 0 ); + } ); + + it( "a route with a closure response has an empty responsePlaceholders array", function(){ + router.addRoute( + pattern = "/closure", + response = function( event, rc, prc ){ return "hi"; } + ); + var routes = router.getRoutes(); + expect( routes[ 1 ].responsePlaceholders ).toBeArray(); + expect( routes[ 1 ].responsePlaceholders ).toHaveLength( 0 ); + } ); + + it( "a route with no response has an empty responsePlaceholders array", function(){ + router.addRoute( pattern = "/noop", event = "main.index" ); + var routes = router.getRoutes(); + expect( routes[ 1 ].responsePlaceholders ).toBeArray(); + expect( routes[ 1 ].responsePlaceholders ).toHaveLength( 0 ); + } ); + } ); + } ); } } diff --git a/tests/specs/web/services/HandlerServiceTest.cfc b/tests/specs/web/services/HandlerServiceTest.cfc index dc5589eb7..10f1598bf 100755 --- a/tests/specs/web/services/HandlerServiceTest.cfc +++ b/tests/specs/web/services/HandlerServiceTest.cfc @@ -194,6 +194,31 @@ component extends="tests.resources.BaseIntegrationTest" { } ); } ); } ); + + describe( "Hot-path caching optimizations", () => { + beforeEach( () => { + setup(); + variables.handlerService = controller.getHandlerService(); + } ); + + it( "caches implicitViews setting in variables scope after configuration load", () => { + // implicitViews must be a boolean cached from getSetting("ImplicitViews") + expect( variables.handlerService.$getProperty( "implicitViews", "variables" ) ).toBeBoolean(); + expect( variables.handlerService.$getProperty( "implicitViews", "variables" ) ).toBeTrue(); + } ); + + it( "isViewDispatch detects a view by extension without a filesystem call", () => { + // simpleview exists — getHandlerBean triggers isViewDispatch internally + // If the extension-check logic is wrong the viewDispatch flag won't be set + var results = variables.handlerService.getHandlerBean( "simpleview" ); + expect( results.getViewDispatch() ).toBeTrue(); + } ); + + it( "isViewDispatch returns false for an event with no matching view", () => { + var results = variables.handlerService.getHandlerBean( "nonexistent_view_xyz" ); + expect( results.getViewDispatch() ).toBeFalse(); + } ); + } ); } } From 79a105abcd3de9b9b659870beee217477fea73e1 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 20 Jun 2026 08:44:34 +0000 Subject: [PATCH 2/3] fix(tests): remove extra closing brace in RouterTest causing parse error Co-Authored-By: Claude Sonnet 4.6 Claude-Session: https://claude.ai/code/session_01MUinjJLvJod1u9s2e9T6zc --- tests/specs/web/routing/RouterTest.cfc | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/specs/web/routing/RouterTest.cfc b/tests/specs/web/routing/RouterTest.cfc index 808557c91..34da95617 100644 --- a/tests/specs/web/routing/RouterTest.cfc +++ b/tests/specs/web/routing/RouterTest.cfc @@ -720,7 +720,6 @@ component extends="coldbox.system.testing.BaseModelTest" { expect( routes[ 1 ].responsePlaceholders ).toHaveLength( 0 ); } ); } ); - } ); } } From 2b1a333afe556c73fb18b92b069f3807d707227a Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 20 Jun 2026 08:51:19 +0000 Subject: [PATCH 3/3] fix(tests): always set responsePlaceholders on route; use prepareMock for $getProperty - Router.addRoute() builds thisRoute from arguments struct, not initRouteDefinition(), so responsePlaceholders was only added for string responses. Add else branch to set [] for closure/empty cases. - HandlerServiceTest: getHandlerService() returns the real service object; call prepareMock() before using $getProperty to access variables scope. Co-Authored-By: Claude Sonnet 4.6 Claude-Session: https://claude.ai/code/session_01MUinjJLvJod1u9s2e9T6zc --- system/web/routing/Router.cfc | 2 ++ tests/specs/web/services/HandlerServiceTest.cfc | 1 + 2 files changed, 3 insertions(+) diff --git a/system/web/routing/Router.cfc b/system/web/routing/Router.cfc index f3593b39f..2e5d0da79 100644 --- a/system/web/routing/Router.cfc +++ b/system/web/routing/Router.cfc @@ -1070,6 +1070,8 @@ component thisRoute.responsePlaceholders = reMatchNoCase( "{[^{]+?}", thisRoute.response ).map( function( token ){ return { token : token, key : reReplaceNoCase( token, "({|})", "", "all" ) }; } ); + } else { + thisRoute.responsePlaceholders = []; } // Add it to the corresponding routing table diff --git a/tests/specs/web/services/HandlerServiceTest.cfc b/tests/specs/web/services/HandlerServiceTest.cfc index 10f1598bf..86ce1c260 100755 --- a/tests/specs/web/services/HandlerServiceTest.cfc +++ b/tests/specs/web/services/HandlerServiceTest.cfc @@ -203,6 +203,7 @@ component extends="tests.resources.BaseIntegrationTest" { it( "caches implicitViews setting in variables scope after configuration load", () => { // implicitViews must be a boolean cached from getSetting("ImplicitViews") + prepareMock( variables.handlerService ); expect( variables.handlerService.$getProperty( "implicitViews", "variables" ) ).toBeBoolean(); expect( variables.handlerService.$getProperty( "implicitViews", "variables" ) ).toBeTrue(); } );