20 Lines or Less: HTTP Headers and Query Parameters

What could you do with your code in 20 Lines or Less?

That's the question we like to ask from, for, and of (feel free to insert your favorite preposition here) the DevCentral community, and every time we do, we go looking to find cool new examples that show just how flexible and powerful iRules can be without getting in over your head. Thus was born the 20LoL (20 Lines or Less) series many moons ago. Over the years we've highlighted hundreds of iRules examples, all of which do downright cool things in less than 21 lines of code.

Location Header Rewrite with Non-Standard Port

In the first of two entries in this edition of 20LoL from community member AMG, this solution rewrites the location header not just from http to https, but also replaces the non-standard port as well, featuring a command completely valid but underused in lreplace.

when HTTP_RESPONSE {
  if {[string tolower [HTTP::header Location]] starts_with "http://" }{
    #Splits the Location Header string into a list
    # e.g. http://www.test.com/path1/path2/index.html = 'http:', '', 'www.test.com', 'path1', 'path2', 'index.html'
    set loc_list [split [HTTP::header Location] "/"]
    [getfield [HTTP::header Location] "/" 2]
    
    # Replaces list location 0 (first item) with 'https:'
    # e.g. list item 0 = 'http:' and is replaced with 'https:'
    lreplace [$loc_list 0 0 "https:"]
    
    # Appended the port number to list location 2 (the FQDN), if a port is already defined this will replaced
    # e.g. list item 2 = 'www.test.com:897' is replaced with 'www.test.com:80'
    # e.g. list item 2 = 'www2.test.com' is replaced with 'www2.test.com:80'
    lreplace [$loc_list 2 2 [lindex [split [lindex $loc_list 2] ":"] 0]:80]
    
    # List items are joined back together with '/' inserted and set at the new HTTP Location Header
    # e.g. list = 'https:', '', 'www.test.com:80', 'path1', 'path2', 'index.html' becomes 'https://www.test.com:80/path1/path2/index.html'
    HTTP::header replace Location [join $loc_list "/"]
  }
}

Persist on First Address in X-Forwarded-For Header

AMG’s second entry is short but useful extraction of one (in this case the first) of potentially many IP addresses listed in the X-Forwarded-For header for persistence. If the XFF header is empty, then the persistence is mapped to the source address of the IP packet.

# Name: persist_xff_uie
#
# To be used with UIE Persistence Profile
#
# Checks HTTP Request for 'X-Forwarded-For' header and if exists takes the first 'X-Forwarded-For' IP address as sets as
# Persist identifier.
# If the 'X-Forwarded-For' header does not exist then the client IP address is set as Persist identifier.
 
when HTTP_REQUEST {
  if {[HTTP::header X-Forwarded-For] != ""} then {
    persist uie [lindex [split [HTTP::header X-Forwarded-For] ","] 0]
  } else {
      persist uie [IP::client_addr]
  }
}

Select Specific Pool Member via Query Parameter

The first two entries are both in the codeshare, but the final entry is from the answers section of the site, courtesy of a question from community member “Just Have to Know” (cool handle!). The question is how to ensure a request is mapped to a specific pool member. Member Stanislas provides a short and elegant solution utilizing a query parameter on the request URL.

when CLIENT_ACCEPTED {
  set default_pool [LB::server pool]
}
when HTTP_REQUEST {
  set target_member [URI::query [HTTP::uri] server]
  if {!($target_member eq "")} {
    pool $default_pool member $target_member
    HTTP::uri [string map -nocase [list "&server=$target_member" "" ] [HTTP::uri]]
  }
}

And there it is, another edition of 20 Lines or Less, the power of iRules on full display. Happy coding out there, and I look forward to seeing what excellent contributions might make the next edition!

Published Oct 28, 2015
Version 1.0

Was this article helpful?

4 Comments

  • not so fast my friend, "tring map" is the latest and greatest! :) I kid...nice catch.
  • B_Earp's avatar
    B_Earp
    Icon for Nimbostratus rankNimbostratus

    First iRule: line 10: set loc_list [lreplace $loc_list 0 0 https:] line 15: set loc_list [lreplace $loc_list 2 2 [lindex [split [lindex $loc_list 2] ":"] 0]:8443]

     

  • Thanks B.Earp, I updated these, but left :80 as the original author has notes in the codeshare entry to change that to whatever the port should be in their scenario. Updated the original in the codeshare entry as well.