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