Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dynamic routes url in dev mode contains illegal characters #15049

Closed
JoHaHu opened this issue Sep 27, 2022 · 9 comments
Closed

dynamic routes url in dev mode contains illegal characters #15049

JoHaHu opened this issue Sep 27, 2022 · 9 comments

Comments

@JoHaHu
Copy link

JoHaHu commented Sep 27, 2022

Environment

  • Operating System: Linux
  • Node Version: v16.16.0
  • Nuxt Version: 3.0.0-rc.11
  • Nitro Version: 0.5.4
  • Package Manager: npm@8.11.0
  • Builder: vite
  • User Config: modules, colorMode, ssr, app, store, srcDir, vite
  • Runtime Modules: @pinia/nuxt@0.4.2, @nuxtjs/tailwindcss@5.3.3, @nuxtjs/color-mode@3.1.6
  • Build Modules: -

Reproduction

same issue as in #12606

java.net.URISyntaxException: Illegal character in path at index 22: http://localhost:8080/[...slug]-4eea24f4.mjs
at java.base/java.net.URI$Parser.fail(Unknown Source)
at java.base/java.net.URI$Parser.checkChars(Unknown Source)
at java.base/java.net.URI$Parser.parseHierarchical(Unknown Source)
at java.base/java.net.URI$Parser.parse(Unknown Source)
at java.base/java.net.URI.(Unknown Source)
at java.base/java.net.URI.create(Unknown Source)
at reactor.netty.http.HttpOperations.resolvePath(HttpOperations.java:388)
at reactor.netty.http.server.HttpServerOperations.(HttpServerOperations.java:160)
at reactor.netty.http.server.HttpServerOperations.(HttpServerOperations.java:136)

Describe the bug

If a dynamic route is used, production build urls are sanitized. During development this sanitation is not applied leading to Illegal characters (rfc2396).

Additionally if we take a dynamic route e.g. details-[id].vue during development this will create illegal urls.
If we instead use details-:id.vue it works, but I'm not sure if this should be escaped before passed to vue router or not.

Additional context

#12606

Logs

No response

@danielroe
Copy link
Member

