Forum Discussion
Flexible host + uri redirector with data-groups
Hi!
We have an irule that I've been trying to port over from v9. In v9 it was simple... I had 2 classes, a keep_uri and a nokeep_uri class, each in the format:
hostheader1.example.com /someuri1 http://destination1.example.com/otheruri1 301
hostheader2.foobar.com /someuri2 http://destination2.example.com/otheruri2 301
hostheader3.foobaz.com /someuri3 http://destination3.example.com/otheruri3 302
etc...
From there I could easily loop looking for a [HTTP:host] match and then loop looking for a [HTTP::uri] starts_with [getfield $row " " 2] in the "keep_uri" case or in the nokeep_uri, ([string tolower [HTTP::uri]] equals [getfield $row " " 2]) or ([string tolower [HTTP::uri]] starts_with "[getfield $row " " 2]/"). In v10/v11, the data-groups have been moved to key-value pairs, which I understand is probably faster and easier to search, but feels less flexible.
Here is what I've come up with:
ltm rule redirect_by_host_and_uri {
when HTTP_REQUEST {
get rid of any port information in the host header + set the url variable
set url [substr [string tolower [HTTP::host]] 0 ':' ][HTTP::uri]
log local0. "Saved into url variable: $url"
if { [class match $url starts_with redirect_301_keep] } {
HTTP::respond 301 Location [class match -value -- $url starts_with redirect_301_keep][HTTP::uri]
log local0. "Matched $url in redirect_301_keep, redirecting to [class match -value -- $url starts_with redirect_301_keep][HTTP::uri]"
} elseif { [class match $url equals redirect_301_nokeep] }{
HTTP::respond 301 Location [class match -value -- $url equals redirect_301_nokeep]
log local0. "Matched $url in redirect_301_nokeep, redirecting to [class match -value -- $url equals redirect_301_nokeep]"
} elseif { [class match $url equals redirect_302_nokeep] }{
HTTP::redirect [class match -value -- $url equals redirect_302_nokeep]
log local0. "Matched $url in redirect_302_nokeep, redirecting to [class match -value -- $url equals redirect_302_nokeep]"
}
set cn redirect_301_nokeep
set id [class startsearch $cn]
while { [class anymore $cn $id] } {
set n [class nextelement $cn $id]
set u [lindex $n 0]
set r [lindex $n 1]
if { ($url starts_with "$u/") }{
log local0. "Matched url: $url with element [class nextelement -name $cn $id]"
HTTP::respond 301 Location $r
break
}
}
class donesearch $cn $id
set cn redirect_302_nokeep
set id [class startsearch $cn]
while { [class anymore $cn $id] } {
set n [class nextelement $cn $id]
set u [lindex $n 0]
set r [lindex $n 1]
if { ($url starts_with "$u/") }{
log local0. "Matched url: $url with element [class nextelement -name $cn $id]"
HTTP::redirect $r
break
}
}
class donesearch $cn $id
}
}
ltm data-group internal redirect_301_keep {
description "A list of host/uri pairs to redirect with 301 and keep the uri intact."
records {
foobar.example.com/foo/bar {
}
}
type string
}
ltm data-group internal redirect_301_nokeep {
description "A list of hosts/uris to match and 301 redirect without keeping the URI"
records {
foobar.example.com/baz {
}
}
type string
}
ltm data-group internal redirect_302_nokeep {
description "A list of host/uris to match and 302 redirect"
records {
foobar.example.com/302me {
data http://www.example.com/something
}
}
type string
}
This actually seems to work if I have more than 1 entry in the classes, but when I have one entry (as shown) I get these errors:
Feb 19 07:56:18 tmm err tmm[8448]: 01220001:3: TCL error: /Common/redirect_by_host_and_uri - Class iterator has no more elements (line 37) invoked from within "class nextelement -name $cn $id"
Feb 19 07:57:56 tmm2 err tmm2[8450]: 01220001:3: TCL error: /Common/redirect_by_host_and_uri - Class iterator has no more elements (line 37) invoked from within "class nextelement -name $cn $id"
I think I understand *why* I get these errors, but I don't understand how to prevent it. Is there a way to act on the *current* element instead of nextelement? Is there a better way to do this?
Thanks!
- hoolio
Cirrostratus
Hi FishNiX, - FishNiX_29746
Nimbostratus
Thanks Aaron - - FishNiX_29746
Nimbostratus
BTW - Is the only way to use the [class startsearch $cn], [class anymore $cn $id], class donesearch $cn $id and get the current element, to use a counter? Something like this...set cn redirect_302_nokeep set id [class startsearch $cn] set i 0 while { [class anymore $cn $id] } { set n [class element $i $cn] set u [lindex $n 0] set r [lindex $n 1] Do some stuff with the CURRENT values set i [expr {$i + 1}] } class donesearch $cn $id
set cn redirect_302_nokeep foreach { e } { [class names $cn] } { set u [lindex $e 0] set r [lindex $e 1] Do some stuff }
Recent Discussions
Related Content
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com