Redirect Trapper
Problem this snippet solves:
iRule to trap server redirect response, follow the redirect on the BIG-IP and return the followed response to the client as a result of original request
Code :
## REDIRECT TRAPPER - 1.1
## c.jenison@f5.com (Chad Jenison)
## More advanced and more expensive iRule to trap server redirect response, follow the redirect on the BIG-IP and return the followed response to the client as a result of original request
## advantages over simple approach:
## + sends original browser headers and cookies along with retried request
## + handles cookie sets on redirect; sends them on followed request; stores them for setting on the followed response
## + insertion of base href tag with computed URL (base href must be absolute) of location header - can fix broken embedded objects
## + attempts to prevent loops - should not recurse - assumption is to follow a single redirect; after that just pass redirect to browser
## + detects redirects to external sites (where the hostname portion of the Location field doesn't match Host header of request) and leaves them alone
when RULE_INIT {
#if HTTP for this virtual server
set static::proto http
#if HTTPS for this virtual server
#set static::proto https
# to perform basehref tag insertion on text/html using STREAM profile set below to 1
set static::dobasehref 1
}
when HTTP_REQUEST {
STREAM::disable
if {![info exists requestisredirectfollow]} {
set uri [HTTP::uri]
set httpver [HTTP::version]
set headers [HTTP::header names]
array unset request
array set request {uri $uri}
foreach header $headers {
set request($header) [HTTP::header $header]
}
} else {
#this request results from a followed redirect that was done using HTTP::retry
if {[info exists gotnewcookie]} {
HTTP::cookie insert $newcookiename $newcookievalue
}
unset requestisredirectfollow
set responseresultsfromretry 1
}
}
when HTTP_RESPONSE {
if {[HTTP::is_redirect]} {
if {![info exists responseresultsfromretry]} {
set location [HTTP::header Location]
if {[HTTP::header exists "Set-Cookie"]} {
set gotnewcookie 1
set newcookiename [HTTP::cookie names]
set newcookievalue [HTTP::cookie value $newcookiename]
set newsetcookieheader [HTTP::header value "Set-Cookie"]
}
if {$location starts_with "http:" || $location starts_with "https:"} {
set locationhost [URI::host $location]
set locationuri [URI::path $location]
append locationuri [URI::query $location]
} else {
#TBD: special handling for "relative" Location headers
set locationhost $request(Host)
set locationuri $location
}
if {[string tolower $request(Host)] == [string tolower $locationhost]} {
set newrequest "GET $locationuri HTTP/$httpver{BR}"
foreach header $headers {
if {$header == "Referer"} {
append newrequest "$header: http://$request(Host)$request(uri){BR}"
} else {
append newrequest "$header: $request($header){BR}"
}
}
append newrequest "x-irule-trapped-redirect: true{BR}"
append newrequest "{BR}"
set requestisredirectfollow 1
HTTP::retry $newrequest
} else {
#Redirect must be to an external host; not trapping
}
} else {
#this must be a redirect following a redirect; don't follow any further - don't recurse
#expected behavior is that the 2nd redirect response will pass through to client unaltered
unset responseresultsfromretry
if {[info exists gotnewcookie]} {
HTTP::header insert "Set-Cookie" $newsetcookieheader
unset gotnewcookie
}
}
} elseif {[info exists responseresultsfromretry]} {
if {[info exists gotnewcookie]} {
HTTP::header insert "Set-Cookie" $newsetcookieheader
unset gotnewcookie
#must be a normal response following a trapped redirect; need to add cookie to response
}
unset responseresultsfromretry
HTTP::header remove ETag
HTTP::header insert x-irule-trapped-redirect true
if {$static::dobasehref} {
if {[HTTP::header value Content-Type] == "text/html" && ![HTTP::header exists Content-Encoding]} {
STREAM::expression "@@ @"
STREAM::enable
}
}
}
}Published Mar 18, 2015
Version 1.0Chad_Jenison
Nimbostratus
Joined May 13, 2008
Chad_Jenison
Nimbostratus
Joined May 13, 2008
No CommentsBe the first to comment
Help guide the future of your DevCentral Community!
What tools do you use to collaborate? (1min - anonymous)