Forum Discussion

Tony_Kitzky_936's avatar
Tony_Kitzky_936
Icon for Nimbostratus rankNimbostratus
Aug 24, 2013

How best to accomplish HTTP redirection for specific URLs?

I am trying to create a site where some URLs are not redirected to HTTPS but all other URLs do get redirected. I do not know what is the best method to accomplish this. I want the ability to easily add URLs that should not be redirected. Should I be using iRule for this? Or is an html rewrite profile better?

 

For example... http://www.drspanky.com/slowcomputer/is/slow/index.html --> not redirected http://www.drspanky.com/notso/fastcomputer/is/notfast.html ---> not redirected http://www.drspanky.com/slownotebook/is/slow/nossl/index.html --> not redirected http://www.drspanky.com/slow12345/nossl/is/slow/myhome.svc --> not redirected All other requests to www.drspanky.com are redirected to https.

 

I am fairly new with working on the F5 Big IP LTM appliances. I have been able to create simple LTM policies for http and https web sites. For most all of the https sites I have, I am simply using the F5 ceritified iRule to redirect all http requests to https.

 

I have a series of sites that have a number of URLs that cannot be redirected. I am porting this site from a Cisco ACE 4710 appliance where I have http url class-maps defined for the URLs not to be redirected.

 

I am using the latest and greatest tmos release on new hardware. thnx in advance for any suggestions. I want to learn so pointing me in the right direction would be very much appreciated.

 

