terreng / simple-web-server

Create a local web server in just a few clicks with an easy to use interface. Built with Electron.
https://simplewebserver.org
MIT License
255 stars 67 forks source link

Missing Content-Encoding: gzip Header for Files with .gz Extension #219

Open tigerbalm opened 3 weeks ago

tigerbalm commented 3 weeks ago

Description/Steps to reproduce The Content-Encoding: gzip header should be included even when the file extension already contains .gz, but it is currently missing, causing the functionality to fail.

Version information Windows, macOS, or Linux? MacOS What version of the program are you using? Version 1.2.12 (31)

Screenshots If applicable, add screenshots to help explain the issue.

image
ethanaobrien commented 3 weeks ago

Please include a screenshot of the response headers in the network tab. This shouldn't be possible

https://github.com/terreng/simple-web-server/blob/068dc2510f7d1cf6e42e85db868bfc50f81110c3/mime.js#L296

Edit: I see what you mean, @terreng do you know if it'd harm a download at all if we added the content encoding header on a normal gz file download?

terreng commented 3 weeks ago

Based on my understanding, I don't think we should add the Content-Encoding: gzip header to all files across the board, because I do think it would mess up downloading .gz files. If you try to directly download example.gz, it should just download the file as-is, but I think that adding this header would cause the browser to try and decompress it first.

That said, there seems to be a pattern of adding .gz to the end of an existing file extension. Like Build/WebGL.framework.js.gz in this case. Right now this file is getting served as application/gzip. I think it should instead be served with text/javascript and Content-Encoding: gzip.

Ethan, could you implement that? If the file ends with .gz, try removing it and checking if the remaining string still has a valid file extension. If it does, like in the case of .js.gz, then use the content-type of js and add the content-encoding header. If not, then keep the content-type as gz and don't add a content-encoding header.

So in summary:

example.gz

example.js.gz

ethanaobrien commented 3 weeks ago

I can look at doing this

tigerbalm commented 3 weeks ago
image
terreng commented 1 week ago

@ethanaobrien I totally forgot that we already have the "Serve precompressed .gz and .br files" option, but it's just off by default. I think we should turn it on by default.

That said, the existing option didn't seem to work for me. I made a file called example.js.gz, but when I tried to access example.js I just got a 404.

I think the existing option would also need to be modified to allow you to load .gz files directly if the .gz follows another file extension, like we were talking about before.

So if you have a file called example.js.gz, then loading either /example.js or /example.js.gz should work:

(Unless example.js exists by itself, in which case serve that)

But if you have a file called just example.gz, then only loading that path should work.

With the precompression option enabled, then I think it's already supposed to mostly work this way, except that currently loading example.js.gz will give content type application/gzip.

Here's the relevant part of the code:

if (this.opts.precompression) {
    let found = false;
    const ac = this.request.headers['accept-encoding'];
    if (ac.includes('gzip')) {
        let file = this.fs.getByPath(entry.fullPath+".gz");
        if (file && !file.error) {
            entry = file;
            this.setHeader('Content-Encoding', 'gzip');
            found = true;
        }
    }
    if (ac.includes('br') && !found) {
        let file = this.fs.getByPath(entry.fullPath+".br");
        if (file && !file.error) {
            this.setHeader('Content-Encoding', 'br');
            entry = file;
        }
    }
}

And also the part of the code that chooses what content-type to serve.

ethanaobrien commented 1 week ago

@terreng At the moment, It only serves a pre-compressed file if a non-compressed version is found, and the requesting request says it supports it.

Doing it if without checking for a non-compressed file can lead to differing behaviors in browsers that either have the feature disabled, or do not support it. How should we handle this issue?

terreng commented 1 week ago

In this case with the Unity export, I don't think it includes a non .gz version, which means it just doesn't work on browsers that don't support gzip. That said, I'm pretty sure all the browsers do support it.

If there's only a .gz file, then the only choice we have is to serve that with gzip encoding, and it just won't work on unsupported browsers. But that's not a problem with the web server, that's on the user. So I think it's fine if we just don't handle that issue.