I think this would be an issue for vite, not Nuxt. There should be no issue if used with the default development server. (I'm assuming you have another server proxying access to your dev server.)

@JoHaHu
Copy link
Author

JoHaHu commented Sep 29, 2022

Ok. Then i will close this here and reopen in vite.

@sapphi-red
Copy link
Contributor

[id].vue is imported from /_nuxt/@id/virtual:nuxt:/home/projects/github-tjxq2a-k3p4ab/.nuxt/routes.mjs:

import { meta as _47home_47projects_47github_45tjxq2a_45k3p4ab_47pages_47index_46vueMeta } from "/_nuxt/pages/index.vue?macro=true";
import { meta as _47home_47projects_47github_45tjxq2a_45k3p4ab_47pages_47test_46vueMeta } from "/_nuxt/pages/test.vue?macro=true";
import { meta as _47home_47projects_47github_45tjxq2a_45k3p4ab_47pages_47test_47_91id_93_46vueMeta } from "/_nuxt/pages/test/[id].vue?macro=true";
export default [
  {
    name: "index",
    path: "/",
    file: "/home/projects/github-tjxq2a-k3p4ab/pages/index.vue",
    children: [],
    meta: _47home_47projects_47github_45tjxq2a_45k3p4ab_47pages_47index_46vueMeta,
    alias: _47home_47projects_47github_45tjxq2a_45k3p4ab_47pages_47index_46vueMeta?.alias || [],
    component: () => import("/_nuxt/pages/index.vue").then(m => m.default || m)
  },
  {
    name: "test",
    path: "/test",
    file: "/home/projects/github-tjxq2a-k3p4ab/pages/test.vue",
    children: [
  {
    name: "test-id",
    path: ":id",
    file: "/home/projects/github-tjxq2a-k3p4ab/pages/test/[id].vue",
    children: [],
    meta: _47home_47projects_47github_45tjxq2a_45k3p4ab_47pages_47test_47_91id_93_46vueMeta,
    alias: _47home_47projects_47github_45tjxq2a_45k3p4ab_47pages_47test_47_91id_93_46vueMeta?.alias || [],
    component: () => import("/_nuxt/pages/test/[id].vue").then(m => m.default || m)
  }
],
    meta: _47home_47projects_47github_45tjxq2a_45k3p4ab_47pages_47test_46vueMeta,
    alias: _47home_47projects_47github_45tjxq2a_45k3p4ab_47pages_47test_46vueMeta?.alias || [],
    component: () => import("/_nuxt/pages/test.vue").then(m => m.default || m)
  }
]

This file seems to be generated by nuxt and I think the escaping needs to be handled on nuxt side.
https://github.com/nuxt/framework/blob/eab4706614199594006b2132f57e838718ac3e73/packages/nuxt/src/pages/module.ts#L121-L129
https://github.com/nuxt/framework/blob/eab4706614199594006b2132f57e838718ac3e73/packages/nuxt/src/pages/utils.ts#L246

@danielroe
Copy link
Member

danielroe commented Oct 2, 2022

@sapphi-red Why should this be handled by Nuxt? It's the name of the file and a valid import. The issue, as I understand it, is the HTTP request that vite makes is not valid (according to the Java HTTP framework being used by OP).

What kind of escaping are you suggesting that Nuxt should do?

But happy to be corrected!

@sapphi-red
Copy link
Contributor

sapphi-red commented Oct 2, 2022

IIUC the setup is "Browser <-> Java Server <-> Vite" and the steps are:

  1. routes.mjs is served to browser
  2. router.mjs is executed by browser
  3. browser requests /_nuxt/pages/test/[id].vue
  4. Java server rejects that request

So if import("/_nuxt/pages/test/[id].vue") were changed to import("/_nuxt/pages/test/%5Bid%5D.vue"), I guess it works. (also for [id].vue?macro=true)

It's the name of the file and a valid import.

Now I recognized the problem here.
Specifiers are parsed1 by URL parser defined in URL Standard2.
But URL Standard seems to be slightly different from RFC 3986 (which superseded RFC 2396).

http://example.com/[id].vue seems to be valid in URL Standard but not valid in RFC 3986.
Browsers works based on URL Standard, so it doesn't throw any errors. But the Java Server rejects that request since it tries to parse the URL based on RFC 3986.

Footnotes

  1. https://html.spec.whatwg.org/multipage/webappapis.html#resolve-a-module-specifier

  2. https://url.spec.whatwg.org/#concept-url-parser

@danielroe
Copy link
Member

@sapphi-red But that code isn't outputting URLs. It's also not written just for Vite, and if we output escaped characters there it would break everywhere else (including possibly in build). I'm not even convinced it would work with the vite dev server, but trust you know much more than me on this one.

Here's how Node would handle escaped character in imports:

❯ node
> require('./[bob].js')
42
> require('./%5Bbob%5D.js')
Uncaught Error: Cannot find module './%5Bbob%5D.js'
Require stack:
- <repl>
    at Function.Module._resolveFilename (node:internal/modules/cjs/loader:956:15)
    at Function.Module._load (node:internal/modules/cjs/loader:804:27)
    at Module.require (node:internal/modules/cjs/loader:1028:19)
    at require (node:internal/modules/cjs/helpers:102:18) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [ '<repl>' ]
}

Imagine a compiled module had a relative import from a file with a bracket in its name. The same problem would occur; the fact that this is a virtual module isn't relevant, I think.

I think the point I'm making is that vite, instead of requesting the exact URL in the file, could encode it in the client (and then decode it in the dev server). That would seem to make more sense to me - if you, indeed, did decide to support this very particular use case.

@sapphi-red
Copy link
Contributor

sapphi-red commented Oct 2, 2022

I'm not even convinced it would work with the vite dev server, but trust you know much more than me on this one.

Sorry, it seems it doesn't work with vite. (This is a bug I think)

Here's how Node would handle escaped character in imports:

That is not working because require is used. For import, it has a different behavior.

$ node --input-type=module -e "console.log(await import('./[a].mjs'))"
[Module: null prototype] { default: 42 }
$ node --input-type=module -e "console.log(await import('./%5Ba%5D.mjs'))"
[Module: null prototype] { default: 42 }

Relative import specifiers are URL (parsed by URL Standard).

I think the point I'm making is that vite, instead of requesting the exact URL in the file, could encode it in the client (and then decode it in the dev server).

I see.
I now agree this should be handled on Vite side (or by a plugin) if this is going to be supported.

@danielroe
Copy link
Member

danielroe commented Oct 2, 2022

TIL - thank you 😊

It sounds like we could escape them in this particular template, which is certainly where they are most likely to have brackets in the filenames. But it would not affect any other imports in other modules, and Vite already is transforming the import specifiers in the virtual module (for example, to make them absolute and to add the base).

Do you think it still makes sense to escape them? Happy to open an issue to track if you feel it's a bug in Nuxt.

@sapphi-red
Copy link
Contributor

sapphi-red commented Oct 4, 2022

Thanks for the replies. 💚

I think it's better to handle in Vite (or by a plugin). (or the Java server)

And I think it's more a feature request than a bug in vite or nuxt (since it's compliant to URL standard spec).

@danielroe danielroe added the 3.x label Jan 19, 2023
@danielroe danielroe transferred this issue from nuxt/framework Jan 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants