<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:copyright="http://blogs.law.harvard.edu/tech/rss" xmlns:image="http://purl.org/rss/1.0/modules/image/">
    <channel>
        <title>iRules</title>
        <link>http://devcentral.f5.com/weblogs/macvittie/category/100.aspx</link>
        <description>All things iRules</description>
        <language>en-US</language>
        <copyright>Lori MacVittie</copyright>
        <managingEditor>l.macvittie@f5.com</managingEditor>
        <generator>Subtext Version 1.9.5.176</generator>
        <item>
            <title>Understanding network-side scripting</title>
            <link>http://devcentral.f5.com/weblogs/macvittie/archive/2008/10/31/understanding-network-side-scripting.aspx</link>
            <description>&lt;p&gt;We all understand the lines in the sand (or the architectural diagram) that separate &lt;em&gt;client-side &lt;/em&gt;scripting from &lt;em&gt;server-side &lt;/em&gt;scripting. It's very clear that client-side scripting, e.g. JavaScript, VBScript, ActionScript, executes on the client while server-side scripting, e.g. &lt;a href="http://www.php.net/ "&gt;PHP&lt;/a&gt;, &lt;a href="http://www.asp.net/"&gt;ASP&lt;/a&gt;, executes on the server. But what about &lt;em&gt;network-side scripting? &lt;/em&gt;&lt;/p&gt;
