Forum Discussion

Richard_Milner-'s avatar
Richard_Milner-
Icon for Nimbostratus rankNimbostratus
May 08, 2012

mod_rewrite to iRule conversion question from a newcomer

Hi Folks,

 

 

 

I'm fairly new to the BIGIP devices, though I've used competitors products before so I'm not starting from scratch. I have a mod_rewrite rule that I'm trying to migrate from our Apache servers onto the BIGIPs, this is one of many but I'm having particular difficulty with this one.

 

 

 

My main issue seems to be a lack of understanding on how to handle negative matches in condition statements when it's not a simple x != y statement.

 

 

 

The mod_rewrite rule is as follows:

 

 

 

RewriteCond %{REQUEST_URI} !\..*$

 

RewriteCond %{REQUEST_URI} !^/$

 

RewriteCond %{REQUEST_URI} !^/server-status$

 

RewriteRule ^/(.*) /redirect.jsp?code=$1 [NE,L,R=301]

 

 

 

 

So if the URI is not ending with .* or / (or a request to /server-status) then pass the URI to /redirect.jsp as a parameter.

 

 

 

I've been trying to avoid using matches_regex so have been focusing on ends_with or equals for performance reasons, but I've been falling at the first hurdle...

 

 

 

when HTTP_REQUEST {

 

if { not [ [HTTP::uri] ends_with ".*" ] } {

 

log local0. "url didn't match .*"

 

}

 

}

 

 

 

 

I'm guessing I will want a switch in here when I get it working once, but how do I get it to *not* match ends_with rather than match it?

 

 

 

I get the following thrown:

 

 

 

invalid command name "/home.jsp" while executing "[HTTP::uri] ends_with ".*" "

 

 

 

Thanks in advance for any help.

 

Richard.

 

  • You're looking for parens there instead of square brackets. Like this:

    when HTTP_REQUEST {
     if { not ( [HTTP::uri] ends_with ".*"  ) } {
      log local0. "url didn't match .*"
     }
    } 
     

    The iRules interpreter is attempting to execute the URI as a command because that's what it expects after a square bracket - that's why it fails. Parenthesis are how "order" is specified in iRules, curly-braces are how conditionals are separated, and square brackets identify TCL commands to execute.

    You've got a little more work to do on your logic, but you're on the right track. Let me know if you need some additional help to get there.
  • That's great, thank you. So I've gotten a bit further, but have a couple of further issues:

     

     

     

    when HTTP_REQUEST {

     

    if { !([HTTP::uri] equals "/") or !([HTTP::uri] ends_with ".*") or !([HTTP::uri] equals "/server-status") } {

     

    HTTP::uri [string trimleft [HTTP::uri] /]

     

    log local0. "rule has fired, uri set to [HTTP::uri]"

     

    HTTP::respond 301 Location "/redirect.jsp?code=[HTTP::uri]"

     

    }

     

    }

     

     

    I can see that the rule has fired when it shouldn't have (I think!)

     

     

    Rule vanityrewrites : rule has fired, uri set to /assets/images/buttons/english/btn_signup_off.jpg

     

     

    Surely the statement !([HTTP::uri] ends_with ".*") should have excluded any requests that end with a . followed by a number of characters? Do I need to regex this to something like \.[A-Za-z0-9]{3,4}?

     

     

    All I really want is "does the URI end in a file name without any parameters"

     

     

    THanks,

     

  • The ends_with operator does an exact match (without support for wildcards). If you want to check with a request with no query string, you can use [HTTP::query] eq "". Or if you want to check if the requested path has a file type you can use [URI::basename [HTTP::uri]] contains ".".

     

     

    I'd also check if the [HTTP::uri] starts_with "/server-status" to prevent someone from bypassing your blacklist by adding a query string to the URI.

     

     

    Aaron
  • I think this may work, if I'm understanding your use case well enough. If not, well, tweaking is how one learns! 😆

     

     

    when HTTP_REQUEST {
    switch -regexp -- [string tolower [HTTP::uri]] {
    "^/$" -
    "^/server-status$" -
    "^.*\.[a-z0-9]{3,4}$" {
    return
    }
    default {
    set redirect_uri [string range [HTTP::uri] 1 end]
    HTTP::respond 301 Location "/redirect.jsp?code=$redirect_uri" 
    }
    }
    } 
  • Many thanks for the responses guys, I will test this tomorrow when I get back into the office.
  • This is all working great now, the final rule is:

     

     

     

    when HTTP_REQUEST {

     

    if { !([HTTP::uri] equals "/") and !([HTTP::uri] contains ".") and !([HTTP::uri] starts_with "/server-status") } {

     

    set redirect_uri [string range [HTTP::uri] 1 end]

     

    HTTP::respond 301 Location "/redirect.jsp?code=$redirect_uri"

     

    }

     

    }

     

     

     

    Many thanks for the assistance folks.