nginx rewrite to replace single character

2019-07-29 18:41发布

问题:

I have a tool that downloads a bunch of tarballs and patches that I'm in the process of mirroring to a local NGINX server to speed up the download process and give us tighter control over what's being used. For the tool to work correctly, the local filename has to match the remote filename (path does not matter), but because of what the tool considers a filename, I've run into a snag with ?.

An example would be downloading this remote patch:

https://gitweb.gentoo.org/repo/gentoo.git/plain/dev-libs/openssl/files/openssl-1.0.2d-parallel-build.patch?id=c8abcbe8de5d3b6cdd68c162f398c011ff6e2d9d

The filename, as far as the tool is concerned, is openssl-1.0.2d-parallel-build.patch?id=c8abcbe8de5d3b6cdd68c162f398c011ff6e2d9d which has a nice little ? in the middle and the local mirror has to be:

https://server.local/mirror/openssl-1.0.2d-parallel-build.patch?id=c8abcbe8de5d3b6cdd68c162f398c011ff6e2d9d

The tool uses wget to download the file but does not replace the '?' with '%3f' so the NGINX server returns a 404. If you manually replace the '?' with '%3f' then the wget works normally.

I would be fine with the NGINX server never treating the ? as a query string but if that's not a possibility, I need a way to rewrite the uri so that the file downloads properly. I assumed it would be something like this:

rewrite ^(.*)\?(.*)$ $1%3f$2 permanent;

but that doesn't resolve my issue. The mirror folder is defined as an alias in /etc/nginx/apps/mirror.conf as follows, if that matters:

location /mirror {
    autoindex on;
    alias /var/lib/dl-cache;
}

Could use a little help bridging the gap.

回答1:

The location and rewrite directives use a normalised URI which has already separated out the ? and the query string.

The variable $request_uri contains the unmodified URI and can be interrogated using an if...return statement:

if ($request_uri ~ ^(/.*)[?](.*)$) { 
    return 301 $1%3f$2;
}

You may want to place this inside a location block to limit the scope. See this caution on the use of if