&lt;p&gt;"There is no such thing!" might be the first response to this question, but I beg to disagree. Programmable proxies, a la &lt;a href="http://www.f5.com"&gt;F5's&lt;/a&gt; &lt;a href="http://www.f5.com/products/big-ip"&gt;BIG-IP&lt;/a&gt; Local Traffic Manager, that provide a scripting language such as &lt;a href="http://devcentral.f5.com/iRules"&gt;iRules&lt;/a&gt;, are simultaneously client-side &lt;em&gt;and &lt;/em&gt;server-side, with the best definition to describe their placement in architectures being &lt;em&gt;network-side&lt;/em&gt; scripting. &lt;/p&gt;
&lt;p&gt;That's because the scripting, which is not different at all from client or server side scripting, executes &lt;em&gt;in the network&lt;/em&gt; rather than on the client or the server. It has a view of both the client and the server and the data being exchanged between them because of its unique placement in the communication channel. &lt;/p&gt;
&lt;p&gt;&lt;a href="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/WindowsLiveWriter/Networksidecoding_C72A/network-side-scripting_2.jpg"&gt;&lt;img height="118" border="0" align="left" width="486" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/WindowsLiveWriter/Networksidecoding_C72A/network-side-scripting_thumb.jpg" alt="network-side-scripting" style="border-width: 0px; margin: 0px 10px 5px 0px;" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Network-side scripting essentially gives you a view of both client and server environments simultaneously, and in a single, unified location. &lt;/p&gt;
&lt;p&gt;For example, network-side scripting can react to server-focused data like HTTP responses, cookies, and session information while simultaneously taking into consideration client-side information - HTTP requests, cookies, submitted data, and even the network conditions currently being experienced by that specific client. Because a programmable proxy is by necessity a &lt;a href="http://devcentral.f5.com/weblogs/macvittie/archive/2008/10/02/the-concise-guide-to-proxies.aspx"&gt;full proxy&lt;/a&gt;, it is both client (to your application) and server (to the browser/customer) and can view all interactions between the two as a cohesive unit rather than as disconnected pieces of data. &lt;br /&gt;
&lt;/p&gt;
&lt;p style="color: rgb(255, 0, 0);"&gt;[Edited to include an example, thanks to a suggestion from Bob in the comments!]&lt;/p&gt;
&lt;p&gt;Here's an example of Cookie encryption that uses network-side scripting. The entire script runs in the network (on the proxy) but we've split the code into "client" and "server" side to show how network-side scripting can deal with both sides of the equation. There is additional script that executes when the rule is first initialized. You can check it out in the &lt;a href="javascript:void(0);/*1225468289314*/"&gt;article that is the source for this code&lt;/a&gt;. &lt;br /&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;&lt;table cellspacing="1" cellpadding="1" border="1" align="" summary="" style="width: 665px; height: 23px;"&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;td&gt;"Client side"&lt;/td&gt;
            &lt;td&gt;"Server side"&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;
            &lt;pre&gt;when HTTP_REQUEST {&lt;br /&gt;   # If the error cookie exists with any value, for any requested object, try to decrypt it&lt;br /&gt;   if {[string length [HTTP::cookie value $::cookie]]}{&lt;br /&gt;&lt;br /&gt;      if {$::cookie_encryption_debug}{log local0. \&lt;br /&gt;         "Original error cookie value: [HTTP::cookie value $::cookie]"}&lt;br /&gt;&lt;br /&gt;      # URI decode the value (catching any errors that occur when trying to &lt;br /&gt;      # decode the cookie value and save the output to cookie_uri_decoded)&lt;br /&gt;      if {not ([catch {URI::decode [HTTP::cookie value $::cookie]} cookie_uri_decoded])}{&lt;br /&gt;&lt;br /&gt;         # Log that the cookie was URI decoded&lt;br /&gt;         if {$::cookie_encryption_debug}{log local0. "\$cookie_uri_decoded was set successfully"}&lt;br /&gt;&lt;br /&gt;         # Decrypt the value&lt;br /&gt;         if {not ([catch {AES::decrypt $::aes_key $cookie_uri_decoded} cookie_decrypted])}{&lt;br /&gt;&lt;br /&gt;            # Log the decrypted cookie value&lt;br /&gt;            if {$::cookie_encryption_debug}{log local0. "\$cookie_decrypted: $cookie_decrypted"}&lt;br /&gt;         } else {&lt;br /&gt;&lt;br /&gt;            # URI decoded value couldn't be decrypted.&lt;br /&gt;         }&lt;br /&gt;      } else {&lt;br /&gt;         # Cookie value couldn't be URI decoded&lt;br /&gt;      }&lt;br /&gt;   } else {&lt;br /&gt;      # Cookie wasn't present in the request&lt;/pre&gt;
            &lt;/td&gt;
            &lt;td&gt;
            &lt;div style="text-align: left;"&gt;when HTTP_RESPONSE {&lt;br /&gt;
            &lt;/div&gt;
            &lt;pre&gt;&lt;br /&gt;   # Check if response contains an error cookie with a value&lt;br /&gt;   if {[string length [HTTP::cookie value $::cookie]] &amp;gt; 0}{&lt;br /&gt;&lt;br /&gt;      # Log the original error cookie value from the app&lt;br /&gt;      if {$::cookie_encryption_debug}{log local0. \&lt;br /&gt;         "Response from app contained our cookie: [HTTP::cookie value $::cookie]"}&lt;br /&gt;&lt;br /&gt;      # Encrypt the cookie value so the client can't change the value&lt;br /&gt;      HTTP::cookie value $::error_cookie [URI::encode [AES::encrypt $::aes_key [HTTP::cookie value $::cookie]]]&lt;br /&gt;&lt;br /&gt;      # Log the encoded and encrypted error cookie value&lt;br /&gt;      if {$::cookie_encryption_debug}{log local0. \&lt;br /&gt;        "Encrypted error cookie to: [URI::encode [AES::encrypt $::aes_key [HTTP::cookie value $::cookie]]]"}&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;The "client" side deals with client-specific events, like HTTP_REQUEST, and executes code to find and decrypt the appropriate cookie before sending the request and the now plain-text cookie to the web server. &lt;br /&gt;
&lt;/p&gt;
&lt;p&gt;The "server" side deals with server-side specific events, like HTTP_RESPONSE, and executes code to find and encrypt the cookie before returning the response and the now protected cookie to the client. &lt;/p&gt;
&lt;p&gt;Network-side scripting executes &lt;em&gt;in the network&lt;/em&gt;, on a programmable &lt;a href="http://devcentral.f5.com/weblogs/macvittie/archive/2008/10/08/8-things-you-can-do-with-a-proxy.aspx"&gt;proxy&lt;/a&gt; such as an &lt;a href="http://www.f5.com/products/big-ip"&gt;application delivery platform&lt;/a&gt;. It can store information about client-side activity and environments that can be taken into consideration when processing server responses. It can inspect and modify both client and server side data for myriad purposes including optimization, security, and to assist with implementing application-specific logic. &lt;/p&gt;
&lt;p&gt;Network-side scripting allows you to implement application functionality &lt;em&gt;in the network &lt;/em&gt;that can provide benefits like improved application performance; it can enable agility in both your network and application infrastructure; it can provide centralization of functionality in a service-oriented manner through reusable network-side scripts that can be applied as necessary to one, two, or all applications with minimal effort. &lt;/p&gt;
&lt;p&gt;Network-side scripting is a powerful mechanism through which you can architect more scalable, secure, and peformant infrastructures capable of handling high-volumes of requests while protecting server-side infrastructures from the sometimes adverse affects of sudden spikes in user concurrency. &lt;/p&gt;
&lt;table cellspacing="0" cellpadding="2" border="0" width="100%"&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;td width="199" valign="top" style="color: white; background-color: rgb(153, 0, 0);"&gt;&lt;strong&gt;Network-side scripting uses&lt;/strong&gt;&lt;/td&gt;
            &lt;td width="696" valign="top"&gt;Network-side scripting is both client and server-side scripting that lives in the network, mediating between &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td width="199" valign="top" style="border: 1px solid rgb(153, 0, 0); padding: 5px;"&gt;
            &lt;ul&gt;
                &lt;li&gt;Cookie Encryption&lt;/li&gt;
                &lt;li&gt;LDAP Connection Proxy&lt;/li&gt;
                &lt;li&gt;Authentication&lt;/li&gt;
                &lt;li&gt;Data input validation&lt;/li&gt;
                &lt;li&gt;Data scrubbing&lt;/li&gt;
                &lt;li&gt;Sticky connections&lt;/li&gt;
                &lt;li&gt;Error handling&lt;/li&gt;
                &lt;li&gt;Exception handling&lt;/li&gt;
                &lt;li&gt;URI rewriting &lt;/li&gt;
            &lt;/ul&gt;
            &lt;/td&gt;
            &lt;td width="696" valign="top"&gt;clients and servers to provide a platform on which a wide variety of solutions can be implemented. If you haven't previously considered the potential uses of network-side scripting in your architecture, give it some thought now.          &lt;br /&gt;
            &lt;br /&gt;
            Network-side scripting is one of the ways in which an agile infrastructure can be built that supports both IT and business agility. It offers a unique view into client and server side variables and parameters at a single point in the transaction process, which can be leveraged to implement any number of really cool solutions that span a variety of IT-focused disciplines.           &lt;br /&gt;
            &lt;br /&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;a href="http://twitter.com/lmacvittie"&gt;&lt;img height="18" border="0" width="18" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_twitt-twoo-icon.png" alt="Follow me on Twitter" /&gt;&lt;/a&gt; &lt;a href="http://devcentral.f5.com/weblogs/macvittie/Rss.aspx"&gt;&lt;img border="0" src="http://devcentral.f5.com/Portals/0/images/Icons/icon_xml_18.gif" alt="" /&gt;&lt;/a&gt;&lt;a href="http://www.slideshare.net/lmacvittie"&gt;&lt;img height="18" border="0" width="18" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_slideshare.png" alt="View Lori's profile on SlideShare" /&gt;&lt;/a&gt;&lt;a border="0" href="http://lmacvittie.tumblr.com"&gt;&lt;img height="18" border="0" width="18" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_tumblr.gif" title="Follow me on Tumblr" alt="" /&gt;&lt;/a&gt; &lt;a href="http://lmacvittie.posterous.com/"&gt;&lt;img border="0" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_posterous.png" title="Posterous" alt="" /&gt;&lt;/a&gt; &lt;a href="http://www.linkedin.com/in/lmacvittie"&gt;&lt;img border="0" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_linkedin_16.png" alt="" /&gt;&lt;/a&gt; &lt;a href="http://www.addthis.com/feed.php?pub=lmacvittie&amp;amp;h1=http%3A%2F%2Fdevcentral.f5.com%2Fweblogs%2Fmacvittie%2FRss.aspx&amp;amp;t1=" title="Subscribe using any feed reader!"&gt;&lt;img height="18" border="0" width="125" src="http://s9.addthis.com/button1-fd.gif" alt="AddThis Feed Button" /&gt;&lt;/a&gt; &lt;a target="_blank" href="http://www.addthis.com/bookmark.php" onclick="window.open('http://www.addthis.com/bookmark.php?wt=nw&amp;amp;pub=lmacvittie&amp;amp;url='+encodeURIComponent(location.href)+'&amp;amp;title='+encodeURIComponent(document.title), 'addthis', 'scrollbars=yes,menubar=no,width=620,height=520,resizable=yes,toolbar=no,location=no,status=no,screenX=200,screenY=100,left=200,top=100'); return false;" title="Bookmark and Share"&gt;&lt;img height="18" border="0" width="125" src="http://s9.addthis.com/button1-share.gif" alt="Bookmark and Share" /&gt;&lt;/a&gt;&lt;script src="http://track.mybloglog.com/js/jsserv.php?mblID=2008070914270355" type="text/javascript"&gt;&lt;/script&gt;&lt;script src="http://feeds.feedburner.com/~s/f5/XOwx" type="text/javascript" charset="utf-8"&gt;&lt;/script&gt;&lt;script src="http://feeds.feedburner.com/~d/static/site-tracker.js" type="text/javascript" charset="utf-8"&gt;&lt;/script&gt;&lt;script src="http://feeds.feedburner.com/~d/static/site-tracker.js" type="text/javascript" charset="utf-8"&gt;&lt;/script&gt; &lt;/p&gt;
&lt;div style="margin: 0px; padding: 0px; display: inline;" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:76bac5b5-4f97-4bc3-9ea2-94187bf9b066" class="wlWriterSmartContent"&gt;Technorati Tags: &lt;a rel="tag" href="http://technorati.com/tags/MacVittie"&gt;MacVittie&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/F5"&gt;F5&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/BIG-IP"&gt;BIG-IP&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/proxy"&gt;proxy&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/scripting"&gt;scripting&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/server-side"&gt;server-side&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/client-side"&gt;client-side&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/application%20delivery"&gt;application delivery&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/network-side"&gt;network-side&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/cookies"&gt;cookies&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/persistence"&gt;persistence&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/web"&gt;web&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/internet"&gt;internet&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/applications"&gt;applications&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/architecture"&gt;architecture&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/infrastructure"&gt;infrastructure&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/PHP"&gt;PHP&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/ASP"&gt;ASP&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/JavaScript"&gt;JavaScript&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/VBScript"&gt;VBScript&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/ActionScript"&gt;ActionScript&lt;/a&gt;&lt;/div&gt;&lt;div class='blogtags'&gt;&lt;/div&gt;&lt;img src="http://devcentral.f5.com/weblogs/macvittie/aggbug/3744.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Lori MacVittie</dc:creator>
            <guid>http://devcentral.f5.com/weblogs/macvittie/archive/2008/10/31/understanding-network-side-scripting.aspx</guid>
            <pubDate>Fri, 31 Oct 2008 12:26:49 GMT</pubDate>
            <wfw:comment>http://devcentral.f5.com/weblogs/macvittie/comments/3744.aspx</wfw:comment>
            <comments>http://devcentral.f5.com/weblogs/macvittie/archive/2008/10/31/understanding-network-side-scripting.aspx#feedback</comments>
            <slash:comments>5</slash:comments>
            <wfw:commentRss>http://devcentral.f5.com/weblogs/macvittie/comments/commentRss/3744.aspx</wfw:commentRss>
            <trackback:ping>http://devcentral.f5.com/weblogs/macvittie/services/trackbacks/3744.aspx</trackback:ping>
        </item>
        <item>
            <title>How to prevent content theft using Apache mod_rewrite or F5 iRules</title>
            <link>http://devcentral.f5.com/weblogs/macvittie/archive/2008/10/21/how-to-prevent-content-theft-using-apache-mod_rewrite-or-f5.aspx</link>
            <description>&lt;p&gt;Over the years imaginative developers have come up with a number of ways through which they hope to stop the pilfering of their images. Whether due to copyright issues or the increased bandwidth and associated costs resulting from "&lt;a href="http://en.wikipedia.org/wiki/Inline_linking"&gt;hot linking&lt;/a&gt;", site owners have tried a variety of solutions from JavaScript that prevents the ability to right-click and "save as" to watermarking high-resolution versions to make their images less appealing to image thieves. &lt;/p&gt;  &lt;p&gt;Regardless of the reason you may want to prevent image theft, there's an easier and more effective method than introducing easily countered JavaScript and costly alternative technology solutions. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;HTTP REFERER&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Every web request made via &lt;a href="http://devcentral.f5.com/weblogs/macvittie/archive/2008/05/21/3283.aspx"&gt;HTTP&lt;/a&gt; comes with a set of standard &lt;a href="http://en.wikipedia.org/wiki/HTTP"&gt;HTTP&lt;/a&gt; headers. One of those headers is the &lt;em&gt;referer (&lt;/em&gt;interesting spelled incorrectly)&lt;em&gt;, &lt;/em&gt;which indicates the domain and &lt;a href="http://en.wikipedia.org/wiki/Uniform_Resource_Locator "&gt;URL&lt;/a&gt; from which the request was made. If the request was direct (e.g. typed into the address bar by the user or loaded from a bookmark) then the referer header will be empty and usually displays in logs as "-" (at least they do on &lt;a href="http://www.apache.org"&gt;Apache&lt;/a&gt;). Otherwise, the referer header will have the &lt;a href="http://en.wikipedia.org/wiki/FQDN"&gt;FQDN&lt;/a&gt; (Fully Qualified Domain Name) of the referring page. &lt;/p&gt;  &lt;p&gt;The &lt;em&gt;referer header&lt;/em&gt; is central to this solution; by checking the &lt;em&gt;referer header&lt;/em&gt; you can determine whether the request for your image came from a page on your site or someone else's or was a direct request. If you're trying to prevent theft obviously you only want to allow access to images if the request came from a page hosted on your site. So the referrer must contain your unique domain name (or any domain name you wish to allow access to) or the request should be denied. &lt;/p&gt;  &lt;p&gt;Once you've determined that the referrer is &lt;em&gt;not &lt;/em&gt;allowed access to the image, you'll want to rewrite the URL (there are caveats with this, so be careful) or respond in such a way as to indicate to the client that the image is not available for viewing. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;IMPLEMENTING THE SOLUTION&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;In order to implement the solution you'll need to be able to intercept the request and examine the headers to determine its validity. We'll look at both &lt;em&gt;&lt;a href="http://httpd.apache.org/docs/1.3/mod/mod_rewrite.html"&gt;mod_rewrite&lt;/a&gt; &lt;/em&gt;(&lt;a href="http://www.apache.org"&gt;Apache&lt;/a&gt;) and &lt;em&gt;&lt;a href="http://www.f5.com"&gt;F5&lt;/a&gt; &lt;a href="http://devcentral.f5.com/iRules"&gt;iRules&lt;/a&gt; (&lt;/em&gt;&lt;a href="http://www.f5.com/products/big-ip"&gt;BIG-IP&lt;/a&gt;) as a mechanism to do this. &lt;/p&gt;  &lt;table cellspacing="0" cellpadding="2" width="985" border="0"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td style="color: white; background-color: #990000" valign="top" width="461"&gt;&lt;strong&gt;mod_rewrite&lt;/strong&gt;&lt;/td&gt;        &lt;td style="color: white; background-color: #990000" valign="top" width="522"&gt;&lt;strong&gt;iRules&lt;/strong&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="461"&gt;         &lt;pre&gt;(mod_rewrite code courtesy of: &lt;a href="http://www.debian-administration.org/articles/136"&gt;Debian Administration&lt;/a&gt;)&lt;/pre&gt;

        &lt;pre&gt;Rewriteengine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://example.com/.*$ [NC]
RewriteRule .*.(gif|GIF|jpg|JPG)$ - [F]&lt;/pre&gt;

        &lt;pre&gt; &lt;/pre&gt;
      &lt;/td&gt;

      &lt;td valign="top" width="522"&gt;
        &lt;pre&gt;when HTTP_REQUEST {          &lt;br /&gt;   set thief 0        &lt;br /&gt;   set uri [HTTP::uri]       &lt;p&gt;   if {[matchclass $uri ends_with $::images] &amp;gt; 0 } {          &lt;br /&gt;      if {[HTTP::header value Referer] contains "example.com"} {&lt;br /&gt;         set thief 0          &lt;br /&gt;      }          &lt;br /&gt;      else {          &lt;br /&gt;         set thief 1          &lt;br /&gt;      }          &lt;br /&gt;   }          &lt;br /&gt;   if {$thief eq 1} {          &lt;br /&gt;      HTTP::respond 200 content ""          &lt;br /&gt;   }          &lt;br /&gt;   else {          &lt;br /&gt;      pool &lt;strong&gt;mywebsite_pool &lt;/strong&gt;          &lt;br /&gt;   }          &lt;br /&gt;}&lt;/p&gt;&lt;/pre&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;That's pretty much it. You could get creative and respond with an actual image, or rewrite the URI to be a different image. If you choose the latter, be aware that you'll need to add code to handle that exception case, or you'll put the client into a redirection loop. After all, the referrer is still not your site, so redirecting to another image will fall into the same code unless you specifically catch it. While &lt;a href="http://www.mozilla.com/firefox"&gt;Firefox&lt;/a&gt; will recognize this infinite loop and stop requesting the image, &lt;a href="http://www.microsoft.com/windows/products/winfamily/ie/default.mspx"&gt;IE 7&lt;/a&gt; just keeps trying, which is somewhat amusing but floods the network with requests that aren't going to get answered and uses up a connection on your web server or &lt;a href="http://www.f5.com/products/big-ip"&gt;BIG-IP&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;This solution obviously can be used to stop hotlinking to any type of content: Flash, video, audio, text. You only need change the extensions you are looking for to match those used by the content in question. You could also get more sophisticated and set up a system whereby allowed domains are given a &lt;a href="http://devcentral.f5.com/weblogs/macvittie/archive/2008/06/04/3329.aspx"&gt;cookie&lt;/a&gt;, which you can subsequently check to determine whether access should be allowed. You could also use this logic to stop specific domains from hotlinking to your content by checking the referer header against a list of allowed sites and refusing to serve the content to sites not on the list. &lt;/p&gt;

&lt;p&gt;The nature of an intelligent mediator is such that you can pretty much come up with just about any solution involving HTTP headers and implement it fairly easily. There are &lt;a href="http://devcentral.f5.com/weblogs/macvittie/archive/2008/07/07/3428.aspx"&gt;advantages to using a full-proxy solution over mod_rewrite&lt;/a&gt;, but both will definitely provide a platform on which you can deploy a solution that can prevent content theft. &lt;/p&gt;

&lt;p&gt;&lt;a href="http://twitter.com/lmacvittie"&gt;&lt;img height="18" alt="Follow me on Twitter" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_twitt-twoo-icon.png" width="18" border="0" /&gt;&lt;/a&gt; &lt;a href="http://devcentral.f5.com/weblogs/macvittie/Rss.aspx"&gt;&lt;img src="http://devcentral.f5.com/Portals/0/images/Icons/icon_xml_18.gif" border="0" /&gt;&lt;/a&gt;&lt;a href="http://www.slideshare.net/lmacvittie"&gt;&lt;img height="18" alt="View Lori's profile on SlideShare" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_slideshare.png" width="18" border="0" /&gt;&lt;/a&gt;&lt;a href="http://lmacvittie.tumblr.com" border="0"&gt;&lt;img title="Follow me on Tumblr" height="18" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_tumblr.gif" width="18" border="0" /&gt;&lt;/a&gt; &lt;a href="http://lmacvittie.posterous.com/"&gt;&lt;img title="Posterous" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_posterous.png" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.linkedin.com/in/lmacvittie"&gt;&lt;img src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_linkedin_16.png" border="0" /&gt;&lt;/a&gt; &lt;a title="Subscribe using any feed reader!" href="http://www.addthis.com/feed.php?pub=lmacvittie&amp;amp;h1=http%3A%2F%2Fdevcentral.f5.com%2Fweblogs%2Fmacvittie%2FRss.aspx&amp;amp;t1="&gt;&lt;img height="18" alt="AddThis Feed Button" src="http://s9.addthis.com/button1-fd.gif" width="125" border="0" /&gt;&lt;/a&gt; &lt;a title="Bookmark and Share" onclick="window.open('http://www.addthis.com/bookmark.php?wt=nw&amp;amp;pub=lmacvittie&amp;amp;url='+encodeURIComponent(location.href)+'&amp;amp;title='+encodeURIComponent(document.title), 'addthis', 'scrollbars=yes,menubar=no,width=620,height=520,resizable=yes,toolbar=no,location=no,status=no,screenX=200,screenY=100,left=200,top=100'); return false;" href="http://www.addthis.com/bookmark.php" target="_blank"&gt;&lt;img height="18" alt="Bookmark and Share" src="http://s9.addthis.com/button1-share.gif" width="125" border="0" /&gt;&lt;/a&gt;&lt;script src="http://track.mybloglog.com/js/jsserv.php?mblID=2008070914270355" type="text/javascript"&gt;&lt;/script&gt;&lt;script src="http://feeds.feedburner.com/~s/f5/XOwx" type="text/javascript" charset="utf-8"&gt;&lt;/script&gt;&lt;script src="http://feeds.feedburner.com/~d/static/site-tracker.js" type="text/javascript" charset="utf-8"&gt;&lt;/script&gt; &lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:98965a8b-49cf-4240-8058-1d2daf644472" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/MacVittie" rel="tag"&gt;MacVittie&lt;/a&gt;,&lt;a href="http://technorati.com/tags/F5" rel="tag"&gt;F5&lt;/a&gt;,&lt;a href="http://technorati.com/tags/iRules" rel="tag"&gt;iRules&lt;/a&gt;,&lt;a href="http://technorati.com/tags/BIG-IP" rel="tag"&gt;BIG-IP&lt;/a&gt;,&lt;a href="http://technorati.com/tags/mod_rewrite" rel="tag"&gt;mod_rewrite&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Apache" rel="tag"&gt;Apache&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Flash" rel="tag"&gt;Flash&lt;/a&gt;,&lt;a href="http://technorati.com/tags/images" rel="tag"&gt;images&lt;/a&gt;,&lt;a href="http://technorati.com/tags/theft" rel="tag"&gt;theft&lt;/a&gt;,&lt;a href="http://technorati.com/tags/rewrite" rel="tag"&gt;rewrite&lt;/a&gt;,&lt;a href="http://technorati.com/tags/hotlinking" rel="tag"&gt;hotlinking&lt;/a&gt;,&lt;a href="http://technorati.com/tags/firefox" rel="tag"&gt;firefox&lt;/a&gt;,&lt;a href="http://technorati.com/tags/IE7" rel="tag"&gt;IE7&lt;/a&gt;,&lt;a href="http://technorati.com/tags/referer%20header" rel="tag"&gt;referer header&lt;/a&gt;,&lt;a href="http://technorati.com/tags/HTTP" rel="tag"&gt;HTTP&lt;/a&gt;,&lt;a href="http://technorati.com/tags/internet" rel="tag"&gt;internet&lt;/a&gt;,&lt;a href="http://technorati.com/tags/web" rel="tag"&gt;web&lt;/a&gt;&lt;/div&gt;&lt;div class='blogtags'&gt;&lt;/div&gt;&lt;img src="http://devcentral.f5.com/weblogs/macvittie/aggbug/3729.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Lori MacVittie</dc:creator>
            <guid>http://devcentral.f5.com/weblogs/macvittie/archive/2008/10/21/how-to-prevent-content-theft-using-apache-mod_rewrite-or-f5.aspx</guid>
            <pubDate>Tue, 21 Oct 2008 10:31:51 GMT</pubDate>
            <wfw:comment>http://devcentral.f5.com/weblogs/macvittie/comments/3729.aspx</wfw:comment>
            <comments>http://devcentral.f5.com/weblogs/macvittie/archive/2008/10/21/how-to-prevent-content-theft-using-apache-mod_rewrite-or-f5.aspx#feedback</comments>
            <slash:comments>4</slash:comments>
            <wfw:commentRss>http://devcentral.f5.com/weblogs/macvittie/comments/commentRss/3729.aspx</wfw:commentRss>
            <trackback:ping>http://devcentral.f5.com/weblogs/macvittie/services/trackbacks/3729.aspx</trackback:ping>
        </item>
        <item>
            <title>Automatically detecting client speed</title>
            <link>http://devcentral.f5.com/weblogs/macvittie/archive/2008/09/09/3599.aspx</link>
            <description>&lt;p&gt;We used to spend a lot of cycles worrying about &lt;a href="http://devcentral.f5.com/weblogs/cwalker/archive/2008/07/16/20-lines-or-less-11.aspx"&gt;detecting user agents&lt;/a&gt; (i.e. browser) and redirecting clients to the pages written specifically for that browser. You know, back when browser incompatibility was a way of life. Yesterday. &lt;/p&gt;  &lt;p&gt;&lt;a href="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/WindowsLiveWriter/Automaticallydetectingclientspeed_A815/multi-browsers_2.gif"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="100" alt="multi-browsers" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/WindowsLiveWriter/Automaticallydetectingclientspeed_A815/multi-browsers_thumb.gif" width="100" align="left" border="0" /&gt;&lt;/a&gt; Compatibility is still an issue, but most web developers are either using third-party JavaScript libraries to handle detection and incompatibility issues or don't use those particular features that cause problems. &lt;/p&gt;  &lt;p&gt;One thing still seen at times, however, is the "choose high bandwidth or low bandwidth" entry pages, particularly on sites laden with streaming video and audio, whose playback is highly sensitive to the effects of &lt;a href="http://www.webopedia.com/TERM/J/jitter.html"&gt;jitter&lt;/a&gt; and thus need a fatter pipe over which to stream. &lt;/p&gt;  &lt;p&gt;Web site designers necessarily include the "choose your speed" page because they can't reliably determine client speed. Invariably, some user on a poor connection is going to choose high bandwidth anyway, and then e-mail or call to complain about poor service. Because that's how people are. &lt;/p&gt;  &lt;p&gt;So obviously we still have a need to detect client speed, but the code and method of doing so in the web application would be prohibitively complex and consume time and resources better spent elsewhere. But we'd still like to direct the client to the appropriate page without asking, because we're nice that way - or more likely we just want to avoid the phone call later. That would be a huge motivator for me, but I'm like that. I hate phones.  &lt;/p&gt;  &lt;p&gt;Whatever the reason, detecting client speed is valuable for directing users to appropriate content as well as providing other functionality, such as compression. Compression is itself a resource consuming function and &lt;a href="http://devcentral.f5.com/weblogs/macvittie/archive/2007/10/19/2971.aspx"&gt;applying compression in some situations can actually degrade performance&lt;/a&gt;, effectively negating the improvement in response time gained by decreasing the size of the data to be transferred. &lt;/p&gt;  &lt;p&gt;If you've got an &lt;a href="http://www.f5.com/products/big-ip"&gt;intelligent application delivery platform&lt;/a&gt; in place, you can automatically determine client speed and direct requests based on that speed without needing to ask the client for input. Using &lt;a href="http://devcentral.f5.com/iRules"&gt;iRules&lt;/a&gt;, just grab the round-trip time (or bandwidth) and &lt;a href="http://http://devcentral.f5.com/weblogs/macvittie/archive/2008/03/06/3099.aspx"&gt;rewrite the URI&lt;/a&gt; accordingly: &lt;/p&gt;  &lt;pre&gt;    when HTTP_REQUEST { &lt;br /&gt;        if { [TCP::rtt] &amp;gt;= 1000 } { &lt;br /&gt;            HTTP::uri "/slowsite.html" &lt;br /&gt;        } &lt;br /&gt;    } &lt;/pre&gt;

&lt;p&gt;If you don't want to automatically direct the client, you could use this information to add a message to your normal "choose your bandwidth" page that lets the client know their connection isn't so great and perhaps they should  choose the lower-bandwidth option. This is also good for collecting statistics, if you're interested, on the types of connections your customers and users are on. This can help you make a decision regarding whether you even need that choice page, and maybe lead to only supporting one option - making the development and maintenance of your site and video/audio all that much more streamlined. &lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="http://twitter.com/lmacvittie"&gt;&lt;img height="18" alt="Follow me on Twitter" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_twitt-twoo-icon.png" width="18" border="0" /&gt;&lt;/a&gt; &lt;a href="http://devcentral.f5.com/weblogs/macvittie/Rss.aspx"&gt;&lt;img src="http://devcentral.f5.com/Portals/0/images/Icons/icon_xml_18.gif" border="0" /&gt;&lt;/a&gt;&lt;a href="http://www.slideshare.net/lmacvittie"&gt;&lt;img height="18" alt="View Lori's profile on SlideShare" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_slideshare.png" width="18" border="0" /&gt;&lt;/a&gt;&lt;a href="http://lmacvittie.tumblr.com" border="0"&gt;&lt;img title="Follow me on Tumblr" height="18" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_tumblr.gif" width="18" border="0" /&gt;&lt;/a&gt; &lt;a href="http://lmacvittie.posterous.com/"&gt;&lt;img title="Posterous" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_posterous.png" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.linkedin.com/in/lmacvittie"&gt;&lt;img src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_linkedin_16.png" border="0" /&gt;&lt;/a&gt; &lt;a title="Subscribe using any feed reader!" href="http://www.addthis.com/feed.php?pub=lmacvittie&amp;amp;h1=http%3A%2F%2Fdevcentral.f5.com%2Fweblogs%2Fmacvittie%2FRss.aspx&amp;amp;t1="&gt;&lt;img height="18" alt="AddThis Feed Button" src="http://s9.addthis.com/button1-fd.gif" width="125" border="0" /&gt;&lt;/a&gt; &lt;a title="Bookmark and Share" onclick="window.open('http://www.addthis.com/bookmark.php?wt=nw&amp;amp;pub=lmacvittie&amp;amp;url='+encodeURIComponent(location.href)+'&amp;amp;title='+encodeURIComponent(document.title), 'addthis', 'scrollbars=yes,menubar=no,width=620,height=520,resizable=yes,toolbar=no,location=no,status=no,screenX=200,screenY=100,left=200,top=100'); return false;" href="http://www.addthis.com/bookmark.php" target="_blank"&gt;&lt;img height="18" alt="Bookmark and Share" src="http://s9.addthis.com/button1-share.gif" width="125" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:c0e06214-3670-4516-9b8b-2a0f5e24ae5d" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/MacVittie" rel="tag"&gt;MacVittie&lt;/a&gt;,&lt;a href="http://technorati.com/tags/F5" rel="tag"&gt;F5&lt;/a&gt;,&lt;a href="http://technorati.com/tags/iRules" rel="tag"&gt;iRules&lt;/a&gt;,&lt;a href="http://technorati.com/tags/bandwidth" rel="tag"&gt;bandwidth&lt;/a&gt;,&lt;a href="http://technorati.com/tags/compression" rel="tag"&gt;compression&lt;/a&gt;,&lt;a href="http://technorati.com/tags/redirect" rel="tag"&gt;redirect&lt;/a&gt;,&lt;a href="http://technorati.com/tags/http" rel="tag"&gt;http&lt;/a&gt;,&lt;a href="http://technorati.com/tags/web" rel="tag"&gt;web&lt;/a&gt;,&lt;a href="http://technorati.com/tags/internet" rel="tag"&gt;internet&lt;/a&gt;,&lt;a href="http://technorati.com/tags/tcp" rel="tag"&gt;tcp&lt;/a&gt;,&lt;a href="http://technorati.com/tags/speed" rel="tag"&gt;speed&lt;/a&gt;,&lt;a href="http://technorati.com/tags/browser" rel="tag"&gt;browser&lt;/a&gt;&lt;/div&gt;
&lt;script src="http://track.mybloglog.com/js/jsserv.php?mblID=2008070914270355" type="text/javascript"&gt;&lt;/script&gt;&lt;script src="http://feeds.feedburner.com/~s/f5/XOwx" type="text/javascript" charset="utf-8"&gt;&lt;/script&gt;&lt;script src="http://feeds.feedburner.com/~d/static/site-tracker.js" type="text/javascript" charset="utf-8"&gt;&lt;/script&gt;&lt;script src="http://feeds.feedburner.com/~d/static/site-tracker.js" type="text/javascript" charset="utf-8"&gt;&lt;/script&gt;&lt;div class='blogtags'&gt;&lt;/div&gt;&lt;img src="http://devcentral.f5.com/weblogs/macvittie/aggbug/3599.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Lori MacVittie</dc:creator>
            <guid>http://devcentral.f5.com/weblogs/macvittie/archive/2008/09/09/3599.aspx</guid>
            <pubDate>Tue, 09 Sep 2008 10:31:35 GMT</pubDate>
            <wfw:comment>http://devcentral.f5.com/weblogs/macvittie/comments/3599.aspx</wfw:comment>
            <comments>http://devcentral.f5.com/weblogs/macvittie/archive/2008/09/09/3599.aspx#feedback</comments>
            <wfw:commentRss>http://devcentral.f5.com/weblogs/macvittie/comments/commentRss/3599.aspx</wfw:commentRss>
            <trackback:ping>http://devcentral.f5.com/weblogs/macvittie/services/trackbacks/3599.aspx</trackback:ping>
        </item>
        <item>
            <title>Layer 7 Switching + Load Balancing = Layer 7 Load Balancing</title>
            <link>http://devcentral.f5.com/weblogs/macvittie/archive/2008/08/12/3529.aspx</link>
            <description>&lt;p&gt;Modern load balancers (application delivery controllers) blend traditional load-balancing capabilities with advanced, application aware layer 7 switching to support the design of a highly scalable, optimized application delivery network. Here's the difference between the two technologies, and the benefits of combining the two into a single application delivery controller. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;LOAD BALANCING&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.f5.com/glossary/load-balancing.html"&gt;Load balancing&lt;/a&gt; is the process of balancing load (application requests) across a number of servers. The load balancer presents to the outside world a "virtual server" that accepts requests on behalf of a pool (also called a cluster or farm) &lt;a href="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/WindowsLiveWriter/Layer7SwitchingversusLoadBalancing_8AEE/loadbalancing_2.jpg"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; margin: 0px 10px 0px 0px; border-right-width: 0px" height="332" alt="loadbalancing" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/WindowsLiveWriter/Layer7SwitchingversusLoadBalancing_8AEE/loadbalancing_thumb.jpg" width="284" align="left" border="0" /&gt;&lt;/a&gt;of servers and distributes those requests across all servers based on a load-balancing algorithm. All servers in the pool must contain the same content. &lt;/p&gt;  &lt;p&gt;Load balancers generally use one of several industry standard algorithms to distribute request. Some of the most common standard load balancing algorithms are: &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;em&gt;round-robin &lt;/em&gt;&lt;/li&gt;    &lt;li&gt;&lt;em&gt;weighted round-robin &lt;/em&gt;&lt;/li&gt;    &lt;li&gt;&lt;em&gt;least connections &lt;/em&gt;&lt;/li&gt;    &lt;li&gt;&lt;em&gt;weighted least connections &lt;/em&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Load balancers are used to increase the capacity of a web site or application, ensure availability through failover capabilities, and to improve application performance. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;LAYER 7 SWITCHING&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://devcentral.f5.com/weblogs/macvittie/archive/2008/05/28/3301.aspx"&gt;Layer 7 switching&lt;/a&gt; takes its name from the OSI model, indicating that the device switches requests based on layer 7 (application) data. Layer 7 switching is also known as "request switching", "application switching", and "content based routing". &lt;/p&gt;  &lt;p&gt;&lt;a href="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/WindowsLiveWriter/Layer7SwitchingversusLoadBalancing_8AEE/appswitching_2.jpg"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="315" alt="appswitching" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/WindowsLiveWriter/Layer7SwitchingversusLoadBalancing_8AEE/appswitching_thumb.jpg" width="269" align="right" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;A layer 7 switch presents to the outside world a "virtual server" that accepts requests on behalf of a number of servers and distributes those requests based on policies that use application data to determine which server should service which request. This allows for the application infrastructure to be specifically tuned/optimized to serve specific types of content. For example, one server can be tuned to serve only images, another for execution of server-side scripting languages like PHP and ASP, and another for static content such as &lt;span class="acronym" title="HyperText Markup Language"&gt;HTML&lt;/span&gt; , &lt;span class="acronym" title="Cascading Style Sheet"&gt;CSS&lt;/span&gt; , and JavaScript. &lt;/p&gt;  &lt;p&gt;Unlike load balancing, layer 7 switching does not require that all servers in the pool (farm/&lt;a href="http://devcentral.f5.com/weblogs/macvittie/archive/2007/09/25/2953.aspx"&gt;cluster&lt;/a&gt;) have the same content. In fact, layer 7 switching expects that servers will have different content, thus the need to more deeply inspect requests before determining where they should be directed. Layer 7 switches are capable of &lt;a href="http://devcentral.f5.com/weblogs/macvittie/archive/2008/03/06/3099.aspx"&gt;directing requests based on URI&lt;/a&gt;, host, HTTP headers, and anything in the application message. &lt;/p&gt;  &lt;p&gt;The latter capability is what gives layer 7 switches the ability to perform &lt;a href="http://devcentral.f5.com/weblogs/macvittie/archive/2007/11/14/2989.aspx"&gt;content based routing for ESBs&lt;/a&gt; and XML/SOAP services. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;LAYER 7 LOAD BALANCING&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;By combining load balancing with layer 7 switching, we arrive at layer 7 load balancing, a core capability of all modern load balancers (a.k.a. application &lt;a href="http://www.f5.com/products/big-ip"&gt;delivery controllers&lt;/a&gt;). &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;a href="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/WindowsLiveWriter/Layer7SwitchingversusLoadBalancing_8AEE/layer7loadbalancing_2.jpg"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; margin: 0px 10px 0px 0px; border-right-width: 0px" height="313" alt="layer7loadbalancing" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/WindowsLiveWriter/Layer7SwitchingversusLoadBalancing_8AEE/layer7loadbalancing_thumb.jpg" width="372" align="left" border="0" /&gt;&lt;/a&gt;&lt;/strong&gt;Layer 7 load balancing combines the standard load balancing features of a load balancing to provide failover and improved capacity for specific types of content. This allows the architect to design an application delivery network that is highly optimized to serve specific types of content but is also highly available. &lt;/p&gt;  &lt;p&gt;Layer 7 load balancing allows for additional features offered by application delivery controllers to be applied based on content type, which further improves performance by executing only those policies that are applicable to the content. For example, data security in the form of &lt;a href="http://www.f5.com/products/big-ip/product-modules/application-security-manager.html"&gt;data scrubbing&lt;/a&gt; is likely not necessary on JPG or GIF images, so it need only be applied to HTML and PHP. &lt;/p&gt;  &lt;p&gt;Layer 7 load balancing also allows for increased efficiency of the application infrastructure. For example, only two highly tuned image servers may be required to meet application performance and user concurrency needs, while three or four optimized servers may be necessary to meet the same requirements for PHP or ASP scripting services. Being able to separate out content based on type, URI, or data allows for better allocation of physical resources in the application infrastructure. &lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://twitter.com/lmacvittie"&gt;&lt;img height="18" alt="Follow me on Twitter" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_twitt-twoo-icon.png" width="18" border="0" /&gt;&lt;/a&gt; &lt;a href="http://devcentral.f5.com/weblogs/macvittie/Rss.aspx"&gt;&lt;img src="http://devcentral.f5.com/Portals/0/images/Icons/icon_xml_18.gif" border="0" /&gt;&lt;/a&gt;&lt;a href="http://www.slideshare.net/lmacvittie"&gt;&lt;img height="18" alt="View Lori's profile on SlideShare" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_slideshare.png" width="18" border="0" /&gt;&lt;/a&gt;&lt;a href="http://lmacvittie.tumblr.com" border="0"&gt;&lt;img title="Follow me on Tumblr" height="18" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_tumblr.gif" width="18" border="0" /&gt;&lt;/a&gt; &lt;a href="http://lmacvittie.posterous.com/"&gt;&lt;img title="Posterous" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_posterous.png" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.linkedin.com/in/lmacvittie"&gt;&lt;img src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_linkedin_16.png" border="0" /&gt;&lt;/a&gt; &lt;a title="Subscribe using any feed reader!" href="http://www.addthis.com/feed.php?pub=lmacvittie&amp;amp;h1=http%3A%2F%2Fdevcentral.f5.com%2Fweblogs%2Fmacvittie%2FRss.aspx&amp;amp;t1="&gt;&lt;img height="18" alt="AddThis Feed Button" src="http://s9.addthis.com/button1-fd.gif" width="125" border="0" /&gt;&lt;/a&gt; &lt;a title="Bookmark and Share" onclick="window.open('http://www.addthis.com/bookmark.php?wt=nw&amp;amp;pub=lmacvittie&amp;amp;url='+encodeURIComponent(location.href)+'&amp;amp;title='+encodeURIComponent(document.title), 'addthis', 'scrollbars=yes,menubar=no,width=620,height=520,resizable=yes,toolbar=no,location=no,status=no,screenX=200,screenY=100,left=200,top=100'); return false;" href="http://www.addthis.com/bookmark.php" target="_blank"&gt;&lt;img height="18" alt="Bookmark and Share" src="http://s9.addthis.com/button1-share.gif" width="125" border="0" /&gt;&lt;/a&gt;&lt;script src="http://w.sharethis.com/widget/?tabs=web%2Cpost%2Cemail&amp;amp;charset=utf-8&amp;amp;style=default&amp;amp;publisher=b38ba4d2-6d9c-465a-98d8-a7f5fdb0abb6" type="text/javascript"&gt;&lt;/script&gt;&lt;span id="sharethis_0"&gt; &lt;/span&gt;&lt;/p&gt; &lt;script src="http://track.mybloglog.com/js/jsserv.php?mblID=2008070914270355" type="text/javascript"&gt;&lt;/script&gt;&lt;script src="http://feeds.feedburner.com/~s/f5/XOwx" type="text/javascript" charset="utf-8"&gt;&lt;/script&gt;&lt;script src="http://feeds.feedburner.com/~d/static/site-tracker.js" type="text/javascript" charset="utf-8"&gt;&lt;/script&gt;&lt;script src="http://feeds.feedburner.com/~d/static/site-tracker.js" type="text/javascript" charset="utf-8"&gt;&lt;/script&gt;  &lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:958fc5ce-ce0b-4d73-ae77-dcb7d3f862f1" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/MacVittie" rel="tag"&gt;MacVittie&lt;/a&gt;,&lt;a href="http://technorati.com/tags/F5" rel="tag"&gt;F5&lt;/a&gt;,&lt;a href="http://technorati.com/tags/load-balancing" rel="tag"&gt;load-balancing&lt;/a&gt;,&lt;a href="http://technorati.com/tags/layer%207%20switching" rel="tag"&gt;layer 7 switching&lt;/a&gt;,&lt;a href="http://technorati.com/tags/application%20delivery" rel="tag"&gt;application delivery&lt;/a&gt;,&lt;a href="http://technorati.com/tags/application%20switching" rel="tag"&gt;application switching&lt;/a&gt;,&lt;a href="http://technorati.com/tags/SOA" rel="tag"&gt;SOA&lt;/a&gt;,&lt;a href="http://technorati.com/tags/XML" rel="tag"&gt;XML&lt;/a&gt;,&lt;a href="http://technorati.com/tags/SOA%20delivery" rel="tag"&gt;SOA delivery&lt;/a&gt;,&lt;a href="http://technorati.com/tags/clustering" rel="tag"&gt;clustering&lt;/a&gt;&lt;/div&gt; &lt;script src="http://track.mybloglog.com/js/jsserv.php?mblID=2008070914270355" type="text/javascript"&gt;&lt;/script&gt;&lt;script src="http://feeds.feedburner.com/~s/f5/XOwx" type="text/javascript" charset="utf-8"&gt;&lt;/script&gt;&lt;script src="http://feeds.feedburner.com/~d/static/site-tracker.js" type="text/javascript" charset="utf-8"&gt;&lt;/script&gt;&lt;script src="http://feeds.feedburner.com/~d/static/site-tracker.js" type="text/javascript" charset="utf-8"&gt;&lt;/script&gt;&lt;div class='blogtags'&gt;&lt;/div&gt;&lt;img src="http://devcentral.f5.com/weblogs/macvittie/aggbug/3529.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Lori MacVittie</dc:creator>
            <guid>http://devcentral.f5.com/weblogs/macvittie/archive/2008/08/12/3529.aspx</guid>
            <pubDate>Tue, 12 Aug 2008 11:44:57 GMT</pubDate>
            <wfw:comment>http://devcentral.f5.com/weblogs/macvittie/comments/3529.aspx</wfw:comment>
            <comments>http://devcentral.f5.com/weblogs/macvittie/archive/2008/08/12/3529.aspx#feedback</comments>
            <wfw:commentRss>http://devcentral.f5.com/weblogs/macvittie/comments/commentRss/3529.aspx</wfw:commentRss>
            <trackback:ping>http://devcentral.f5.com/weblogs/macvittie/services/trackbacks/3529.aspx</trackback:ping>
        </item>
        <item>
            <title>The Treachery of Hyperlinks</title>
            <link>http://devcentral.f5.com/weblogs/macvittie/archive/2008/08/08/3527.aspx</link>
            <description>&lt;p&gt;&lt;a href="http://devcentral.f5.com/weblogs/macvittie"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="347" alt="notablog" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/WindowsLiveWriter/Cestnespasuneblogpost_11243/notablog_2.jpg" width="519" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;With apologies to &lt;a href="http://en.wikipedia.org/wiki/Ren%C3%A9_Magritte"&gt;René Magritte&lt;/a&gt;.  &lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;Did you know you could stop the treachery that is &lt;a href="http://en.wikipedia.org/wiki/Rickroll"&gt;Rickrolling&lt;/a&gt; hyperlinks with an &lt;a href="http://devcentral.f5.com/Default.aspx?tabid=75"&gt;iRule&lt;/a&gt;? Just search your outbound HTML for the appropriate &lt;a href="http://www.youtube.com"&gt;YouTube&lt;/a&gt; URLs (you may need a data group to store them all) and strip them out, or search your inbound posts for the URLs and refuse to post them. &lt;/p&gt;  &lt;p&gt;Of course you could also write an iRule that automatically changes every submitted URL to be a rickroll, but man, that's evil! Maybe you just want to do it for a specific user. You can do that with iRules if your site uses cookies to identify users by id or name. Just check the cookie and if you find the right user, fire off the appropriate iRule code to replace the URLs before it's posted. &lt;/p&gt;  &lt;p&gt;It would still be evil. But it would be funny evil, if you know what I mean. &lt;/p&gt;  &lt;p&gt;&lt;a href="http://twitter.com/lmacvittie"&gt;&lt;img height="18" alt="Follow me on Twitter" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_twitt-twoo-icon.png" width="18" border="0" /&gt;&lt;/a&gt; &lt;a href="http://devcentral.f5.com/weblogs/macvittie/Rss.aspx"&gt;&lt;img src="http://devcentral.f5.com/Portals/0/images/Icons/icon_xml_18.gif" border="0" /&gt;&lt;/a&gt;&lt;a href="http://www.slideshare.net/lmacvittie"&gt;&lt;img height="18" alt="View Lori's profile on SlideShare" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_slideshare.png" width="18" border="0" /&gt;&lt;/a&gt;&lt;a href="http://lmacvittie.tumblr.com" border="0"&gt;&lt;img title="Follow me on Tumblr" height="18" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_tumblr.gif" width="18" border="0" /&gt;&lt;/a&gt; &lt;a href="http://lmacvittie.posterous.com/"&gt;&lt;img title="Posterous" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_posterous.png" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.linkedin.com/in/lmacvittie"&gt;&lt;img src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_linkedin_16.png" border="0" /&gt;&lt;/a&gt; &lt;a title="Subscribe using any feed reader!" href="http://www.addthis.com/feed.php?pub=lmacvittie&amp;amp;h1=http%3A%2F%2Fdevcentral.f5.com%2Fweblogs%2Fmacvittie%2FRss.aspx&amp;amp;t1="&gt;&lt;img height="18" alt="AddThis Feed Button" src="http://s9.addthis.com/button1-fd.gif" width="125" border="0" /&gt;&lt;/a&gt; &lt;a title="Bookmark and Share" onclick="window.open('http://www.addthis.com/bookmark.php?wt=nw&amp;amp;pub=lmacvittie&amp;amp;url='+encodeURIComponent(location.href)+'&amp;amp;title='+encodeURIComponent(document.title), 'addthis', 'scrollbars=yes,menubar=no,width=620,height=520,resizable=yes,toolbar=no,location=no,status=no,screenX=200,screenY=100,left=200,top=100'); return false;" href="http://www.addthis.com/bookmark.php" target="_blank"&gt;&lt;img height="18" alt="Bookmark and Share" src="http://s9.addthis.com/button1-share.gif" width="125" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:f8a32eed-9d97-45aa-8c24-aedf7ecf27b5" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/MacVittie" rel="tag"&gt;MacVittie&lt;/a&gt;,&lt;a href="http://technorati.com/tags/surrealism" rel="tag"&gt;surrealism&lt;/a&gt;,&lt;a href="http://technorati.com/tags/art" rel="tag"&gt;art&lt;/a&gt;,&lt;a href="http://technorati.com/tags/magritte" rel="tag"&gt;magritte&lt;/a&gt;,&lt;a href="http://technorati.com/tags/iRules" rel="tag"&gt;iRules&lt;/a&gt;,&lt;a href="http://technorati.com/tags/transformation" rel="tag"&gt;transformation&lt;/a&gt;,&lt;a href="http://technorati.com/tags/rickroll" rel="tag"&gt;rickroll&lt;/a&gt;&lt;/div&gt; &lt;script src="http://track.mybloglog.com/js/jsserv.php?mblID=2008070914270355" type="text/javascript"&gt;&lt;/script&gt;&lt;div class='blogtags'&gt;&lt;/div&gt;&lt;img src="http://devcentral.f5.com/weblogs/macvittie/aggbug/3527.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Lori MacVittie</dc:creator>
            <guid>http://devcentral.f5.com/weblogs/macvittie/archive/2008/08/08/3527.aspx</guid>
            <pubDate>Fri, 08 Aug 2008 10:59:50 GMT</pubDate>
            <wfw:comment>http://devcentral.f5.com/weblogs/macvittie/comments/3527.aspx</wfw:comment>
            <comments>http://devcentral.f5.com/weblogs/macvittie/archive/2008/08/08/3527.aspx#feedback</comments>
            <slash:comments>2</slash:comments>
            <wfw:commentRss>http://devcentral.f5.com/weblogs/macvittie/comments/commentRss/3527.aspx</wfw:commentRss>
            <trackback:ping>http://devcentral.f5.com/weblogs/macvittie/services/trackbacks/3527.aspx</trackback:ping>
        </item>
        <item>
            <title>Working around client-side limitations on custom HTTP headers</title>
            <link>http://devcentral.f5.com/weblogs/macvittie/archive/2008/08/06/3519.aspx</link>
            <description>&lt;p&gt;One of the most well-kept secrets in technology is the extensibility of &lt;a href="http://www.w3.org/Protocols/" target="_blank"&gt;HTTP&lt;/a&gt;. It's one of the reasons it became the &lt;a href="http://devcentral.f5.com/weblogs/macvittie/archive/2008/05/21/3283.aspx" target="_blank"&gt;de facto application transport protocol&lt;/a&gt; and it was instrumental in getting &lt;a href="http://www.w3.org/TR/soap/" target="_blank"&gt;SOAP&lt;/a&gt; off the ground before &lt;a href="http://www.w3.org/TR/soap12-part1/"&gt;SOAP 1.2&lt;/a&gt; and &lt;a href="http://www.ws-i.org/Profiles/BasicProfile"&gt;WS-I Basic Profile&lt;/a&gt; made the requirement for the &lt;em&gt;SOAP Action&lt;/em&gt; header obsolete. &lt;/p&gt;  &lt;p&gt;Web browsers aren't capable of adding custom HTTP headers on their own; that functionality comes from the use of client-side scripting languages such as &lt;a href="http://www.ecma-international.org/publications/standards/Ecma-262.htm"&gt;JavaScript&lt;/a&gt; or &lt;a href="http://msdn.microsoft.com/en-us/library/t0aew7h6.aspx"&gt;VBScript&lt;/a&gt;. Other RIA (Rich Internet Applications) client platforms such as &lt;a href="http://www.adobe.com/products/air/"&gt;Adobe AIR&lt;/a&gt; and &lt;a href="http://www.adobe.com/products/flash/ "&gt;Flash&lt;/a&gt; are also capable of adding HTTP headers, though both have &lt;a href="http://fupeg.blogspot.com/2008/02/setting-custom-http-headers-in-flash.html"&gt;limitations&lt;/a&gt; on which (if any) &lt;a href="http://kb.adobe.com/selfservice/viewContent.do?externalId=2217621d"&gt;custom headers you can use&lt;/a&gt;. &lt;/p&gt;  &lt;p&gt;&lt;a href="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/WindowsLiveWriter/UsingcustomHTTPheaderstomanageserviceacc_6F34/code%20small_2.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; margin: 0px 10px 0px 0px; border-left: 0px; border-bottom: 0px" height="180" alt="code small" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/WindowsLiveWriter/UsingcustomHTTPheaderstomanageserviceacc_6F34/code%20small_thumb.jpg" width="240" align="left" border="0" /&gt;&lt;/a&gt; There are valid reasons for wanting to set a custom header. The most common use of custom HTTP headers is to preserve in some way the source IP address of the client for logging purposes in a load-balanced environment using the &lt;a href="http://devcentral.f5.com/weblogs/macvittie/archive/2008/06/02/3323.aspx"&gt;X-Forwarded-For&lt;/a&gt; custom header.  Custom HTTP headers can be set by the client or set by the server or intermediary (&lt;a href="http://www.f5.com/products/big-ip"&gt;load-balancer&lt;/a&gt;, &lt;a href="http://www.f5.com/products/big-ip"&gt;application delivery controller&lt;/a&gt;, &lt;a href="http://www.f5.com/products/big-ip/product-modules/webaccelerator.html"&gt;cache&lt;/a&gt;) as well and often are to indicate that the content has passed through a proxy. A quick perusal of the web shows developers desiring to use custom HTTP headers for a variety of reasons including security, SSO (single sign on) functionality, and to transfer data between pages/applications. &lt;/p&gt;  &lt;p&gt;Unfortunately, a class of vulnerabilities known as "&lt;a href="http://en.wikipedia.org/wiki/HTTP_Header_Injection "&gt;HTTP header injection&lt;/a&gt;" often causes platform providers like &lt;a href="http://www.adobe.com"&gt;Adobe&lt;/a&gt; to limit or completely remove the ability to manipulate HTTP headers on the client. And adding custom headers using JavaScript or VBScript may require modification of the application and relies on the user allowing scripts to run in the first place, the consistency of which can no longer be relied upon. &lt;/p&gt;  &lt;p&gt;But what if you really need those custom headers to either address a problem or enable some functionality? &lt;/p&gt;  &lt;p&gt;All is not lost; you can generally use an &lt;a href="http://www.f5.com/products/big-ip"&gt;intelligent proxy-based load balancer (application delivery controller)&lt;/a&gt; to insert the headers for you.If the load balancer/application delivery controller has the ability to inspect requests and modify the requests and responses with a technology like &lt;a href="http://devcentral.f5.com/Default.aspx?tabid=75"&gt;iRules&lt;/a&gt;, you can easily add your custom headers at the intermediary without losing the functionality desired or needing to &lt;a href="http://fupeg.blogspot.com/2008/02/setting-custom-http-headers-in-flash.html"&gt;change the request method from GET to POST&lt;/a&gt;, as some have done to get around these limitations.&lt;/p&gt;  &lt;p&gt;Using your load balancer/application delivery controller to insert, delete, or modify custom HTTP headers has other advantages as well: &lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;You don't need to modify the client or the server-side application or script that served the client &lt;/li&gt;    &lt;li&gt;The load balancer can add the required custom HTTP header(s) for all applications at one time in one place&lt;/li&gt;    &lt;li&gt;Your application will still work even if the client disables scripting &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Custom HTTP headers are often used for valid reasons when developing applications. The inability to manipulate them easily on the client can interfere with the development lifecycle and make it more difficult to address vulnerabilities and quirks with packaged applications and the platforms on which applications are often deployed. Taking advantage of more advanced features available in &lt;a href="http://devcentral.f5.com/weblogs/macvittie/archive/2008/06/11/3352.aspx"&gt;modern load balancers/application delivery controllers&lt;/a&gt; makes implementing such workarounds simple. &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://twitter.com/lmacvittie"&gt;&lt;img height="18" alt="Follow me on Twitter" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_twitt-twoo-icon.png" width="18" border="0" /&gt;&lt;/a&gt; &lt;a href="http://devcentral.f5.com/weblogs/macvittie/Rss.aspx"&gt;&lt;img src="http://devcentral.f5.com/Portals/0/images/Icons/icon_xml_18.gif" border="0" /&gt;&lt;/a&gt;&lt;a href="http://www.slideshare.net/lmacvittie"&gt;&lt;img height="18" alt="View Lori's profile on SlideShare" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_slideshare.png" width="18" border="0" /&gt;&lt;/a&gt;&lt;a href="http://lmacvittie.tumblr.com" border="0"&gt;&lt;img title="Follow me on Tumblr" height="18" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_tumblr.gif" width="18" border="0" /&gt;&lt;/a&gt; &lt;a href="http://lmacvittie.posterous.com/"&gt;&lt;img title="Posterous" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_posterous.png" border="0" /&gt;&lt;/a&gt; &lt;a href="http://www.linkedin.com/in/lmacvittie"&gt;&lt;img src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_linkedin_16.png" border="0" /&gt;&lt;/a&gt; &lt;a title="Subscribe using any feed reader!" href="http://www.addthis.com/feed.php?pub=lmacvittie&amp;amp;h1=http%3A%2F%2Fdevcentral.f5.com%2Fweblogs%2Fmacvittie%2FRss.aspx&amp;amp;t1="&gt;&lt;img height="18" alt="AddThis Feed Button" src="http://s9.addthis.com/button1-fd.gif" width="125" border="0" /&gt;&lt;/a&gt; &lt;a title="Bookmark and Share" onclick="window.open('http://www.addthis.com/bookmark.php?wt=nw&amp;amp;pub=lmacvittie&amp;amp;url='+encodeURIComponent(location.href)+'&amp;amp;title='+encodeURIComponent(document.title), 'addthis', 'scrollbars=yes,menubar=no,width=620,height=520,resizable=yes,toolbar=no,location=no,status=no,screenX=200,screenY=100,left=200,top=100'); return false;" href="http://www.addthis.com/bookmark.php" target="_blank"&gt;&lt;img height="18" alt="Bookmark and Share" src="http://s9.addthis.com/button1-share.gif" width="125" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:23a6dc30-f2de-4ad8-99e0-6a25396c8b4a" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/MacVittie" rel="tag"&gt;MacVittie&lt;/a&gt;,&lt;a href="http://technorati.com/tags/F5" rel="tag"&gt;F5&lt;/a&gt;,&lt;a href="http://technorati.com/tags/iRules" rel="tag"&gt;iRules&lt;/a&gt;,&lt;a href="http://technorati.com/tags/HTTP" rel="tag"&gt;HTTP&lt;/a&gt;,&lt;a href="http://technorati.com/tags/internet" rel="tag"&gt;internet&lt;/a&gt;,&lt;a href="http://technorati.com/tags/web" rel="tag"&gt;web&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Adobe%20Flash" rel="tag"&gt;Adobe Flash&lt;/a&gt;,&lt;a href="http://technorati.com/tags/JavaScript" rel="tag"&gt;JavaScript&lt;/a&gt;,&lt;a href="http://technorati.com/tags/VBScript" rel="tag"&gt;VBScript&lt;/a&gt;,&lt;a href="http://technorati.com/tags/script" rel="tag"&gt;script&lt;/a&gt;,&lt;a href="http://technorati.com/tags/custom" rel="tag"&gt;custom&lt;/a&gt;,&lt;a href="http://technorati.com/tags/development" rel="tag"&gt;development&lt;/a&gt;,&lt;a href="http://technorati.com/tags/architecture" rel="tag"&gt;architecture&lt;/a&gt;,&lt;a href="http://technorati.com/tags/proxy" rel="tag"&gt;proxy&lt;/a&gt;,&lt;a href="http://technorati.com/tags/AIR" rel="tag"&gt;AIR&lt;/a&gt;,&lt;a href="http://technorati.com/tags/http%20headers" rel="tag"&gt;http headers&lt;/a&gt;&lt;/div&gt; &lt;script src="http://track.mybloglog.com/js/jsserv.php?mblID=2008070914270355" type="text/javascript"&gt;&lt;/script&gt;&lt;div class='blogtags'&gt;&lt;/div&gt;&lt;img src="http://devcentral.f5.com/weblogs/macvittie/aggbug/3519.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Lori MacVittie</dc:creator>
            <guid>http://devcentral.f5.com/weblogs/macvittie/archive/2008/08/06/3519.aspx</guid>
            <pubDate>Wed, 06 Aug 2008 11:07:14 GMT</pubDate>
            <wfw:comment>http://devcentral.f5.com/weblogs/macvittie/comments/3519.aspx</wfw:comment>
            <comments>http://devcentral.f5.com/weblogs/macvittie/archive/2008/08/06/3519.aspx#feedback</comments>
            <slash:comments>1</slash:comments>
            <wfw:commentRss>http://devcentral.f5.com/weblogs/macvittie/comments/commentRss/3519.aspx</wfw:commentRss>
            <trackback:ping>http://devcentral.f5.com/weblogs/macvittie/services/trackbacks/3519.aspx</trackback:ping>
        </item>
        <item>
            <title>API Request Throttling: A Better Option</title>
            <link>http://devcentral.f5.com/weblogs/macvittie/archive/2008/06/30/3412.aspx</link>
            <description>&lt;p&gt;This past week there's been &lt;a href="http://blog.twhirl.org/2008/06/27/twhirl-and-the-twitter-api-rate-limit/" target="_blank"&gt;some interesting commentary&lt;/a&gt; regarding &lt;a href="http://www.twitter.com" target="_blank"&gt;Twitter's&lt;/a&gt; change to its API &lt;a href="http://willfjohnston.com/2008/05/24/twitter-api-lowers-authenticated-request-limit-to-30-per-hour/" target="_blank"&gt;request throttling feature&lt;/a&gt;. Request throttling, often used as a method to ensure QoS (Quality of Service) for a variety of network and application uses, is used by &lt;a href="http://www.twitter.com" target="_blank"&gt;Twitter&lt;/a&gt; as an attempt to not overwhelm the system such that they are forced to display the now (in)famous Twitter fail whale image. &lt;/p&gt;  &lt;p&gt;One of the things you can do with a &lt;a href="http://www.f5.com/products/big-ip" target="_blank"&gt;BIG-IP Local Traffic Manager (LTM)&lt;/a&gt; and &lt;a href="http://devcentral.f5.com/Default.aspx?tabid=75" target="_blank"&gt;iRules&lt;/a&gt; is request throttling. Why would you want to let a mediating device like an application delivery controller control request throttling? Because request throttling implemented by the server still requires the server to respond to the request. The act of responding wastes some of the resources you're trying to save by request throttling in the first place. &lt;/p&gt;  &lt;p&gt;It's like taking two steps forward and one back. By allowing the application delivery controller to manage throttling requests you're relieving the burden on the servers and freeing up resources so the servers can do what they're designed to do: serve content. &lt;/p&gt;  &lt;p&gt;&lt;img style="margin: 5px 10px 5px 0px" height="172" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_ideabulb.jpg" width="153" align="left" /&gt; Because an intermediary that is also a full proxy (like &lt;a href="http://www.f5.com/products/big-ip" target="_blank"&gt;BIG-IP LTM&lt;/a&gt;) terminates the TCP connection on the client side, it does not need to bother the server in the case that a client has exceeded their allotted request usage. Now you might be thinking that such a solution would be fine for an entire site, but Twitter (and others) use request throttling on a &lt;em&gt;per API call &lt;/em&gt;basis, not the entire site, and wouldn't a general solution stop people from even connecting to twitter.com in general?&lt;/p&gt;  &lt;p&gt;It depends on the implementation. In the case of &lt;a href="http://www.f5.com/products/big-ip" target="_blank"&gt;BIG-IP&lt;/a&gt; and &lt;a href="http://devcentral.f5.com/Default.aspx?tabid=75" target="_blank"&gt;iRules&lt;/a&gt;, request throttling can be done on a per virtual server (usually corresponding to a single "web site") basis or it can get as granular as specific URIs. In the case of a site with an API like twitter, the URIs generally correspond to their REST-based APIs. That means not only can you throttle requests in general, but you could get even more specific and throttle requests based on specific API calls. If one of the API calls is particularly resource-intensive, you could limit it further than those that are less resource intensive. So while querying may be limited to 40 request per hour, perhaps updating is limited to 30. Or vice-versa. The ability to inspect, detect, and direct messages lets you get as specific as you want - or need - according to the needs of your application and your specific architecture. &lt;/p&gt;  &lt;p&gt;It really gets interesting when you consider that you could further make decisions based on parameters, such as a specific user and the application function. Because an intelligent application delivery controller can inspect messages both on request &lt;em&gt;and &lt;/em&gt;reply, you can use information that may be returned from a specific request to control the way future requests are handled, whether that's permanently or for a specified time interval. &lt;/p&gt;  &lt;p&gt;This kind of functionality is also excellent for service providers moving services to tiers, i.e. "premium (paid) services". By indicating the level of service that should be provided to a given user, usually by setting a &lt;a href="http://devcentral.f5.com/weblogs/macvittie/archive/2008/06/04/3329.aspx" target="_blank"&gt;cookie&lt;/a&gt;, &lt;a href="http://www.f5.com/products/big-ip" target="_blank"&gt;BIG-IP&lt;/a&gt; can dynamically apply the appropriate request throttling to that user's service. The reason this is exciting is because it can be done transparently - without modifying the application itself. That means changes in business models can be implemented faster and with less interruption. &lt;/p&gt;  &lt;p&gt;As an example, here's a simple iRule that throttles HTTP requests to 3 per second per client. Simple, effective, transparent to the servers. Thanks to our guys in the field for writing this one and sharing! &lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;when HTTP_REQUEST {&lt;/p&gt;    &lt;p&gt;    set cur_time [clock seconds]&lt;/p&gt;    &lt;p&gt;    if { [HTTP::request_num] &amp;gt; 1 } {&lt;/p&gt;    &lt;p&gt;       if { $cur_time == $start_time } {&lt;/p&gt;    &lt;p&gt;          if { $reqs_sec &amp;gt; 3 } {&lt;/p&gt;    &lt;p&gt;             HTTP::respond 503 Retry-After 2&lt;/p&gt;    &lt;p&gt;          }&lt;/p&gt;    &lt;p&gt;          incr reqs_sec&lt;/p&gt;    &lt;p&gt;          return&lt;/p&gt;    &lt;p&gt;       }&lt;/p&gt;    &lt;p&gt;    }&lt;/p&gt;    &lt;p&gt;    set start_time $cur_time&lt;/p&gt;    &lt;p&gt;    set reqs_sec 0&lt;/p&gt;    &lt;p&gt;}&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;It doesn't make sense to implement request throttling inside an application when the reason you're implementing it is because the servers are overwhelmed. Let an intermediary, an application delivery controller, do it for you. &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://twitter.com/lmacvittie"&gt;&lt;img height="18" alt="Follow me on Twitter" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_twitt-twoo-icon.png" width="18" border="0" /&gt;&lt;/a&gt; &lt;a href="http://devcentral.f5.com/weblogs/macvittie/Rss.aspx"&gt;&lt;img src="http://devcentral.f5.com/Portals/0/images/Icons/icon_xml_18.gif" border="0" /&gt;&lt;/a&gt;&lt;a href="http://www.slideshare.net/lmacvittie"&gt;&lt;img height="18" alt="View Lori's profile on SlideShare" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_slideshare.png" width="18" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:aa828a21-c1c8-462c-bd1c-2081f57d95dc" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/MacVittie" rel="tag"&gt;MacVittie&lt;/a&gt;,&lt;a href="http://technorati.com/tags/F5" rel="tag"&gt;F5&lt;/a&gt;,&lt;a href="http://technorati.com/tags/BIG-IP" rel="tag"&gt;BIG-IP&lt;/a&gt;,&lt;a href="http://technorati.com/tags/iRules" rel="tag"&gt;iRules&lt;/a&gt;,&lt;a href="http://technorati.com/tags/request%20throttling" rel="tag"&gt;request throttling&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Twitter" rel="tag"&gt;Twitter&lt;/a&gt;,&lt;a href="http://technorati.com/tags/QoS" rel="tag"&gt;QoS&lt;/a&gt;&lt;/div&gt;&lt;div class='blogtags'&gt;&lt;/div&gt;&lt;img src="http://devcentral.f5.com/weblogs/macvittie/aggbug/3412.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Lori MacVittie</dc:creator>
            <guid>http://devcentral.f5.com/weblogs/macvittie/archive/2008/06/30/3412.aspx</guid>
            <pubDate>Mon, 30 Jun 2008 10:43:11 GMT</pubDate>
            <wfw:comment>http://devcentral.f5.com/weblogs/macvittie/comments/3412.aspx</wfw:comment>
            <comments>http://devcentral.f5.com/weblogs/macvittie/archive/2008/06/30/3412.aspx#feedback</comments>
            <slash:comments>1</slash:comments>
            <wfw:commentRss>http://devcentral.f5.com/weblogs/macvittie/comments/commentRss/3412.aspx</wfw:commentRss>
            <trackback:ping>http://devcentral.f5.com/weblogs/macvittie/services/trackbacks/3412.aspx</trackback:ping>
        </item>
        <item>
            <title>Green IT: 404 Blacklisting</title>
            <link>http://devcentral.f5.com/weblogs/macvittie/archive/2008/06/27/3406.aspx</link>
            <description>&lt;p&gt;One of the premises of a greener IT is to &lt;a target="_blank" href="http://www.f5.com/pdf/white-papers/three-rs-wp.pdf"&gt;reduce the number of servers&lt;/a&gt; necessary while maintaining performance levels and meeting capacity needs. &lt;/p&gt;
&lt;p&gt;Chances are that many of the &lt;a target="_blank" href="http://www.w3.org/Protocols/rfc2616/rfc2616.html"&gt;HTTP&lt;/a&gt; requests received that result in a &lt;a target="_blank" href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html"&gt;404&lt;/a&gt; (not found) message are typos, bots, or bad guys attempting to find a way into your web applications. The thing is that the server must respond to these requests, and it often requires some disk I/O to discover the file doesn't exist. That's expensive in terms of resources and can increase the total power consumption of your servers. &lt;/p&gt;
&lt;p&gt;If you're finding enough 404 errors in your logs, and you've verified that they're accurate, i.e. the files don't - and shouldn't - exist, then you may want to consider blacklisting those requests. By blacklisting those pesky non-existent files you can obviate the need for the server to look for it, thus reducing the overall burden (and power consumption) on your servers. This equates to a better performing server, and ensures that real requests get the resources they need to be fulfilled in a timely manner. &lt;/p&gt;
&lt;p&gt;To accomplish this task, you'll need an &lt;a target="_blank" href="http://devcentral.f5.com/Default.aspx?tabid=75"&gt;iRule&lt;/a&gt; that keeps track of &lt;a target="_blank" href="http://devcentral.f5.com/wiki/default.aspx/iRules/HTTP__uri.html"&gt;URIs&lt;/a&gt; resulting in a 404 and ensures that subsequent requests for that URI are immediately "kicked back" to the user instead of passed on to the server. We'll do that dynamically, in real-time, because it's nearly impossible to guess what kind of funky URIs will be requested by users, bots, and bad guys. &lt;/p&gt;
&lt;p&gt;We'll also want to log additions to our blacklist so administrators can verify that the files in question really aren't valid files that have somehow been removed/lost. &lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;when RULE_INIT {&lt;br /&gt;   array set ::unknown_pages { }    &lt;br /&gt;}&lt;/pre&gt;
&lt;pre&gt;when HTTP_REQUEST {&lt;br /&gt;   if { [info exists ::unknown_pages([HTTP::uri])] } {&lt;br /&gt;      HTTP::respond 200 content "&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;The requested file could not be found&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;"&lt;br /&gt;&lt;br /&gt;   } else {&lt;br /&gt;   set curr_uri [HTTP::uri]&lt;br /&gt;   pool webpool&lt;br /&gt;}&lt;/pre&gt;
&lt;pre&gt;when HTTP_RESPONSE {&lt;br /&gt;  if { [HTTP::status] == "404"} {&lt;br /&gt;    set ::unknown_pages($curr_uri) 1&lt;br /&gt;    log "Added $curr_uri to the 404 blacklist" &lt;br /&gt;&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are myriad other options you could employ to make this &lt;a target="_blank" href="http://devcentral.f5.com/Default.aspx?tabid=75"&gt;iRule&lt;/a&gt; even more flexible. You could add a timestamp to any URI added to the 404 blacklist, and revalidate that it is, in fact, still missing after a specified time interval. This allows you to support the case where the file &lt;em&gt;should &lt;/em&gt;have existed, but didn't, giving IT time to resolve the problem and automatically removing the URI from the blacklist later. Or you can write another &lt;a target="_blank" href="http://devcentral.f5.com/Default.aspx?tabid=75"&gt;iRule&lt;/a&gt; that specifically removes a URI from the list, so you can manually manage the list when you need to. &lt;/p&gt;
&lt;p&gt;You could also redirect the user to a prettier "not found" page rather than responding with simple text. Just replace the HTTP::respond line with one that uses HTTP::redirect with the appropriate URL: &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;HTTP::redirect &lt;a href="http://www.example.com/sorry_page.html"&gt;http://www.example.com/sorry_page.html&lt;/a&gt; &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In general, removing unnecessary processing from your server infrastructure can reduce costs, improve performance, and increase/maintain capacity. With a flexible platform like &lt;a target="_blank" href="http://www.f5.com/products/big-ip"&gt;BIG-IP Local Traffic Manager&lt;/a&gt; and &lt;a target="_blank" href="http://devcentral.f5.com/Default.aspx?tabid=75"&gt;iRules&lt;/a&gt;, you can reduce the burden on your servers and get "greener". &lt;/p&gt;
&lt;p&gt;&lt;em&gt;Imbibing: Mountain Dew&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://twitter.com/lmacvittie"&gt;&lt;img width="20" height="20" border="0" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_twitt-twoo-icon.png" alt="Follow me on Twitter" /&gt;&lt;/a&gt;&lt;a href="http://devcentral.f5.com/weblogs/macvittie/Rss.aspx"&gt;&lt;img src="http://devcentral.f5.com/Portals/0/images/Icons/icon_xml_18.gif" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/p&gt;
&lt;div style="margin: 0px; padding: 0px; display: inline;" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:148c696b-d2f0-4946-ba53-92e674668eb1" class="wlWriterSmartContent"&gt;Technorati Tags: &lt;a rel="tag" href="http://technorati.com/tags/MacVittie"&gt;MacVittie&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/F5"&gt;F5&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/iRules"&gt;iRules&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/Green%20IT"&gt;Green IT&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/blacklisting"&gt;blacklisting&lt;/a&gt;,&lt;a rel="tag" href="http://technorati.com/tags/404"&gt;404&lt;/a&gt;&lt;/div&gt;&lt;div class='blogtags'&gt;&lt;/div&gt;&lt;img src="http://devcentral.f5.com/weblogs/macvittie/aggbug/3406.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Lori MacVittie</dc:creator>
            <guid>http://devcentral.f5.com/weblogs/macvittie/archive/2008/06/27/3406.aspx</guid>
            <pubDate>Fri, 27 Jun 2008 11:06:35 GMT</pubDate>
            <wfw:comment>http://devcentral.f5.com/weblogs/macvittie/comments/3406.aspx</wfw:comment>
            <comments>http://devcentral.f5.com/weblogs/macvittie/archive/2008/06/27/3406.aspx#feedback</comments>
            <wfw:commentRss>http://devcentral.f5.com/weblogs/macvittie/comments/commentRss/3406.aspx</wfw:commentRss>
            <trackback:ping>http://devcentral.f5.com/weblogs/macvittie/services/trackbacks/3406.aspx</trackback:ping>
        </item>
        <item>
            <title>Fixing Internet Explorer &amp;amp; AJAX</title>
            <link>http://devcentral.f5.com/weblogs/macvittie/archive/2008/06/26/3397.aspx</link>
            <description>&lt;p&gt;A few weeks ago, as developers are wont to do, I rewrote our online gameroom. Version 1 was getting crusty, and I'd written all the AJAX handlers manually and wanted to clean up the code by using &lt;a href="http://prototypejs.com/" target="_blank"&gt;Prototype&lt;/a&gt; and &lt;a href="http://script.aculo.us/" target="_blank"&gt;Script.aculo.us&lt;/a&gt;. You may recall we discussed using these tools &lt;a href="http://devcentral.f5.com/Default.aspx?tabid=63&amp;amp;articleType=ArticleView&amp;amp;articleId=218" target="_blank"&gt;to build a Web 2.0 interface&lt;/a&gt; to &lt;a href="http://devcentral.f5.com/Default.aspx?tabid=76" target="_blank"&gt;iControl&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;So I rewrote it and was pretty pleased with myself. Until one of our players asked why it wasn't working in Internet Explorer (IE). Now Version 1 hadn't worked in IE either, but because I have a captive set of users I ignored the problem and forced them all to use &lt;a href="http://www.mozilla.com/en-US/firefox/" target="_blank"&gt;FireFox&lt;/a&gt; instead. But this player's wife will be joining us soon and she's legally blind. She uses a reader to get around the Internet and as luck would have it, the reader only works with IE. &lt;/p&gt;
&lt;p&gt;So I started digging into the problem. I had thought it was&lt;em&gt; my &lt;/em&gt;code (silly me), and thus moving to prototype would solve the problem. No such luck. Everything but the periodically updated pieces of the application worked fine. The real-time updating components? Broken in IE.  &lt;/p&gt;
&lt;p&gt;I looked around and found &lt;a href="http://en.wikipedia.org/wiki/XMLHTTP#Known_problems" target="_blank"&gt;this very interesting article&lt;/a&gt; on &lt;a href="http://www.wikipedia.com" target="_blank"&gt;Wikipedia&lt;/a&gt; regarding known problems with IE and &lt;a href="http://www.w3.org/TR/XMLHttpRequest/" target="_blank"&gt;XMLHTTPRequest&lt;/a&gt;, the core of AJAX. &lt;/p&gt;
&lt;fieldset style="padding: 5px;"&gt;&lt;legend&gt;From the Wikipedia article&lt;/legend&gt;
&lt;p&gt;Most of the implementations also realize HTTP caching. Internet Explorer and Firefox do, but there is a difference in how and when the cached data is revalidated. Firefox revalidates the cached response every time the page is refreshed, issuing an "If-Modified-Since" header with value set to the value of the "Last-Modified" header of the cached response.&lt;/p&gt;
&lt;p&gt;Internet Explorer does so only if the cached response is expired (i.e., after the date of received "Expires" header).&lt;/p&gt;
&lt;/fieldset&gt;
&lt;p&gt;Basically, the problem lies with IE's caching mechanisms. So if you were trying to build an AJAX application with a real-time updating component and it didn't seem to work in IE, now you may know why that is. &lt;/p&gt;
&lt;p&gt;There are workarounds: &lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;Modify the AJAX call (within the client-side script) to check the response and, if necessary, make a second call with a Date value in the past to force the call to the server.&lt;/li&gt;
    &lt;li&gt;Append a unique query string to the call, for example appending a timestamp. This makes the URI unique, ensuring it won't be in the cache and forcing IE to call out to the server to get it.  &lt;/li&gt;
    &lt;li&gt;Change all requests to use POST instead of GET.&lt;/li&gt;
    &lt;li&gt;Force the "Expires" header to be set in the past (much in the way we expire cookies programmatically). Setting cache control headers may also help force IE to act according to expectations. &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I used option #3, because it was a simple, quick fix for me to search the single script using &lt;a href="http://www.prototypejs.org/api/ajax/periodicalupdater" target="_blank"&gt;Ajax.PeriodicalUpdater&lt;/a&gt; and automatically change all the GETs to POSTs. That may not feasible for everyone, hence the other available options. &lt;/p&gt;
&lt;p&gt;Option #4 could easily be achieved using &lt;a href="http://devcentral.f5.com/Default.aspx?tabid=75" target="_blank"&gt;iRules&lt;/a&gt;, and could be coded such that only requests sent via IE were modified. In fact, &lt;a href="http://devcentral.f5.com/weblogs/Joe/Default.aspx" target="_blank"&gt;Joe&lt;/a&gt; has a great &lt;a href="http://devcentral.f5.com/weblogs/Joe/archive/2005/10/19/1527.aspx" target="_blank"&gt;post on how to prevent caching on specific file types&lt;/a&gt; that can be easily modified to solve the problem with IE. &lt;/p&gt;
&lt;p&gt;First we want to know if the browser is IE, and if so, we want to modify the caching behavior on the response. Don't forget that &lt;a href="http://blogs.msdn.com/ie/archive/2006/09/20/763891.aspx" target="_blank"&gt;IE7 is using a slightly different User-Agent header&lt;/a&gt; than previous versions of IE. Don't look for specific versions, just try to determine if the browser is &lt;em&gt;a &lt;/em&gt;version of IE. &lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;when HTTP_REQUEST {&lt;br /&gt;  if [string tolower [HTTP::&lt;strong&gt;header&lt;/strong&gt; "&lt;strong&gt;User-Agent&lt;/strong&gt;"]] contains "msie"} {&lt;br /&gt;    set foundmatch 1&lt;br /&gt;  }&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;pre&gt;when HTTP_RESPONSE {&lt;br /&gt;  if {$foundmatch == 1} {&lt;br /&gt;    HTTP::header replace Cache-Control no-cache&lt;br /&gt;    HTTP::header replace Pragma no-cache&lt;br /&gt;    HTTP::header replace Expires -1&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;You could also use an iRule to accomplish #3 dynamically, changing the code &lt;em&gt;only &lt;/em&gt;for IE browsers instead of all browsers. This requires a bit more work as you'll have to search through the payload for 'GET' and replace it with 'POST'. It's a good idea to make the search string as specific as possible to ensure that only the HTTP methods are replaced in the &lt;a href="http://www.prototypejs.org/api/ajax/periodicalupdater" target="_blank"&gt;Ajax.PeriodicalUpdater&lt;/a&gt; calls and not everyplace the letters may appear in the document, hence the inclusion of the quotes around the methods. &lt;/p&gt;
&lt;p&gt;Happy Coding!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://twitter.com/lmacvittie"&gt;&lt;img width="18" height="18" border="0" alt="Follow me on Twitter" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_twitt-twoo-icon.png" /&gt;&lt;/a&gt;&lt;a href="http://devcentral.f5.com/weblogs/macvittie/Rss.aspx"&gt;&lt;img border="0" src="http://devcentral.f5.com/Portals/0/images/Icons/icon_xml_18.gif" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;em&gt;Imbibing: Coffee&lt;/em&gt;&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:2d6708a6-1299-4d31-b7ac-1bd19ce241b1" style="margin: 0px; padding: 0px; display: inline;"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/MacVittie" rel="tag"&gt;MacVittie&lt;/a&gt;,&lt;a href="http://technorati.com/tags/iRules" rel="tag"&gt;iRules&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Web%202.0" rel="tag"&gt;Web 2.0&lt;/a&gt;,&lt;a href="http://technorati.com/tags/AJAX" rel="tag"&gt;AJAX&lt;/a&gt;,&lt;a href="http://technorati.com/tags/XMLHTTPRequest" rel="tag"&gt;XMLHTTPRequest&lt;/a&gt;,&lt;a href="http://technorati.com/tags/caching" rel="tag"&gt;caching&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Internet%20Explorer" rel="tag"&gt;Internet Explorer&lt;/a&gt;,&lt;a href="http://technorati.com/tags/prototype.js" rel="tag"&gt;prototype.js&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Ajax.PeriodicalUpdater" rel="tag"&gt;Ajax.PeriodicalUpdater&lt;/a&gt;&lt;/div&gt;&lt;div class='blogtags'&gt;&lt;/div&gt;&lt;img src="http://devcentral.f5.com/weblogs/macvittie/aggbug/3397.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Lori MacVittie</dc:creator>
            <guid>http://devcentral.f5.com/weblogs/macvittie/archive/2008/06/26/3397.aspx</guid>
            <pubDate>Thu, 26 Jun 2008 11:41:44 GMT</pubDate>
            <wfw:comment>http://devcentral.f5.com/weblogs/macvittie/comments/3397.aspx</wfw:comment>
            <comments>http://devcentral.f5.com/weblogs/macvittie/archive/2008/06/26/3397.aspx#feedback</comments>
            <slash:comments>3</slash:comments>
            <wfw:commentRss>http://devcentral.f5.com/weblogs/macvittie/comments/commentRss/3397.aspx</wfw:commentRss>
            <trackback:ping>http://devcentral.f5.com/weblogs/macvittie/services/trackbacks/3397.aspx</trackback:ping>
        </item>
        <item>
            <title>Improving Security Through Dynamic Resource Obfuscation</title>
            <link>http://devcentral.f5.com/weblogs/macvittie/archive/2008/06/16/3361.aspx</link>
            <description>&lt;p&gt;One of the most basic attacks against data-driven sites generated dynamically through scripting languages like PHP and ASP is to use the weaknesses of the language against the developer. &lt;/p&gt;  &lt;p&gt;Attacks against sites that make use of scripting languages often attempt to exploit system level calls that can lead to all sorts of nastiness with very little work on the part of the attacker. &lt;/p&gt;  &lt;p&gt;One of the ways to guard against this is to write secure code, of course, but we all know that we can only code against known attacks. The unknown is something we just can't always anticipate and that sometimes leaves us open to newly discovered hacks. &lt;/p&gt;  &lt;p&gt;Resource obfuscation is an underused, overlooked capability on servers and &lt;a href="http://www.f5.com/products/big-ip" target="_blank"&gt;application delivery platforms&lt;/a&gt; that can seriously improve the security of your web applications and decrease the chances of an accidental or automate breach of security. Resource obfuscation can be an added protection against attacks. By hiding or obfuscating the actual file/script being invoked you can prevent a lot of automated exploitation of vulnerabilities in the most popular scripting languages used to build dynamic web sites today. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Resource Obfuscation&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Resource obfuscation, called "service virtualization" in the XML world, is really nothing more than &lt;a href="http://devcentral.f5.com/weblogs/macvittie/archive/2008/03/06/3099.aspx" target="_blank"&gt;rewriting the URI&lt;/a&gt;. In many cases you can simply "map" an external URI to an internal URI. For example, "/externalURI.php" will always map to "/internalURI.php". &lt;/p&gt;  &lt;p&gt;I&lt;img style="margin: 5px 0px 0px 5px" height="240" src="http://devcentral.f5.com/weblogs/images/devcentral_f5_com/weblogs/macvittie/125/o_ideabulb.jpg" width="214" align="right" /&gt;f your solution is flexible enough, you could set up a map that can translate exceedingly obfuscated URIs such as "xyz123abc.php" into "internalURI.php". If you are really concerned about security and you have a truly dynamic &lt;a href="http://www.f5.com/products/big-ip" target="_blank"&gt;application delivery platform&lt;/a&gt; with a feature like &lt;a href="http://devcentral.f5.com/Default.aspx?tabid=75" target="_blank"&gt;iRules&lt;/a&gt; you could even dynamically generate the external URIs, creating a per-session map, and replacing all the URIs in the payload with the session-constrained URIs. This is some serious work, but it would certainly keep the bad guys always guessing because the external URIs would never be the same because they would be uniquely generated on a per request basis. &lt;/p&gt;  &lt;p&gt;In general, resource obfuscation is a simple, flexible addition to your security toolkit that is easy to implement and adds an additional layer of security around your web applications. &lt;/p&gt;  &lt;p&gt;To make your web application even more secure try these additional simple security measures: &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Make sure the internal URI isn't easily deduced from query parameters or the functionality of the script. For example, if you're calling a PHP script to delete a record, don't make the internal URI "deleteRecord.php", and don't include the name of the file in hidden parameters. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Use a WAF (Web Application Firewall) or your chosen solution for rewriting URIs to &lt;strong&gt;block &lt;/strong&gt;external access to internal URIs if possible. This prevents exploitation of scripting level vulnerabilities in the event that an attack deduces the names of your internal scripts and applications. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; Give your scripts and applications extensions (if applicable) that do not easily (and loudly) proclaim the language and platform on which your site is running. Consider changing PHP and ASP to .abc or .xyz, either on the server itself or using your chosen URI rewrite solution. It won't stop serious attackers, but it might confuse the heck out of automated bots and script kiddies, which can reduce the likelihood of someone discovering some overlooked vulnerability. &lt;/p&gt;  &lt;p&gt;&lt;em&gt;Imbibing: Coffee&lt;/em&gt;&lt;/p&gt;  &lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:baba4f4d-f234-458f-ba40-84f76210d31d" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati Tags: &lt;a href="http://technorati.com/tags/MacVittie" rel="tag"&gt;MacVittie&lt;/a&gt;,&lt;a href="http://technorati.com/tags/F5" rel="tag"&gt;F5&lt;/a&gt;,&lt;a href="http://technorati.com/tags/iRules" rel="tag"&gt;iRules&lt;/a&gt;,&lt;a href="http://technorati.com/tags/security" rel="tag"&gt;security&lt;/a&gt;,&lt;a href="http://technorati.com/tags/resource%20obfuscation" rel="tag"&gt;resource obfuscation&lt;/a&gt;,&lt;a href="http://technorati.com/tags/rewrite%20URI" rel="tag"&gt;rewrite URI&lt;/a&gt;,&lt;a href="http://technorati.com/tags/service%20virtualization" rel="tag"&gt;service virtualization&lt;/a&gt;&lt;/div&gt;&lt;div class='blogtags'&gt;&lt;/div&gt;&lt;img src="http://devcentral.f5.com/weblogs/macvittie/aggbug/3361.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Lori MacVittie</dc:creator>
            <guid>http://devcentral.f5.com/weblogs/macvittie/archive/2008/06/16/3361.aspx</guid>
            <pubDate>Mon, 16 Jun 2008 14:46:40 GMT</pubDate>
            <wfw:comment>http://devcentral.f5.com/weblogs/macvittie/comments/3361.aspx</wfw:comment>
            <comments>http://devcentral.f5.com/weblogs/macvittie/archive/2008/06/16/3361.aspx#feedback</comments>
            <wfw:commentRss>http://devcentral.f5.com/weblogs/macvittie/comments/commentRss/3361.aspx</wfw:commentRss>
            <trackback:ping>http://devcentral.f5.com/weblogs/macvittie/services/trackbacks/3361.aspx</trackback:ping>
        </item>
    </channel>
</rss>