Handling %3F in URI with try_files

1. Output of caddy version:

v2.6.2 h1:wKoFIxpmOJLGl3QXoo6PNbYvGW4xLEgo32GPBEjWL8o=

2. How I run Caddy:

Directly on the host, via systemd

a. System environment:

Ubuntu Focal, using the deb from https://dl.cloudsmith.io/public/caddy/stable/deb/ubuntu

b. Command:


c. Service/unit/compose file:

# caddy.service
# For using Caddy with a config file.
# Make sure the ExecStart and ExecReload commands are correct
# for your installation.
# See https://caddyserver.com/docs/install for instructions.
# WARNING: This service does not use the --resume flag, so if you
# use the API to make changes, they will be overwritten by the
# Caddyfile next time the service is restarted. If you intend to
# use Caddy's API to configure it, add the --resume flag to the
# `caddy run` command or use the caddy-api.service file instead.

After=network.target network-online.target

ExecStart=/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile
ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile --force


d. My complete Caddy config:

This is the minimum required to make the problem reproducible.

mati.ca, www.mati.ca {
        root * /home/rich/sites/mati.ca
        file_server browse {
                index index.html index.htm
        try_files {path}

3. The problem I’m having:

Background: I have files in my filesystem with ? in their names, from mirroring an old Wordpress site. I access those files via a try_files config.

Test scenario: To eliminate the rest of my config for my live site, I duplicated the problem with a tiny test scenario. I set up the config above with three files in the site root directory, named as follows. The content of each file is the same as the file’s filename, so I could tell what file caddy was returning.


Expected behavior: When I curl https://www.mati.ca/file.txt%3Fhonk, it should serve the file named file.txt?honk.

Observed behavior: When I do the abovementioned curl, it serves file.txt.

I think this is a bug in try_files, where something is double-unencoding the %3F, because if a client requests something with the ? URI-encoded, it’s specifically saying “these are not query params, this is a literal ?”. If I don’t use try_files then it does not decode the %3F.

4. Error messages and/or full log output:

Behavior with try_files {path} is the surprising behavior:

$ curl https://www.mati.ca/file.txt?honk
$ curl https://www.mati.ca/file.txt%3Fhonk

Behavior without try_files {path} is the expected behavior:

$ curl https://www.mati.ca/file.txt?honk
$ curl https://www.mati.ca/file.txt%3Fhonk

5. What I already tried:

All of the above, including the test case :slight_smile: I was going to go straight to a Github issue, but I’ve only been using Caddy for a couple days now, so I figured I should start here in case I’m using it wrong.

I also verified that nginx, which I’m replacing, returns the file with a literal ? in its name even with try_files enabled in the nginx config.

6. Links to relevant resources:


1 Like

how about try_files {path}{query} or try_files {path}%3F{query} ?

1 Like

Wouldn’t surprise me if that was a bug. It’s the same thing as a rewrite with a matcher, and probably the rewrite is doing the encode unexpectedly. IIRC this is a tricky situation since we don’t know whether the placeholder is supposed to span multiple URI components or not (like path + query string).

Want to open an issue on GitHub so we don’t lose it?

Sure thing, will do! caddy#5278

1 Like

This topic was automatically closed after 30 days. New replies are no longer allowed.