Skip to content

Commit 8493c45

Browse files
authored
fix: respect req.url when modified
1 parent 7c658fe commit 8493c45

File tree

4 files changed

+93
-3
lines changed

4 files changed

+93
-3
lines changed

.changeset/stale-geese-open.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"webpack-dev-middleware": patch
3+
---
4+
5+
Respect `req.url` when modified by middleware such as `connect-history-api-fallback`.

src/utils.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ function parseTokenList(str) {
255255
* @property {(() => string | undefined)=} getMethod get method extra method
256256
* @property {(() => string | undefined)=} getURL get URL extra method
257257
* @property {string=} originalUrl an extra option for `fastify` (and `@fastify/express`) to get original URL
258+
* @property {string=} id an extra option for `fastify` (and `@fastify/express`) to get ID of request
258259
*/
259260

260261
/**
@@ -312,9 +313,17 @@ function getRequestURL(req) {
312313
if (typeof req.getURL === "function") {
313314
return req.getURL();
314315
}
315-
// Fastify decodes URI by default, Our logic is based on encoded URI
316-
else if (typeof req.originalUrl !== "undefined") {
317-
return req.originalUrl;
316+
// Fastify decodes URI by default, our logic is based on encoded URI.
317+
// `req.url` may be modified by middleware (e.g. connect-history-api-fallback), in which case we use req.url instead.
318+
// `req.id` is a special property of `fastify`
319+
else if (req.id && req.originalUrl) {
320+
try {
321+
if (req.url === decodeURI(req.originalUrl)) {
322+
return req.originalUrl;
323+
}
324+
} catch {
325+
// decodeURI can throw on malformed sequences, fall through
326+
}
318327
}
319328

320329
return req.url;

test/middleware.test.js

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3473,6 +3473,77 @@ describe.each([
34733473
});
34743474
});
34753475

3476+
if (!["hapi", "hono"].includes(name)) {
3477+
describe("should work when req.url is modified by middleware to a file with encoded characters", () => {
3478+
let compiler;
3479+
3480+
const outputPath = path.resolve(
3481+
__dirname,
3482+
"./outputs/basic-test-modified-url-encoded",
3483+
);
3484+
3485+
beforeAll(async () => {
3486+
compiler = getCompiler({
3487+
...webpackConfig,
3488+
output: {
3489+
filename: "bundle.js",
3490+
path: outputPath,
3491+
},
3492+
});
3493+
3494+
[server, req, instance] = await frameworkFactory(
3495+
name,
3496+
framework,
3497+
compiler,
3498+
{},
3499+
{
3500+
setupMiddlewares: (middlewares) => {
3501+
if (name === "koa") {
3502+
middlewares.unshift(async (ctx, next) => {
3503+
ctx.url = "/file with spaces.html";
3504+
3505+
await next();
3506+
});
3507+
} else {
3508+
middlewares.unshift({
3509+
route: "/",
3510+
fn: (oldReq, res, next) => {
3511+
oldReq.url = "/file with spaces.html";
3512+
next();
3513+
},
3514+
});
3515+
}
3516+
3517+
return middlewares;
3518+
},
3519+
},
3520+
);
3521+
3522+
instance.context.outputFileSystem.mkdirSync(outputPath, {
3523+
recursive: true,
3524+
});
3525+
instance.context.outputFileSystem.writeFileSync(
3526+
path.resolve(outputPath, "file with spaces.html"),
3527+
"HTML with spaces",
3528+
);
3529+
});
3530+
3531+
afterAll(async () => {
3532+
await close(server, instance);
3533+
});
3534+
3535+
it('should return the "200" code for the "GET" request when req.url is rewritten to a path with spaces', async () => {
3536+
const response = await req.get("/any-path");
3537+
3538+
expect(response.statusCode).toBe(200);
3539+
expect(response.headers["content-type"]).toBe(
3540+
"text/html; charset=utf-8",
3541+
);
3542+
expect(response.text).toBe("HTML with spaces");
3543+
});
3544+
});
3545+
}
3546+
34763547
describe("should work and don't call the next middleware for finished or errored requests by default", () => {
34773548
let compiler;
34783549

types/utils.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ export type ExpectedIncomingMessage = {
1818
* an extra option for `fastify` (and `@fastify/express`) to get original URL
1919
*/
2020
originalUrl?: string | undefined;
21+
/**
22+
* an extra option for `fastify` (and `@fastify/express`) to get ID of request
23+
*/
24+
id?: string | undefined;
2125
};
2226
export type ExpectedServerResponse = {
2327
/**
@@ -147,6 +151,7 @@ export function getOutgoing<
147151
* @property {(() => string | undefined)=} getMethod get method extra method
148152
* @property {(() => string | undefined)=} getURL get URL extra method
149153
* @property {string=} originalUrl an extra option for `fastify` (and `@fastify/express`) to get original URL
154+
* @property {string=} id an extra option for `fastify` (and `@fastify/express`) to get ID of request
150155
*/
151156
/**
152157
* @typedef {object} ExpectedServerResponse

0 commit comments

Comments
 (0)