@@ -140,11 +140,18 @@ export function createAppEventHandler(stack: Stack, options: AppOptions) {
140140 event . node . req . originalUrl =
141141 event . node . req . originalUrl || event . node . req . url || "/" ;
142142
143+ // Preserve the raw (percent-encoded) URL for proxies and Node.js middleware
144+ // that expect req.url in its original encoded form (RFC 3986).
145+ const _rawReqUrl = event . node . req . url || "/" ;
146+
143147 // Decode percent-encoded path segments to prevent auth bypass via encoding tricks.
144148 // Only decode the path portion, not the query string, to avoid double-decoding.
145- const _reqPath = _decodePath ( event . _path || event . node . req . url || "/" ) ;
149+ const _reqPath = _decodePath ( event . _path || _rawReqUrl ) ;
146150 event . _path = _reqPath ;
147151
152+ // Fast path: skip raw tracking when URL had nothing to decode
153+ const _needsRawUrl = _reqPath !== _rawReqUrl ;
154+
148155 // Layer path is the path without the prefix
149156 let _layerPath : string ;
150157
@@ -169,9 +176,14 @@ export function createAppEventHandler(stack: Stack, options: AppOptions) {
169176 continue ;
170177 }
171178
172- // 3. Update event path with layer path
179+ // 3. Update event path (decoded for h3 internal routing)
180+ // and req.url (raw encoded for HTTP proxies and Node.js middleware)
173181 event . _path = _layerPath ;
174- event . node . req . url = _layerPath ;
182+ event . node . req . url = _needsRawUrl
183+ ? layer . route . length > 1
184+ ? _rawReqUrl . slice ( layer . route . length ) || "/"
185+ : _rawReqUrl
186+ : _layerPath ;
175187
176188 // 4. Handle request
177189 const val = await layer . handler ( event ) ;
0 commit comments