8 Replies

  • I'd go with the data group method. It's by far the easiest to manage and requires no subsequent changes to the iRule. Example.

    Data group - string-based (ex. my_uri_dg)

    "/uri1"
    "/uri2"
    "/uri3"
    "/uri4"
    

    iRule:

    when HTTP_REQUEST {
       if { not ( [class match [string tolower [HTTP::uri]] starts_with my_uri_dg] ) } {
          HTTP::redirect "https://[HTTP::host][HTTP::uri]"
       }
    }
    

    So as long as the requested URI pattern (starts_with) is in the data group, the request will pass through. Otherwise, for everything else, it gets redirected. It doesn't appear that the host name changes, so you shouldn't have to evaluate that. Also note that we're just looking for data the group key, so the corresponding values can be empty.

  • Can you use regex in these data groups? I will want to match a common 3 digit string in each URI but the digits will change over time. Also I would want to ignore case on these URIs.

    what about this?

    e.g.

    root@(ve11a)(cfg-sync Changes Pending)(Active)(/Common)(tmos) list ltm virtual bar
    ltm virtual bar {
        destination 172.28.20.111:80
        ip-protocol tcp
        mask 255.255.255.255
        pool foo
        profiles {
            http { }
            tcp { }
        }
        rules {
            myrule
        }
        source 0.0.0.0/0
        source-address-translation {
            type automap
        }
        vs-index 23
    }
    root@(ve11a)(cfg-sync Changes Pending)(Active)(/Common)(tmos) list ltm rule myrule
    ltm rule myrule {
        when HTTP_REQUEST {
      set path [string tolower [HTTP::path]]
      switch -glob $path {
        "/slowcomputer/is/slow/index.html" -
        "/notso/fastcomputer/is/notfast.html" -
        "slownotebook/is/slow/nossl/index.html" -
        "/slow[0-9][0-9][0-9][0-9][0-9]/nossl/is/slow/myhome.svc" {
           do nothing
        }
        default {
          HTTP::redirect "https://[HTTP::host][HTTP::uri]"
        }
      }
    }
    }
    
    [root@ve11a:Active:Changes Pending] config  curl -I http://172.28.20.111/slowcomputer/is/slow/index.html
    HTTP/1.1 404 Not Found
    Date: Sun, 25 Aug 2013 01:28:50 GMT
    Server: Apache/2.2.3 (CentOS)
    Content-Type: text/html; charset=iso-8859-1
    
    [root@ve11a:Active:Changes Pending] config  curl -I http://172.28.20.111/SLOW54321/nossl/is/slow/myhome.svc
    HTTP/1.1 404 Not Found
    Date: Sun, 25 Aug 2013 01:31:45 GMT
    Server: Apache/2.2.3 (CentOS)
    Content-Type: text/html; charset=iso-8859-1
    
    [root@ve11a:Active:Changes Pending] config  curl -I http://172.28.20.111/somethingelse
    HTTP/1.0 302 Found
    Location: https://172.28.20.111/somethingelse
    Server: BigIP
    Connection: Keep-Alive
    Content-Length: 0
    
    • Tony_Kitzky_936's avatar
      Tony_Kitzky_936
      Icon for Nimbostratus rankNimbostratus
      Ahh... I think I followed what you did. Thnx. I can use this as a sample to learn from. I like the method of using a data group for the individual URIs. I need to dig into iRule fundamentals, I guess.
    • nitass_89166's avatar
      nitass_89166
      Icon for Noctilucent rankNoctilucent
      i understand we cannot use regex in data group. so, we may separate those data (from data group) and check it using command such as switch glob, string match, scan, etc.
  • Can you use regex in these data groups? I will want to match a common 3 digit string in each URI but the digits will change over time. Also I would want to ignore case on these URIs.

    what about this?

    e.g.

    root@(ve11a)(cfg-sync Changes Pending)(Active)(/Common)(tmos) list ltm virtual bar
    ltm virtual bar {
        destination 172.28.20.111:80
        ip-protocol tcp
        mask 255.255.255.255
        pool foo
        profiles {
            http { }
            tcp { }
        }
        rules {
            myrule
        }
        source 0.0.0.0/0
        source-address-translation {
            type automap
        }
        vs-index 23
    }
    root@(ve11a)(cfg-sync Changes Pending)(Active)(/Common)(tmos) list ltm rule myrule
    ltm rule myrule {
        when HTTP_REQUEST {
      set path [string tolower [HTTP::path]]
      switch -glob $path {
        "/slowcomputer/is/slow/index.html" -
        "/notso/fastcomputer/is/notfast.html" -
        "slownotebook/is/slow/nossl/index.html" -
        "/slow[0-9][0-9][0-9][0-9][0-9]/nossl/is/slow/myhome.svc" {
           do nothing
        }
        default {
          HTTP::redirect "https://[HTTP::host][HTTP::uri]"
        }
      }
    }
    }
    
    [root@ve11a:Active:Changes Pending] config  curl -I http://172.28.20.111/slowcomputer/is/slow/index.html
    HTTP/1.1 404 Not Found
    Date: Sun, 25 Aug 2013 01:28:50 GMT
    Server: Apache/2.2.3 (CentOS)
    Content-Type: text/html; charset=iso-8859-1
    
    [root@ve11a:Active:Changes Pending] config  curl -I http://172.28.20.111/SLOW54321/nossl/is/slow/myhome.svc
    HTTP/1.1 404 Not Found
    Date: Sun, 25 Aug 2013 01:31:45 GMT
    Server: Apache/2.2.3 (CentOS)
    Content-Type: text/html; charset=iso-8859-1
    
    [root@ve11a:Active:Changes Pending] config  curl -I http://172.28.20.111/somethingelse
    HTTP/1.0 302 Found
    Location: https://172.28.20.111/somethingelse
    Server: BigIP
    Connection: Keep-Alive
    Content-Length: 0
    
    • Tony_Kitzky_936's avatar
      Tony_Kitzky_936
      Icon for Nimbostratus rankNimbostratus
      Ahh... I think I followed what you did. Thnx. I can use this as a sample to learn from. I like the method of using a data group for the individual URIs. I need to dig into iRule fundamentals, I guess.
    • nitass's avatar
      nitass
      Icon for Employee rankEmployee
      i understand we cannot use regex in data group. so, we may separate those data (from data group) and check it using command such as switch glob, string match, scan, etc.
  • Okay, this is a little hacky, but there is technically a way to achieve "regex-like" behavior with data groups. I'll start with the data group.

    /slow1234/nossl/is/
    /fast1234/nossl/is/
    ... 
    

    The digits in the URI aren't important and I'm purposely limiting the URIs to three-levels deep, but yours should be limited to the lowest common denominator for your matched URIs. Now the iRule:

    when HTTP_REQUEST {
         limit the request URI to three levels
         Example: /slow1234/nossl/is/slow/ becomes /slow1234/nossl/is/
        set uri [string range [HTTP::uri] 0 [string first "/" [HTTP::uri] [expr [string first "/" [HTTP::uri] [expr [string first "/" [HTTP::uri] 1] +1]]+1]]]
    
         Turn the URI into a glob pattern based on numeric values
         Example: /slow1234/nossl/is/slow becomes /slow*/nossl/is/slow
        regsub -all -nocase {\d+} $uri "*" globuri
        append globuri "*"
    
         Search for the glob pattern in the data group
        if { not ( [lindex [class get -nocase glob_datagrouop $globuri] 1] eq "" ) } {
            log local0. "no match"
             perform redirects
        } 
    }
    

    The idea here is that I'm using the [class get ] command with a glob pattern - not truly a regex itself, but the regsub command above makes sure that only digits are affected. So to illustrate what's happening:

    1. The URI is first truncated to three levels. That'll make more sense in a moment.

    2. The regsub command replaces any instance of a sequential digits in the URI with a glob "*" character, and then an additional "*" is appended to the end.

    3. This pattern is fed into the [class get ] command, which produces a list. If the pattern matches a single data group entry, then it's flagged as a match. Otherwise all or multiple records are returned and it's not a match. Of course you want to make sure that your URI patterns cannot produce multiple results in the search.

    The reason for limiting the data group URI is that you can't really do a "starts_with" expression like you can with other class commands. So, for example, if the data group URI was something like "/slow1234/nossl/is/" and the request URI was "/slow3454/nossl/is/slow/test/foo/bar", the glob pattern would become "/slow*/nossl/is/slow/test/foo/bar" - and this wouldn't match the data group.