Forum Discussion

1000blocks's avatar
1000blocks
Icon for Nimbostratus rankNimbostratus
Mar 07, 2017

Applying lowercase iRule to HTTPS virtual server?

Hi,

 

For SEO reasons, I need to apply force all HTTP requests to my site to be lowercase.

 

The Big-IP configuration for the site is a HTTP virtual server and a HTTPS virtual server (with a client SSL profile).

 

I currently have this iRule below on the HTTP virtual server and this works perfectly.

 

when HTTP_REQUEST {

 

if { [string tolower [HTTP::host]] eq "mysitename.com" } then {

 

HTTP::respond 301 noserver Location "https://www.mysitename.com[string tolower [HTTP::uri]]"

 

} else {

 

HTTP::respond 301 noserver Location "https://[getfield [HTTP::host] ":" 1][string tolower [HTTP::uri]]"

 

}

 

}

 

 

This iRule correctly forces HTTP traffic to HTTPS with a 301 response code and forces the URI's to lowercase.

 

E.g. http://www.sitename.com/WHATEVER gets converted to https://www.sitename.com/whatever

 

So this is all good.

 

However my problem is that I can't work out how to do the same lowercase rule for the HTTPS virtual server connections.

 

I currently have this iRule below applied to the HTTPS virtual server and nothing is being converted to lowercase.

 

when HTTP_REQUEST {

 

if { [string tolower [HTTP::host]] starts_with "mysitename.com" } {

 

HTTP::respond 301 noserver Location "https://www.mysitename.com[string tolower [HTTP::uri]]"

 

}

 

}

 

 

E.g. https://www.sitename.com/WHATEVER remains as https://www.sitename.com/WHATEVER

 

Is there a way to force lowercase to the HTTPS virtual server as well?

 

Any advice would be appreciated.

 

Thanks in advance!

 

