Trouble with a complex rewrite
Wilson Bilkovich
wilsonb at gmail.com
Mon Apr 2 23:55:20 MSD 2007
On 4/2/07, Igor Sysoev <is at rambler-co.ru> wrote:
> On Mon, Apr 02, 2007 at 03:15:12PM -0400, Wilson Bilkovich wrote:
>
> > On 4/2/07, Igor Sysoev <is at rambler-co.ru> 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.
More information about the nginx
mailing list