Forum Discussion

DNSgeek_90802's avatar
DNSgeek_90802
Icon for Nimbostratus rankNimbostratus
Dec 28, 2009

Get HTTP::uri in HTTP_RESPONSE

I have an irule that needs to get the URI from a 404 page and muck with it. However, when I try to reference [HTTP::uri], I get told that I cannot access it from the HTTP_RESPONSE context.

 

 

How can I get the URI that caused the 404 so I can modify it?

 

 

Thanks!

 

Tom

10 Replies

  • Hi Tom,

     

    Have you look at [URI::path]?

     

     

    http://devcentral.f5.com/wiki/default.aspx/iRules.URI

     

     

    I hope this helps

     

     

    Bhattman
  • You can save the HTTP::uri value in HTTP_REQUEST to a variable and then reference that in HTTP_RESPONSE:

     
     when HTTP_REQUEST { 
         Save the URI 
        set uri [HTTP::uri] 
     } 
     when HTTP_RESPONSE { 
         Check if response was a 404 
        if {[HTTP::status] == 404}{ 
           log local0. "[IP::client_addr]:[TCP::client_port]: 404 received from $uri" 
        } 
     } 
     

    Aaron
  • A variable set in a prior event should be available in all subsequent events on the same TCP connection. The only case I can think of where you'd get a runtime TCL error about a variable not existing is if you added the iRule in the middle of a client's TCP connection. Any new TCP connection should work fine.

     

     

    If you're seeing something else, could you post the iRule and logs from /var/log/ltm?

     

     

    Thanks,

     

    Aaron
  • Here's what I'm trying to do. I send a request to pool A. If and only if pool A returns a 404 code, I need to rewrite the path and send the request to pool B. No matter what pool B responds with, return it to the client.

     

     

    So, in the HTTP_REQUEST section, we save off the [HTTP::path] into the variable $mypath. In the HTTP_RESPONSE section, we have:

     

     

     
     when HTTP_RESPONSE { 
         if { $::DEBUG }{ 
             log "respcode -> [HTTP::status]'" 
             log "host -> [HTTP::host]" 
         } 
         if { ([HTTP::status] == 404) } { 
             if { $mypath ends_with "/" }{ 
                 set mypath [string range 0 [string length $mypath]-1 $mypath] 
                 append .html $mypath 
             } 
             HTTP::path $mypath 
             if { $::DEBUG }{ 
                 log "retruri -> $mypath" 
             } 
             pool B 
         } 
     } 
     

     

     

    The problem comes in the line

     

    HTTP::path $mypath

     

     

    THe error is:

     

    01070151:3: Rule [myrule] error: line 34: [command is not valid in current event context (HTTP_RESPONSE)] [HTTP::path $mypath] 
     

     

     

    How can I change the path/uri so I can submit a request to pool B without forcing a redirect?

     

     

    Tom
  • Ah, so that error is because the HTTP::path command is not valid in the HTTP_RESPONSE event. There isn't a URI or path in responses.

    If you want to retry the request to a new pool, you can use HTTP::retry. Here is a rough, untested example.

    I'm assuming you are only concerned with GET requests. If you want to handle POSTs or other requests with a payload, you'd need to collect the payload on every request using HTTP::collect and then append the payload to the request headers in HTTP_REQUEST_DATA.

     
      Based on the example on the HTTP::request wiki page: 
      http://devcentral.f5.com/wiki/default.aspx/iRules/http__retry.html 
     when CLIENT_ACCEPTED { 
      
         Initialize a variable to track whether a request has been retried 
        set retries 0 
     } 
     when HTTP_REQUEST { 
      
         Check if request is a GET (we only save the request headers using HTTP::request) 
        if {[HTTP::method] eq "GET"}{ 
      
            Save the request headers 
           set request_headers [HTTP::request] 
           log local0. "HTTP request headers: $request_headers" 
        } 
     } 
     when LB_SELECTED { 
        if { $retries >= 1 } { 
          LB::reselect pool pool_b 
        } 
     } 
     when HTTP_RESPONSE { 
      
        if { [HTTP::status] == 404 } { 
           incr retries 
           log local0. "4xx error caught: retry $retries out of [active_members [LB::server pool]]" 
      
           if { $retries < [active_members [LB::server pool]] } { 
              HTTP::retry $request_headers 
           } 
        } else { 
            Successful response, reset the retries variable 
           set retries 0 
        } 
     } 
     

    Aaron
  • How would I modify the HTTP::path in the retry? I need to be able to try pool A, if pool A 404's, modify the path and try again with pool B using the new path.
  • Sorry, I forgot about that part. Can you try this?

     
      Based on the example on the HTTP::request wiki page: 
      http://devcentral.f5.com/wiki/default.aspx/iRules/http__retry.html 
     when CLIENT_ACCEPTED { 
      
         Initialize a variable to track whether a request has been retried 
        set retries 0 
     } 
     when HTTP_REQUEST { 
      
         Use pool A by default 
        pool pool_A 
      
         Check if this is a retried request 
        if { $retries == 0 }{ 
      
            Check if request is a GET (we only save the request headers using HTTP::request) 
           if {[HTTP::method] eq "GET"}{ 
      
               Save the request headers 
              set request_headers [HTTP::request] 
              log local0. "HTTP request headers: $request_headers" 
           } 
        } else { 
      
            This is a retry, so check if the path ends with a slash 
           if { [HTTP::path] ends_with "/" }{ 
      
               Remove the last slash and append .html to the path 
              HTTP::path "[string range [HTTP::path] 0 end-1].html" 
           } 
        } 
     } 
     when LB_SELECTED { 
      
        if { $retries >= 1 }{ 
      
           LB::reselect pool pool_b 
        } 
     } 
     when HTTP_RESPONSE { 
      
        if { [HTTP::status] == 404 }{ 
           incr retries 
           log local0. "4xx error caught: retry $retries out of [active_members [LB::server pool]]" 
      
           if { $retries < [active_members [LB::server pool]] }{ 
              HTTP::retry $request_headers 
           } 
        } else { 
            Successful response, reset the retries variable 
           set retries 0 
        } 
     } 
     

    Aaron
  • Hey Hooli,

     

    Is there another way to record the URI in the response header? Coz in our environment, redirection rule is set on server and URL masking requirement is planned at F5. I cannot record the URI from request header. Please help me with this