Forum Discussion
scott_sams_8256
Nimbostratus
Jun 08, 2010irule redirection question
i guess i am looking for an opinion on an idea i have.
we manage a handful of domains and are starting to get more and more redirect requests. i was told by our ecom director that i should expect more and more to come in. my concern is the way we have done them in the past is to setup a dns entry, point it to an ip, nat to a vip and then do a redirect with an irule.
i had thought that maybe i should consider doing the same but using one ip, and then just add to my irule and do a redirect based on the inbound uri request. i guess i am wondering that if this were to grow to 10,20, or even 30 different redirects would this become problematic?
thanks for any opinions or ideas on this.
scott
- hoolio
Cirrostratus
Hi Scott, - scott_sams_8256
Nimbostratus
Thanks Aaron, - hoolio
Cirrostratus
Here is an example I wrote for a customer for 9.4.7, based on preliminary project plans. The iRule was never used in production, so I didn't fully test or performance tune it. I've anonymized the rule, but not tested it, so try this on a test unit or test VS first.Name: customer_HTTPS_redirects_rewrites_rule HTTPS Redirects and Rewrites iRule BIG-IP ASM Tested on version 9.4.7 Current version: v1.2 2009 Sept 10 - Aaron Hooley Version: 1.0 - 2009 Aug 14 - Initial version tested Version: 1.1 - 2009 Aug 27 - Updates to query string logic Version: 1.2 - 2009 Sept 10 - Logging updates Description: This rule performs HTTP redirection or host/URI rewriting based on the configuration in a datagroup. Functionality: 1. This iRule can be used on an HTTP and/or HTTPS virtual server. A single configuration datagroup is referenced regardless of the client side HTTP or HTTPS setup. 2. The requested host and URI are checked against the source field of the configuration datagroup. The longest matching configuration line is used. The check is done explicitly using the requested path (/path/to/file.ext in the example URI /path/to/file.ext?param=value), logically stripping the query string from the requested URI. 3. Query string handling: The requested query string is not evaluated in the matching, but is preserved in rewrites and redirects. If the original request has a query string, it will be preserved. If the original request has no query string and the destination does, the destination query string is used. Configuration requirements: 1. A datagroup named customer_redirects_rewrites_class must be configured using the following space delimited format: source (host and/or URI) | destination (URL for redirects or host and/or URI for rewrites | action (rewrite or redirect) ---------------------------|----------------------------------------------------------------|----------------------------- www.example.co.uk/dir/ | https://www.example.co.uk/new/directory/ | redirect www.example.co.uk/rewrite | www.example.co.uk/cs/rewritten | rewrite The Host portion of any entry must be set to lower case. The fields must use URL encoding for spaces or the parsing will fail. The destination must not include the protocol if the action is 'rewrite' 2. The virtual server must have this iRule added as a resource. when RULE_INIT { Log debug messages to /var/log/ltm? (0=none, 1=minimal, 2=verbose) set ::customer_HTTPS_debug 1 if {$::customer_HTTPS_debug > 0}{log local0. "Debug set to $::customer_HTTPS_debug"} } when HTTP_REQUEST { if {$::customer_HTTPS_debug > 0}{ set log_prefix "[IP::client_addr]:[TCP::client_port] ([TCP::local_port])" log local0. "$log_prefix: -------------------------------------------------------------------------" log local0. "$log_prefix: New request to [HTTP::host][HTTP::uri] with UA: [HTTP::header User-Agent]" } Check requested host/URI against the datagroup to see if there are any matching rules for redirecting or rewriting the request. Look for the most specific (longest) match by searching first for the requested host/URI and then just requested URI. Evaluate all rules to find the longest match. Reset the longest match set longest_match 0 set matching_line "" Loop through each datagroup line (need to update [set classname] to [class get classname] for 10.x) foreach line [set ::customer_HTTPS_redirects_rewrites_class] { if {$::customer_HTTPS_debug > 1}{log local0. "$log_prefix: Checking [string tolower [HTTP::host]][HTTP::path] against [getfield $line " " 1]"} Check if the current line matches the host/URI if {[string match [string tolower [HTTP::host]][HTTP::path] [getfield $line " " 1]]}{ if {$::customer_HTTPS_debug > 0}{log local0. "$log_prefix: Matched: $line"} Found a match, so save the length of the current source token set current_length [string length [getfield $line " " 1]] if {$current_length > $longest_match}{ This is the longest match so far set matching_line $line Update the length of the current match set longest_match $current_length if {$::customer_HTTPS_debug > 0}{log local0. "$log_prefix: New longest match: $matching_line"} } } } Check if we haven't found a host/URI match. if {$matching_line eq ""}{ Loop through each datagroup line foreach line [set ::customer_HTTPS_redirects_rewrites_class] { if {$::customer_HTTPS_debug > 1}{log local0. "$log_prefix: Checking [HTTP::path] against [getfield $matching_line " " 1]"} Check if the current line matches the host/URI if {[string match [getfield $matching_line " " 1] [HTTP::path]]}{ if {$::customer_HTTPS_debug > 0}{log local0. "$log_prefix: Matched: $matching_line"} Found a match, so save the length of the current source token set current_length [string length [getfield $matching_line " " 1]] if {$current_length > $longest_match}{ This is the longest match so far set matching_line $line Update the length of the current match set longest_match $current_length if {$::customer_HTTPS_debug > 0}{log local0. "$log_prefix: New longest match: $line"} } } } } if {$matching_line eq ""}{ if {$::customer_HTTPS_debug > 0}{log local0. "$log_prefix: No match for [HTTP::host][HTTP::uri], exiting."} If there still isn't a match then exit this event in this rule return } else { There was a matching line in the config datagroup so save the line set destination [getfield $matching_line " " 2] if {$::customer_HTTPS_debug > 0}{log local0. "$log_prefix: Processing matching line: $matching_line"} Check for a query string in the original request as we'll need to include it in the redirect As there is a bug with HTTP::query (CR96326) parse HTTP::uri to get the query string set request_query_string [getfield [HTTP::uri] ? 2] Check if the source and destination both have a query string if {$request_query_string != "" && [scan $destination {%[^?]?%[^?]} destination_path destination_query_string]==2}{ set destination [string map -nocase "$destination_query_string $request_query_string" $destination] if {$::customer_HTTPS_debug > 0}{log local0. "$log_prefix: Replaced destination query string with original query string.\ Orig: $destination_query_string Dest: $request_query_string"} } Check the action from the rule switch [string tolower [getfield $matching_line " " 3]] { "redirect" { Redirect to the new location HTTP::respond 301 noserver Location [getfield $matching_line " " 2] if {$::customer_HTTPS_debug > 0}{log local0. "$log_prefix: Redirecting to [getfield $matching_line " " 2]"} } "rewrite" { Rewrite the host and URI Need to determine if destination is a host plus URI or an absolute URI The first character for a URI is a /, and a host plus URI is an alphanumeric switch [string range $destination 0 0] { "/" { Destination is a URI so just rewrite the URI HTTP::uri $destination if {$::customer_HTTPS_debug > 0}{log local0. "$log_prefix: Rewriting URI to $destination"} } default { Destination is a host and URI Save the host and URI separately using scan to save everything up to the first / as the host and everything including and after as the URI scan $destination {%[^/]%s} host uri if {$::customer_HTTPS_debug > 0}{log local0. "$log_prefix: Parsed host: $host, URI: $uri"} HTTP::header replace Host $host if {$::customer_HTTPS_debug > 0}{log local0. "$log_prefix: Rewrote host to $host"} Rewrite the URI if the destination URI is not empty or / if {[string length $uri] > 1}{ HTTP::uri $uri if {$::customer_HTTPS_debug > 0}{log local0. "$log_prefix: Rewrote URI to $uri"} } } } } } } } when HTTP_REQUEST priority 501 { This event is for debugging only and can be commented out or removed after testing is complete if {$::customer_HTTPS_debug > 0 && [getfield $matching_line " " 3] ne "redirect"}{ log local0. "$log_prefix: 501: Host: [HTTP::host], URI: [HTTP::uri]" } }
- scott_sams_8256
Nimbostratus
wow, that looks pretty in depth. i will take this and work on converting it to 10.1 and implementing in a qa. in the interim since i only have three now, would this suffice? - Michael_Yates
Nimbostratus
You could do it that way. The [HTTP::host] vaule of a URL isn't case sensitive only the [HTTP::uri] or [HTTP::path] is and that depends on the Operating System hosting the website.when HTTP_REQUEST { switch -glob [HTTP::host] { "www.website1.com" { HTTP::respond 301 Location "http://www.google.com" } "www.website2.com" { HTTP::redirect "http://www.yahoo.com" } "www.website3.com" { pool website3pool } } }
- scott_sams_8256
Nimbostratus
Thanks Michael, - Michael_Yates
Nimbostratus
I'm sorry. I'm crossing my realities.when HTTP_REQUEST { switch -glob [string tolower [HTTP::host]] { "www.website1.com" { HTTP::respond 301 Location "http://www.google.com" } "www.website2.com" { HTTP::redirect "http://www.yahoo.com" } "www.website3.com" { pool website3pool } } }
Recent Discussions
Related Content
DevCentral Quicklinks
* 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
Discover DevCentral Connects