Forum Discussion

Former Member's avatar
Former Member
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?

  • Former Member's avatar
    Former Member

    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