6 Replies

  • Do you have a clientside SSL profile enabled?

     

    If the F5 isn't doing SSL offload or SSL bridging you won't be able to run any HTTP irules to manipulate the data. You will need a HTTP profile as well, but you probably won't be able to attach the iRule without that.

     

  • Hi,

    To redirect only when string is not lower case, you can use the condition

     

    if {[ set uri [string tolower [HTTP::uri]]] ne [HTTP::uri]} {    
        HTTP::respond 301 noserver Location $uri        
    }
    

     

  • here is another Irule to do this

    when HTTP_REQUEST {
    # pool_group1 is the pool name for this virtual server
    set Vuri [ string tolower [HTTP::uri]]
    set Vheader [string tolower [HTTP::host]]
    set Poolmember1 [active_members pool_group1] 
    set Default_site www.mysitename.com
    
    switch $Vheader {
    
        www.mysitename.com {
                            if { [HTTP::uri] ne $Vuri  } {
                            [HTTP::uri] $Vuri
                            }
                            else { pool pool_group1 }
                        }
        default { HTTP::redirect "https://$Default_site$Vuri"}
    }
    }
    

     

  • Ok, looks like I have a working solution now.

    Thanks Stanislas - it's basically your rule blended into with my existing redirection rule.

    So the lowercasing happens as planned, but also every HTTP/HTTPS/WWW/non-WWW combination still gets detected and 301 redirected too.

    Just tested all 10 possible combinations for a page and all good so far.

    1. mysitename.com/page (without HTTP/HTTPS/WWW) --> 301 redirect --> https://www.mysitename.com/page
    2. mysitename.com/PAGE (without HTTP/HTTPS/WWW) --> 301 redirect --> https://www.mysitename.com/page
    3. http://mysitename.com/page --> 301 redirect --> https://www.mysitename.com/page
    4. http://mysitename.com/PAGE --> 301 redirect --> https://www.mysitename.com/page
    5. http://www.mysitename.com/page --> 301 redirect --> https://www.mysitename.com/page
    6. http://www.mysitename.com/PAGE --> 301 redirect --> https://www.mysitename.com/page
    7. https://mysitename.com/page --> 301 redirect --> https://www.mysitename.com/page
    8. https://mysitename.com/PAGE --> 301 redirect --> https://www.mysitename.com/page
    9. https://www.mysitename.com/page --> HTTP/200 --> https://www.mysitename.com/page
    10. https://www.mysitename.com/PAGE --> 301 redirect --> https://www.mysitename.com/page

    Working iRule 1

     

    when HTTP_REQUEST {
       if {[string tolower [HTTP::host]] starts_with "www.mysitename.com" && [string match {*[A-Z]*} [HTTP::uri]]}{
          HTTP::respond 301 noserver Location "https://www.mysitename.com[string tolower [HTTP::uri]]"
       } elseif
       {[string tolower [HTTP::host]] starts_with "mysitename.com" && [string match {*[A-Z]*} [HTTP::uri]]}{
          HTTP::respond 301 noserver Location "https://www.mysitename.com[string tolower [HTTP::uri]]"
       } elseif
        {[string tolower [HTTP::host]] starts_with "mysitename.com" } {
         HTTP::respond 301 noserver Location "https://www.mysitename.com[string tolower [HTTP::uri]]"
       }
    }
    

     

    I'm going to continue to test, but looks good so far.

    If anyone can see any ways that I can optimize this rule and trim some fat off it, please let me know.

    Thanks for everyone's input on this post... much appreciated.

     

  • Hi 1000blocks,

    you may take a look to the two iRules below. Both iRules are using a very fast code path to identify the "good" requests (should be >90% of the total request).

    In addition both iRules are not [string tolower] the entire [HTTP::uri] string, since this approach may break certain applications. Both iRules will therefor [string tolower] only the [HTTP::host] and/or [HTTP::path] information, while keeping possible [HTTP::query] information in the original case.

    iRule1: If is the only sitename served by the virtual server.

     

    when HTTP_REQUEST {
        if { [string tolower "[HTTP::host][HTTP::path]"] equals "www.mysitename.com[HTTP::path]" } then { 
             Allow the request to pass. Should be >90% of the requests. 
            return
        }
         Wrong host or mixed case URL requested. 
        if { [HTTP::query] ne "" } then {
            HTTP::respond 301 noserver Location "https://www.mysitename.com[string tolower [HTTP::path]]?[HTTP::query]"
        } else {
            HTTP::respond 301 noserver Location "https://www.mysitename.com[string tolower [HTTP::path]]"
        }
    }
    

     

    iRule2: If multiple sitenames are served by the virtual server.

     

    when HTTP_REQUEST {
        switch -glob -- [string tolower [HTTP::host]] {
            "www.mysitename.com" {
                if { [string tolower [HTTP::path]] equals [HTTP::path] } then {
                     Allow the request to pass... 
                } else {
                    if { [HTTP::query] ne "" } then {
                        HTTP::respond 301 noserver Location "https://www.mysitename.com[string tolower [HTTP::path]]?[HTTP::query]"
                    } else {
                        HTTP::respond 301 noserver Location "https://www.mysitename.com[string tolower [HTTP::path]]"
                    }
                }
            }
            "*mysitename.com*" {
                if { [HTTP::query] ne "" } then {
                    HTTP::respond 301 noserver Location "https://www.mysitename.com[string tolower [HTTP::path]]?[HTTP::query]"
                } else {
                    HTTP::respond 301 noserver Location "https://www.mysitename.com[string tolower [HTTP::path]]"
                }
            }
            "www.mysitename2.com" {
                if { [string tolower [HTTP::path]] equals [HTTP::path] } then {
                     Allow the request to pass... 
                } else {
                    if { [HTTP::query] ne "" } then {
                        HTTP::respond 301 noserver Location "https://www.mysitename2.com[string tolower [HTTP::path]]?[HTTP::query]"
                    } else {
                        HTTP::respond 301 noserver Location "https://www.mysitename2.com[string tolower [HTTP::path]]"
                    }
                }
            }
            "*mysitename2.com*" {
                if { [HTTP::query] ne "" } then {
                    HTTP::respond 301 noserver Location "https://www.mysitename2.com[string tolower [HTTP::path]]?[HTTP::query]"
                } else {
                    HTTP::respond 301 noserver Location "https://www.mysitename2.com[string tolower [HTTP::path]]"
                }
            }
            default {
                 Further/Unknown HOST-names...
            }
        }
    }
    

     

    Cheers, Kai

  • Hi,

    can you try this irule:

     

    when HTTP_REQUEST {
         Manage HTTP / HTTPS and host values
        switch -glob -- [string tolower [HTTP::host]] {
            "mysitename.com" -
            "mysitename2.com" {
                set RedirLocation "https://www.[string tolower [HTTP::host]]"
            }
            "www.mysitename.com" -
            "www.mysitename2.com" {
                if {[TCP::local_port] equals 80} {
                    set RedirLocation "https://[string tolower [HTTP::host]]"
                } else {
                    set RedirLocation ""
                }
            }
            default {
                set RedirLocation ""
            }
        }
         Manage Path values
        if {[ set path [string tolower [HTTP::path]]] ne [HTTP::path]} {
             Convert path to lowercase to be used in redirect
            HTTP::path $path
            append RedirLocation [HTTP::uri]
        } else {
            append RedirLocation [HTTP::uri]
        }
         redirect if Host, protocol or path require redirect
        if {$RedirLocation ne [HTTP::uri]} {
            HTTP::respond 301 noserver Location $RedirLocation
        }
    }
    

     

    this irule check port, hostname and path values to create a variable RedirLocation with redirect URL (relative if host and scheme are unchanged, absolute else)