For more information regarding the security incident at F5, the actions we are taking to address it, and our ongoing efforts to protect our customers, click here.

Forum Discussion

Chris1269_13050's avatar
Chris1269_13050
Icon for Nimbostratus rankNimbostratus
Aug 05, 2015

How to filter within iRule for HTTP_RESPONSE

Hi all,

Is there anyway we can use an iRule to filter a HTTP_RESPONSE with whats in the HTTP header or something like that? We current use a filter like:

when HTTP_RESPONSE { if {[LB::server pool] contains "xxxxxxxxxxx"}{

This works great but can i then filter deeper, with something like:

    elseif {[LB::server pool] contains "xxxxxxxx"}{
    switch -glob [HTTP::header Location] {
    "xxxx" {     

This inst currently working.

Im essentially trying to differentiate a HTTP RESPONSE sent from the same pool.

Thanks!

10 Replies

  • Hi Ketzuken,

    Is the value of "Location" header you're trying to use in your conditional switch statement? If so, try to replace

    switch -glob [HTTP::header "Location"]
    with
    switch -glob [HTTP::header value "Location"]
    .

    Additionally, you may find it useful to include a log statement for the duration of troubleshooting and testing.

    log local0. "[HTTP::header value "Location"]"
    . If this log statement returns an empty value to
    /var/log/ltm
    , you'll know the "Location" header was not included in the HTTP response.

  • If I may add,

    You can actually omit the "value" argument if the header name doesn't collide with any of the HTTP::header subcommands. So in most cases:

    HTTP::header Location
    

    will produce the same result as

    HTTP::header value Location
    

    But more important, the Location response header is only ever present in a 30x redirect response. It may simply be that you're looking for the Location header in non-redirect traffic.

  • Hi and thanks for the response. So it may have been misleading I'm not sure if Location is best thing to filter on. We are filtering the RESPONSE initially with the Pool. We then need to filter deeper into the response and differentiate between two URIs coming from the same POOL in the RESPONSE but i have no idea how to do this.

     

  • We then need to filter deeper into the response and differentiate between two URIs coming from the same POOL in the RESPONSE

     

    What if anything is different between the responses from either pool member?

     

  • Something like:

    elseif {[LB::server pool] contains XXX_POOL"}{
    HTTP::header replace Location [string map -nocase {"XXX" "uat_XXX"} [HTTP::header Location]]
    HTTP::header replace Set-Cookie [string map -nocase {"/XXX" "/uat_XXX"} [HTTP::header Set-Cookie]]
                 STREAM::expression {@XXXB@uat_XXX@}
                    STREAM::enable }
    

    Now throw another one into the mix coming from the same Pool. Like: uat_XXX1. So i guess the differences are the Location, but it doesnt appear to be working with that.

  • My point is that not all responses will contain a Location header - only redirect responses. Unless you're specifically looking for a redirect response, you need to find something else that differentiates the responses of the two pool members. Could you elaborate on what you're trying to do?

     

  • That actually makes sense and would explain why what im seeing in Fiddler. The setup we have is very complex. All backend webservers are setup with the same directory names, databases etc... So we are ripping out the 'uat' parts,

    1) Within the Request we have:

            elseif {$uri contains "/uat_xxx"}{
            switch -glob [string tolower [HTTP::uri]] {
            "*uat_xxx_DB" {
                pool POOL1   
                HTTP::header remove "Accept-Encoding"
                HTTP::header replace Location [string map -nocase {"uat_xxx_DB" "xxx_DB"} [HTTP::header Location]]
                HTTP::uri [string map -nocase {"uat_xxx_DB" "xxx_DB"} [HTTP::uri]]
                STREAM::disable  }
            "uat_xxx"*" {
                pool POOL1  
                HTTP::header remove "Accept-Encoding"
                HTTP::header replace Location [string map -nocase {"uat_xxx" "xxx"} [HTTP::header Location]]
                HTTP::uri [string map -nocase {"uat_xxx" "xxx"} [HTTP::uri]]
                STREAM::disable }
            }
            }
    

    So two different URIs going to the same pool with a uri / http header modification

    2) So with the response, we need to convert the header and the stream back to what the user sees. How would i go about doing this? As you mentioned i cant use Location as it wont convert it all back (only the redirect responses). I can get it working with one URI in play as all i would have to do is use something like in the Response:

            elseif {[LB::server pool] contains "POOL1"}{
    

    But as you can see from my request, 2xURIs are using the same pool so i cant use the above. I have attemped to filter on a custom header i inserted within the request but running into the same problems.

    I hope this helps!

  • Well, there might be a few ways to do this.

    1. If you can modify the application(s) to throw in some specific response header or maybe metatag, you can filter on that in the response.

    2. In most cases the HTTP request and response are an atomic pair, so:

      when HTTP_REQUEST {
          set flag ""
          if { something } {
              set flag "true"
          } elseif { something_else } {
              set flag "false"
          }        
      }
      when HTTP_RESPONSE {
          if { [info exist flag] } {
              switch $flag {
                  "true" {
                      do something
                  }
                  "false" {
                      do something_else
                  }
              }
          }
      }
      
  • Thanks for the help. Using flags in a similar way you suggested worked perfectly. How does this technially work within the iRule and how does the flag persist between request and response?

     

  • It's based on the somewhat atomic relationship of an HTTP request and corresponding response of an otherwise stateless protocol. This isn't always the way it worked, especially with certain types of multiplexing, but it generally works well. It's also important to point out that variables exist within the span of a single TCP session, and in most cases the response to a request is in the same TCP session. Again, that's not the case in every environment.