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