13 messages in ru.sysoev.nginxRe: Trouble with a complex rewrite
FromSent OnAttachments
Wilson BilkovichApr 2, 2007 4:40 am 
Igor SysoevApr 2, 2007 5:25 am 
Wilson BilkovichApr 2, 2007 12:14 pm 
Igor SysoevApr 2, 2007 12:46 pm 
Wilson BilkovichApr 2, 2007 12:54 pm 
Igor SysoevApr 2, 2007 1:19 pm 
Wilson BilkovichApr 2, 2007 2:10 pm 
Igor SysoevApr 2, 2007 2:26 pm 
Wilson BilkovichApr 2, 2007 4:27 pm 
Boris BartsytsApr 10, 2007 8:07 am 
Igor SysoevApr 10, 2007 12:59 pm 
Boris BartsytsApr 11, 2007 3:42 am 
Igor SysoevApr 12, 2007 1:28 pm 
Actions with this message:
Paste this link in email or IM:
Paste this link in email or IM:
Atom feed for this thread
Paste this URL into your reader:
Subject:Re: Trouble with a complex rewriteActions...
From:Wilson Bilkovich (wils@public.gmane.org)
Date:Apr 2, 2007 12:54:57 pm
List:ru.sysoev.nginx

On 4/2/07, Igor Sysoev <is-G@public.gmane.org> wrote:

On Mon, Apr 02, 2007 at 03:15:12PM -0400, Wilson Bilkovich wrote:

On 4/2/07, Igor Sysoev <is-G@public.gmane.org> wrote:

On Mon, Apr 02, 2007 at 07:41:09AM -0400, Wilson Bilkovich wrote:

I am migrating an existing Apache 2.2.4 -> Mongrel configuration to Nginx. Everything is working fine save for one final piece.

We have a complicated rule that redirects some traffic to a partner site based on the contents of the query string. At the moment, this is still a requirement, and I can't do away with it.

The existing Apache rule is:

RewriteCond %{QUERY_STRING} message=.*(%\d+|\b)(foo|bar|baz|qux)(%\d+|\b) [NC] RewriteRule ^/api/receive http://target.example.com/horrible/url/?%{QUERY_STRING} [P,L,NC]

The nasty piece here is that "%\d+" in the regexp pattern is necessary. 'foo' should only match if it is a whole word in the query string. (%\d+|\b) allows the pattern to handle either normal word boundaries, or HTML-encoded entities like %20. For example: api/receive?message=foo%20hello should match this rule, but: api/receive?message=hellofoo should not

Is it possible to duplicate this in nginx? Thus far I have tried: 1. Making a location {} entry for api/receive, and using if ($query_string ~ pattern) 2. Using if($query_string) inside the / location block 3. Making a location entry for the regexp on its own 4. Testing with simply message=.*foo as the pattern, which makes me think the problem is more basic than the regexp pattern

None of these seem to work. I've tried both "~" and "~*" styles, though I haven't actually been able to figure out what the difference between them is.

location /api/receive { if ($args ~ "message=.*(%\d+|\b)(foo|bar|baz|qux)(%\d+|\b)") { rewrite ^ http://target.example.com/horrible/url/; } }

Thank you for the reply. That syntax will do a 302 redirect though, correct? I need to actually proxy the request to the target server.

Sorry, I missed [P,...]. You should use

location /api/receive { if ($args ~ "message=.*(%\d+|\b)(foo|bar|baz|qux)(%\d+|\b)") { rewrite ^ /horrible/url/; break;

proxy_pass http://target.example.com; } }

The "~" operator means 'does this pattern occur in the string'.. How does ~* differ from that? I've seen the two operators used in examples.

"~" means case-sensitive pattern while "~*" means case-insensitive pattern. The wiki should be fixed.

Thanks. I have updated the English wiki with this clarification.

I have two more questions about this: 1. I can use any regular expression supported by PCRE, anywhere in my nginx config, correct? 2. When I have nested locations, such as: location / { location /api/receive { break; } some_config_option on; }

Configuration options in the outer scope (location /, in this case) are always evaluated, despite the break command? In other words, break only 'breaks' from the location / rewrite loop, not from the rest of the configuration?

Thanks again for your help. --Wilson.