serve icon indicating copy to clipboard operation
serve copied to clipboard

Default trailingSlash config breaks relative links

Open lukengda opened this issue 4 years ago • 4 comments

Relative href attributes are not correctly resolved based on the configuration of cleanUrls and trailingSlash config.

Scenario

Files:

  • /login/index.html
  • /login/login.ts.html

The index.html has an anchor tag linking to the other page like following:

<a href="login.ts.html">login.ts</a>

(Something like this could be found in an instanbul coverage html report)

This looks to me like a correct link that should correctly link from index.html to login.ts.html.

Observed behavior

  1. Start serve
  2. Open browser on localhost:5000/login/index.html
  3. The server responds with 301: Location | /login/index (this must be the result of the cleanUrls setting removing the file ending .html)
  4. The browser follows the redirect and requests localhost:5000/login/index.html
  5. The server responds again with 301, now for: Location | /login (is this also part of the cleanUrls setting? but anyway, setting trailingSlash to false changes the target /login/)
  6. The browser requests localhost:5000/login and gets a result that is rendered
  7. The browser resolves the relative URL "login.ts.html" as a sibling of "/login" and goes to localhost:5000/login.ts.html
  8. Serve can not serve the file because this path does not exist.

Expected behavior

Serve should (by default) be configured, so that requesting localhost:5000/login/index.html should settle on one of the following URLs to not break relative URL resolution:

  • localhost:5000/login/index.html
  • localhost:5000/login/index
  • localhost:5000/login/

I am aware that i can configure my serve.json to disable trailingSlash. This solves my problem locally but i am arguing for making sure that the default configuration should be changed.

lukengda avatar Aug 14 '20 12:08 lukengda

Just wanted to confirm that I've run into similar.

Looks like serve can't tell the difference between a subpath and a filename that it's stripped the extension from.

Short of broken user-supplied rewrite rules, it's very incorrect for correctly-supplied paths in an HTML to 404, and it's frustrating that this breakage is caused by gold plating.

AFAICT, it's conventional for web servers to add a trailing slash when removing "index.html" from a URL (which keeps relative links within subpaths intact) but not to do the other things serve attempts.

Thank you to @lukengda for explaining & providing a workaround... I thought I was going crazy, and even switched a static-page project to all absolute paths because I didn't realize the problem was serve.

johncip avatar Jan 24 '21 20:01 johncip

Ok, apparently this issue has already been raised a few other times, over a period of years. A couple others:

  • https://github.com/vercel/serve-handler/issues/79
  • https://github.com/vercel/serve/issues/441

But what I did as a workaround (because I still prefer serve to simplehttpserver): Create a serve.json with

{
  "trailingSlash": true
}

Then I put that in my home folder, and aliased serve as serve='serve -c ~/serve.json'.

Edit: the right trailingSlash setting actually depends on what you're trying to serve. For foo/index.html you want it on, but for foo.html you want it off. 🙄

Here's a better workaround:

$ python -m SimpleHTTPServer 5000

johncip avatar Jan 24 '21 20:01 johncip

I'm encountering the same issue. I have a directory like:

index.html
docs
    index.html
    images
        image1.png
        image2.png
        ...

The docs/index.html contains references to images/image1.png. When I open a link to docs/index.html from the main application index.html, it is redirected to docs, and then the relative urls to the images are broken.

josdejong avatar Apr 07 '22 10:04 josdejong