For more information regarding the security incident at F5, the actions we are taking to address it, and our ongoing efforts to protect our customers, click here.

Forum Discussion

Anonymous's avatar
Anonymous
Feb 01, 2016

check for trailing slash in /foo and /foo/bar

Hi,

I have a case where I want to add a trailing slash if someone hit /foo or /foo/bar. The rules below works but I wonder if it can be optimized:

 

when HTTP_REQUEST {    
   add trailing slash for /foo
   if {[string first "/" [HTTP::uri] 1] equals "-1" } {
     HTTP::redirect "${protocol}://[HTTP::host][HTTP::uri]/"
   }

   add trailing slash for /foo/bar
   if {[string first "/" [string range [HTTP::uri] [string first "/" [HTTP::uri] 1] end] 1] equals     "-1"} {
     HTTP::redirect "${protocol}://[HTTP::host][HTTP::uri]/"
   }

   add trailing slash for /foo and /foo/bar
  if {([string first "/" [HTTP::uri] 1] equals "-1") or ([string first "/" [string range    [HTTP::uri] [string first "/" [HTTP::uri] 1] end] 1] equals "-1")} {
    HTTP::redirect "${protocol}://[HTTP::host][HTTP::uri]/"
  }
}

 

Any ideas?

4 Replies

  • Anonymous's avatar
    Anonymous

    One thing which just came to my mind is that I need to exclude dot, for example index.html:

     

      if {!([HTTP::uri] contains ".")} {
        if {([string first "/" [HTTP::uri] 1] equals "-1") or ([string first "/" [string range [HTTP::uri] [string first "/" [HTTP::uri] 1] end] 1] equals "-1")} {
          HTTP::redirect "${protocol}://[HTTP::host][HTTP::uri]/"
        }
      }
    

     

    Which actually adds even one more check. My concern is if it will slow down the response (even a ms) from the balancer when doing a lot of sub checks.

  • This is a simple way of doing what you want:

     

    when HTTP_REQUEST {
        if {not ([HTTP::path] ends_with "/")}{
            HTTP::respond 301 noserver Location "${protocol}:://[HTTP::host][HTTP::path]"
        }
    }
    

     

    One thing to mention though your original iRule used HTTP::uri, that will contain query parameters if they exist which would make your redirect look like this, http://some.domain.com/originalUri?parameter1=xyz/.

    If you want to account for query parameters you could do this:

     

    when HTTP_REQUEST {
        if {not ([HTTP::path] ends_with "/")}{
            if {[HTTP::query] ne ""}{
                set myuri "[HTTP::path]/?[HTTP::query]"
            }
            else {
                set myuri "[HTTP::path]/"
            }
            HTTP::respond 301 noserver Location "${protocol}:://[HTTP::host]$myuri"
        }
    }
    

     

    • Brad_Parker's avatar
      Brad_Parker
      Icon for Cirrus rankCirrus
      As Kai mentions below, you will need additional logic to account for files that wouldn't want trailing slashes.
  • Hi Vova V,

    I'm using [URI::basename] command to parse the last element of a given HTTP path. But keep in mind that some WebServices (e.g. ".asmx/method" ".json/method) don't like trailing slashes. So you may want to setup some exclusions...

    This is the code I'm using for some SharePoint Sites...

     

    when HTTP_REQUEST {
        if { [set uri_base [URI::basename [HTTP::path]]] eq "" } then {
             if { $debug } { log -noname local0. "The URI::basename is a /Folder/." }
        } elseif { $uri_base contains "." } then {
             if { $debug } { log -noname local0. "The URI::basename is a *.* File." }
        } else {
             if { $debug } { log -noname local0. "The URI::basename is a /Folder (without trailing slash)." }
            switch -glob -- [string tolower [HTTP::path]] "*.asmx*" - "*.json*" - "/_*" - "*/_layout*" - "*/_vti_bin*" {
                 if { $debug } { log -noname local0. "The HTTP::path is exempted..." } 
            } default {
                 if { $debug } { log -noname local0. "Adding a trailing slash to the URI::basename." }
                HTTP::path "[HTTP::path]/"
            }
        }
    }
    

     

    Cheers, Kai