Forum Discussion

Steve_M__153836's avatar
Steve_M__153836
Icon for Nimbostratus rankNimbostratus
Jul 14, 2015

iRule Help - Capture URI, Modify, and Redirect

I have two sets of incoming URLs I need to pick apart and redirect based on their content. Both with the same formatting.

https://my.site.org/A/B/find-a-thing1/garbage

https://my.site.org/A/B/find-a-thing1/thing1detail/actualthing1/garbage

https://my.site.org/A/B/find-a-thing2/garbage/moregarbage/additionalgarbage

https://my.site.org/A/B/find-a-thing2/thing2detail/actualthing2/garbage

"garbage" always starts with "!ut", but could have literally anything after that including additional "/" and more content. Regardless none of it is needed.

find-a-thing1 and find-a-thing2 as well as thing1detail and thing2detail will not change in their respective paths.

actualthing1 and actualthing2 will not have any consistent behavior, specific text to key off of, or common length. I need to extract their values from the URI and use them in the redirect. I'm thinking using scan may be what I need to do, but I don't have the experience to know how to write that from scratch. I don't really understand the scan function, just read from another post and modified.

I need to now validate the part where I am extracting the information from the URI. I took at stab at it, but I think I need some assistance.

when HTTP_REQUEST {
 set URI [string tolower [HTTP::uri]]
  if { $URI contains "find-a-thing1" and $URI contains "thing1detail"}
    set actualthing1value [scan $URI {/thing1detail/%[^/]/%[^.]/!ut}]
       HTTP::redirect https://new.http.host/things1/$actualthing1value
  if { $URI contains "find-a-thing1"}
       HTTP::redirect https://new.http.host/things1
  if { $URI contains "find-a-thing2" and $URI contains "thing2detail"}
     set actualthing2value [scan $URI {/thing2detail/%[^/]/%[^.]/!ut}]
        HTTP::redirect https://new.http.host/things2/$actualthing2value
  if { $URI contains "find-a-thing2"}
     HTTP::redirect https://new.http.host/things2
    }
  • You're probably on the right track with the scan command. TCL scan takes three primary arguments: the string to evaluate, format specifier, and the arbitrary variables to "dump" scanned string values.

    So for example, let's take your second URI:

    set tmp1 "/A/B/find-a-thing1/thing1detail/actualthing1/garbage"
    

    To scan out each of the URI components into separate variables, it might look something like this:

    scan $tmp1 {/%[^/]/%[^/]/%[^/]/%[^/]/%[^/]/%[^/]} a b c d e f
    

    The "%[^/]" specifier says to take all of the characters that are not a forward slash "/" and assign those to one of the variables at the end. With 6 URI components, this dumps each into a separate variable (a-f).

  • You need someplace to store all of the values. You can also split the URI into a list and do it that way:

    set tmp1 "/A/B/find-a-thing1/thing1detail/actualthing1/garbage"
    set urilist [split $tmp1 "/"]
    log local0. [lindex $urilist 5]
    
  • This got shelved and then was resurrected for use. Below is the current form of the iRule. I'm receiving an error in the ltm log.

    err tmm[15729]: 01220001:3: TCL error: /Partition/iRule - invalid command name "6"; while executing "[scan $URI {/%[^/]/%[^/]/%[^/]/%[^/]/%[^/]/%[^/]} 1 2 3 4 5 6]";

    err tmm[15729]: 01220001:3: TCL error: /Partition/iRule - invalid command name "6"; while executing "[scan $URI {/%[^/]/%[^/]/%[^/]/%[^/]/%[^/]/%[^/]} 7 8 9 10 11 12]";

    The rule will execute only when not calling one of the variables. It seems like it is not actually setting the numbers 1-12 as a variable. I'm not sure how to take this further and resolve it. Any help is much appreciated.

    when HTTP_REQUEST {
    set URI [string tolower [HTTP::uri]]
     if { $URI equals "/" or $URI equals ""} {
      HTTP::respond 301 Location "https://My.site.org/mysite"
     } elseif { $URI contains "find-a-thing1" and $URI contains "thing1detail" } {
      [scan $URI {/%[^/]/%[^/]/%[^/]/%[^/]/%[^/]/%[^/]} 1 2 3 4 5 6]
      HTTP::respond 301 Location "https://my.site.org/things1/$5"
      log local0. "Legacy Find Thing1 value is $5"
     } elseif { $URI contains "find-a-thing1"} {
      HTTP::respond 301 Location "https://my.site.org/things1"
     } elseif { $URI contains "find-a-thing2" and $URI contains "thing2detail"} {
      [scan $URI {/%[^/]/%[^/]/%[^/]/%[^/]/%[^/]/%[^/]} 7 8 9 10 11 12]
      HTTP::respond 301 Location "https://my.site.org/things2/$11/$12"
      log local0. "Legacy Find Thing2 values are $11 and $12"
     } elseif { $URI contains "find-a-thing2"} {
      HTTP::respond 301 Location "https://my.site.org/things2"
     }
    }
    
    • Steve_M__153836's avatar
      Steve_M__153836
      Icon for Nimbostratus rankNimbostratus
      Forgot to mention that error in the LTM log corresponds with RST of the connection. Also it happens if the variable attempting to be being called is one other than 6. Further troubleshooting indicates that the the error isn't referencing the varialbe, but the position among each section of the URI that is being scanned via the scan command. I'm at a loss on how to get more diagnostic info out of this to help find a resolution.
  • Devcentral ate and destroyed my previous account so posting under this account. This is a final working version. Note the asterisks in the lines with scan commands. They can be hard to pick out of there. This article helped greatly in getting this to work: Revisiting the Scan Command.

    when HTTP_REQUEST {
    set URI [string tolower [HTTP::uri]]
     if { $URI equals "/" or $URI equals ""} {
       HTTP::respond 301 Location "https://My.site.org/mysite"
     } elseif { $URI contains "find-a-thing1" and $URI contains "thing1detail" } {
           scan $URI {/%*[^/]/%*[^/]/%*[^/]/%*[^/]/%[^/]/%*[^/]/} a
       HTTP::respond 301 Location "https://diff.site.org/thing1/$a"
    } elseif { $URI contains "find-a-thing"} {
       HTTP::respond 301 Location "https://diff.site.org/thing1"
     } elseif { $URI contains "find-a-thing2" and $URI contains "thing2detail"} {
         scan $URI {/%*[^/]/%*[^/]/%*[^/]/%*[^/]/%[^/]/%[^/]/} b c
       HTTP::respond 301 Location "https://diff.site.org/thing2/$b/$c"
     } elseif { $URI contains "find-a-thing2"} {
       HTTP::respond 301 Location "https://diff.site.org/thing2"
    }
    }