20 Lines or Less #67: Maintenance, Cookies, and Closing

What could you do with your code in 20 Lines or Less? That's the question I like to ask for the DevCentral community, and every time I go looking to find cool new examples that show just how flexible and powerful iRules can be without getting in over your head.


The dust has settled after the holidays and it's time to dig through the forums once again, dear reader, and unleash the goodness that is iRules brevity. Yes iRules are a favorite pastime, technology and tool for me, and I am especially keen on finding shining examples of iRules hawesomeness packaged in a bite sized morsel. Sure, I love the long, elaborate, intensely powerful scripts as much as the next coding zealot. Powerful tools like that are always wicked fun to dig into and toy with. For some reason, however, I find myself with a penchant for the brief, the efficient, and the elegant. Hence, the 20 Lines or Less.

Every couple of weeks I dig through the forums to see what's interesting and in 67 installments over the years I have yet to come up skunked, or let down. This week won't be the one to break the streak, either. It seems while many of us, myself included, were out merry making and gallivanting around for the holidays, there were those still firmly entrenched in iRules hawesomeness. Allow me to show my gratitude, then, for that merry band of code junkies, by exalting a few cool tidbits in this week's 20LoL.


Combining iRules for Maintenance Page


Maintenance pages in iRules is not a new concept. This has been done many times, in many different ways. Despite that, it is still a darn useful and increasingly powerful concept, and deserves some time to be shown off. Why is it increasingly powerful, you ask? Well, it's getting easier and more possible than ever to communicate complex, intricate pages from within your iRule. With the advent of iFiles, which allows you to directly load the contents of a file on your BIG-IP into your iRule, it is now shockingly simple to transmit large, complex pages. It is also possible to do things like create what is effectively a very small web server to respond with files as necessary for given requests, like the below example. Too cool.

   1: when HTTP_REQUEST {
   2:    if { [active_members pool ] < 1] } {
   3:        log local0. "Server Pool:  [LB::server pool]"
   4:        HTTP::respond 200 content [ifile get f5maint_txt]
   5:    } else {
   6:     switch -glob [string tolower[HTTP::uri]] {
   7:         "/favicon.ico" { HTTP::respond 200 content [ifile get favicon_ico] }
   8:         "/reset.css" { HTTP::respond 200 content [ifile get reset_css] }
   9:         "/style_main.css" { HTTP::respond 200 content [ifile get style_main_css] }
  10:         "/jquery.js"  { HTTP::respond 200 content [ifile get jquery_js] }
  11:         "/jquery.jfeed.pack.js"  { HTTP::respond 200 content [ifile get jquery.jfeed.pack_js] }
  12:         "/head.js"  { HTTP::respond 200 content [ifile get head_js] }
  13:         "/search.js"  { HTTP::respond 200 content [ifile get search_js] }
  14:         "/image_topbarleft.jpg"  { HTTP::respond 200 content [ifile get image_topbarleft_jpg] }
  15:         "/image_topbarright.jpg"  { HTTP::respond 200 content [ifile get image_topbarright_jpg] }
  16:         "/image_navtop.jpg"  { HTTP::respond 200 content [ifile get image_navtop_jpg] }
  17:         "/logo_main.png"  { HTTP::respond 200 content [ifile get logo_main_png] }
  18:          default { discard }
  19:     }
  20:    }
  21: }


iRules to drop based on cookie value


You know how sometimes there are those intensely corner case issues that you need to build a solution for, and you just don't know where to start? Try this one on for size: You need to inspect the value of cookies being passed through to your application. Based on the last character of each cookie, you need to either allow or deny the request. But you need to compare the last character of the cookie to the current date, and see if they align. You only want to allow cookies ending in an even number on even numbered days, and odd numbered cookies on odd numbered days. Yeah, corner case. Of course this sounds far more complex than it is with iRules in your pocket. Check out the amazingly simple solution hoolio threw together, and bask in the glory that is this powerful, flexible, efficient language. Four lines of effective code to do all that? Yep, I'm still a fan.


   1: when HTTP_REQUEST {
   3:     # Get day of month:
   4:     # set day [clock format [clock seconds] -format {%d}]
   5:     # Check if it is even
   6:     if {[clock format [clock seconds] -format {%d}] % 2 == 0 }{
   8:         # Check if the cookie value is not null: 
   9:         #    [HTTP::cookie my_cookie] ne "" 
  10:         # 
  11:         # Get the last char of the cookie value:
  12:         #    [string range [HTTP::cookie my_cookie] end end]
  13:         #
  14:         # Assign the last character of the cookie value to a variable, last_char
  15:         #    [set last_char [string range [HTTP::cookie my_cookie] end end]]
  16:         #
  17:         # Check if $last_char is an integer
  18:         #    [string is integer ...
  19:         #
  20:         # Check if the last character is even using modulus %
  21:         # string is integer: http://www.tcl.tk/man/tcl8.4/TclCmd/string.htm#M23
  22:         if {[HTTP::cookie my_cookie] ne "" and [string is integer [set last_char [string range [HTTP::cookie my_cookie] end end]]] and $last_char % 2 == 0 }{
  24:             # Allow the request. Exit this event in this iRule so we do not block the request
  25:             return
  26:         }
  27:     }
  28:     # Default action is to block the request
  29:     HTTP::respond 403 content "<html>you're blocked because you had cookie [HTTP::cookie my_cookie] and it is [clock format [clock seconds] -format {%d}] of the month</html>"
  30: }


TCP::close vs Event Disable


When looking to terminate things there are two concepts that people are often looking for, that do distinctly different things. One is the idea of terminating a given connection. You want to signal the BIG-IP to tell the client to pack up and go home, and shut down the connection in progress. For this, the TCP::close command is rather handy, and will get you where you need to go pretty easily. The other termination concept that people sometimes ask about is how to terminate not the connection, but iRule processing. I.E. "I've fired my iRules once, and now I want to make sure they don't run again for this connection". For that you can make use of the "event disable all" command, as long as you're truly sure you want no more iRules running for that connection at all. But what if I want to do both? What if I want to terminate the connection and then force all iRules processing to stop, to ensure I don't get a CLIENT_CLOSED event or something similar for the connection I just terminated? I've...never seen that before, so when it came across in the forums, I took note. It's worth noting that the order of the commands didn't matter here, which was my main curiosity, having not tested it myself. Firing the TCP::close command will indeed force CLIENT_CLOSED to fire, because the connection is terminated, but that won't occur until after the currently executing event's stack is resolved. If you add the event disable all command to that stack, it will ensure that no other events fire after the current one, even if you just forced a close. Interesting stuff, good to know, and easy to test. The code isn't much fancy here, but the concept made it worth mentioning. Thank you forums!


   1: when CLIENT_ACCEPTED {
   2:   log local0. ""
   3:   TCP::respond "OK"
   4:   TCP::close
   5:   event disable all
   6: }
   8: when CLIENT_CLOSED {
   9:   log local0. ""
  10: }
Published Jan 16, 2013
Version 1.0

Was this article helpful?

No CommentsBe the first to comment