Nginx rewrites with %3F - nginx

For a site running Mediawiki, I have this config for clean URLs:
rewrite ^/wiki/([^?]*)(?:\?(.*))? /wiki/index.php?title=$1&$2 last;
This works fine except when the page title needs to have a question mark. For a URL like /wiki/Who_is_your_daddy%3F_It_is_me the correct rewritten URL is /wiki/index.php?title=Who_is_your_daddy%3F_It_is_me. However, Nginx is rewriting to /wiki/index.php?title=Who_is_your_daddy&_It_is_me.
What is the correct rewrite rule?

The query string is not part of the normalised URI that is processed by the rewrite directive's regular expression. However, the query string will be automatically appended to the rewritten URI, so you don't need to do anything to include the &action=edit part. See this document for details.
The %3F in the original request will be normalised to a ? by the time that rewrite is processing it. You will need to capture both sides of the ? to manually translate it back to %3F in the new query string.
You can use more than one rewrite statement, so that the case with and without a %3F are both handled correctly.
For example:
rewrite ^/wiki/(.*)\?(.*)$ /wiki/index.php?title=$1%3f$2 last;
rewrite ^/wiki/(.*)$ /wiki/index.php?title=$1 last;

Related

Nginx redirection based on query parameter

I want to redirect the URL to absolute URL on top of existing rule.
Suppose I have a existing rule as below
rewrite ^/xyz/(.*) /new-url redirect; this is working fine
I want a new url with a query param on top of it and that supports specific condition . I would want above URL also to work
/xyz/?infoid=color to be redirect to www.abcde.com
I tried this by adding the rule above the existing one as per order rule but didn't work.
rewrite ^/xyz/?infoid=color$ www.abcde.com redirect;
Is there any solution for this in nginx?

Is it possible to rewrite to a URL with a fragment in it in nginx?

E.g.
rewrite ^/page /#page;
I'm not sure if this would even be possible, due to the nature of fragments (never sent to the server etc). But since I'm rewriting TO one, rather than FROM one, I think it should work?
In which case how do I encode/escape that hash sign so that it doesn't start a comment..?
Thanks!
As you know, the fragment is used by the browser and is not sent to the server.
But you can use nginx to rewrite a request into a new URI containing a fragment, but it only makes sense if the new URI is sent to the browser, i.e by using an HTTP 3xx response.
The rewrite directive will generate an HTTP 3xx response when the redirect (302) or permanent (301) flag is provided (or the replacement string starts with a scheme - see this document for more).
For example:
rewrite ^/page /#page redirect;
Adding quotation marks, could help. I tried in Docker Nginx latest image (1.17.4)
rewrite ^/page "/#page" redirect;

nginx rewrite Issue, why does it just replaces one matched string?

I want to replace my url via Nginx's rewrite directive. For instance, the client side requests http://127.0.0.1/user/user_id/, and I want to let Nginx rewrite the url to http://127.0.0.1/person/person_id/.
My Nginx configuration is like this:
rewrite (.*)user(.*) $1person$2;
But I fount the Nginx changes the url to .../user/person_id/
Could someone tell me how to change the user to person via rewrite directive?
Assuming that the first instances of user and personare constant and that there is always a slash after the second item, you can try:
rewrite ^/user/user_([^/]+)/(.*)$ /person/person_$1/$2 ;
well this single case you are talking about can be solved simple:
rewrite ^/user/user_id/(.*)$ /person/person_id/$1 ;

Fix duplicate query string in nginx

I've got a strange case where my app is now for some reason appending a duplicate query string onto a URL that already has one. I don't have the access or the time to dig into the application code right now, but I do have access to Nginx configs.
What I need is a rewrite rule that will ignore the duplicate query string, ie
http://foo.com?test=bar?test=bar will redirect to http://foo.com?test=bar
Is this even possible? Thank you.
Here, add this inside your server block, before any other location or if:
if ($query_string ~ ^([^?]+)\?\1$) {
set $clean $1;
rewrite . $uri?$clean?;
}
It's quite tricky to get right, because there are more than a few obscure behaviours:
$query_string is the query string without the initial ?
the \1 in the regexp matches a second copy of the first group (...)
you need to save $1 into a new variable because rewrite will overwrite it
you need to use $uri and not $request_uri in the rewrite, because the latter contains a copy of the original query string
you need to add a trailing ? to the rewrite, otherwise the rewrite would append a copy of the original query string! (that's probably the most obscure bit of Nginx syntax, ever)
The simple form of rewrite (without the redirect flag) should be enough for most applications, plus it doesn't require an additional round-trip to the browser.
If it does not work for you, you can try using the $clean query string into the appropriate backend directive (such as fastcgi_param QUERY_STRING and such) or, as a last resort, issuing a browser redirect using the redirect rewrite flag.

Rewrite a url and rerun the server block

I'm trying to rewrite a url like the following but without sending a 301 to the client (change the url and then restart processing of the server block with the new url).
rewrite ^/a/b/$ /a/c/d permanent;
I would normally just reorder the lines but it's a really convoluted config and also really large.
permanent always means redirect, replace it with last
check the last flag in the reference page

Resources