Forum Discussion

Don_22992's avatar
Don_22992
Icon for Nimbostratus rankNimbostratus
Apr 02, 2008

stubborn 4xx/5xx Error Handler

I am sure this is simple....

 

 

I have the following iRule to redirect 4xx & 5xx errors to a page on a backend server. It works great - once I have sucessfully connected to the site once! What am I missing?

 

 

when HTTP_REQUEST {

 

set myhost [HTTP::host]

 

}

 

 

when HTTP_RESPONSE {

 

if { ([HTTP::status] starts_with "4")} {

 

HTTP::redirect https://$myhost/images/errors/err_4xx.htm

 

} elseif { ([HTTP::status] starts_with "5")} {

 

HTTP::redirect https://$myhost/images/errors/err_5xx.htm

 

} else {

 

}

 

}

 

  • hoolio's avatar
    hoolio
    Icon for Cirrostratus rankCirrostratus
    Can you clarify this? If the pool member responds with a 4xx or 5xx status, the first response still gets through to the client but any subsequent response is redirected? Is that what you mean?

    Can you add logging to the rule to check this?

    
    when HTTP_REQUEST {
       set myhost [HTTP::host]
    }
    when HTTP_RESPONSE {
       log local0. "[IP::client_addr]:[TCP::client_port]: Request $myhost generated response status: [HTTP::status]"
       if { ([HTTP::status] starts_with "4")} {
          log local0. "[IP::client_addr]:[TCP::client_port]: Redirecting to 4xx.htm"
          HTTP::redirect https://$myhost/images/errors/err_4xx.htm
       } elseif { ([HTTP::status] starts_with "5")} {
          log local0. "[IP::client_addr]:[TCP::client_port]: Redirecting to 5xx.htm"
          HTTP::redirect https://$myhost/images/errors/err_5xx.htm
       } else {
          log local0. "[IP::client_addr]:[TCP::client_port]: Doing nothing"
       }
    }

    You can check the log output by tailing the ltm log file (tail -f /var/log/ltm).

    Aaron
  • hoolio's avatar
    hoolio
    Icon for Cirrostratus rankCirrostratus
    The rule looks like it's working as it's written. If the server responds with a 4xx or 5xx response, the response is rewritten to a 302 redirect. However, I don't think you actually want to redirect all 4xx and 5xx responses. The browser won't follow the redirect if the redirect is in response to a request for an image. I don't think even if it were possible, that you'd want to redirect the previous request to a page if a single image referenced on the page wasn't found.

    Do you know why the application responds with a 500 when requesting the an image referenced by the root page of the site? That might be the first thing to address.

    If you wanted to handle this better in an iRule, you might create a list of page types (like .do or /) and then only redirect requests to pages (as opposed to images) if they generate a 4xx or 5xx response from the web app. You could rewrite all other responses 4xx/5xx responses to 200 with no content.

    Also, once you enable blocking on your ASM security policy, ASM will automatically take the blocking action for all 5xx responses (except 502).

    Can you give this updated rule a try?

    
    when RULE_INIT {
       set ::page_suffixes [list \
          .do \
          / \
       ]
    }
    when HTTP_REQUEST {
       set myhost [HTTP::host]
       set mypath [HTTP::path]
    }
    when HTTP_RESPONSE {
       log local0. "[IP::client_addr]:[TCP::client_port]: Request $myhost generated response status: [HTTP::status]"
       if { ([HTTP::status] starts_with "4")} {
          if { $mypath ends_with $::page_suffixes }{
             log local0. "[IP::client_addr]:[TCP::client_port]: request to $mypath generated a [HTTP::status], redirecting to 4xx.htm"
             HTTP::redirect https://$myhost/images/errors/err_4xx.htm
          } else {
             log local0. "[IP::client_addr]:[TCP::client_port]: request to $mypath generated a [HTTP::status], responding with a 200"
             HTTP::respond 200
          }
       } elseif { ([HTTP::status] starts_with "5")} {
          if { $mypath ends_with $::page_suffixes }{
             log local0. "[IP::client_addr]:[TCP::client_port]: request to $mypath generated a [HTTP::status], redirecting to 5xx.htm"
             HTTP::redirect https://$myhost/images/errors/err_5xx.htm
          } else {
             log local0. "[IP::client_addr]:[TCP::client_port]: request to $mypath generated a [HTTP::status], responding with a 200"
             HTTP::respond 200
          }
       } else {
          log local0. "[IP::client_addr]:[TCP::client_port]: Doing nothing"
       }
    }

    Aaron
  • Aaron,

     

     

    The resultant behavior of a redirect for an image performs as desired; just may not be very clean. It actually mirrors the processing of an existing process and will be cleaned up in a subsequent revision of the rule/configuration. However, the fact that it was a request for an image at the root is irrelevant. Replacing "/don.jpg" with "/my.jsp", "begin.do", or "/mystuff/index.html" also results in the same behavior.

     

     

    I do not know WHY or even IF the application responds with a 500 when the root page contains a request for an image.

     

     

    Lets try with https::/my.domain.com/mystuff/index.html (which most assuredly does not exist and causes a 404 error)

     

     

    Using this as my request, the following behavior is observed:

     

    1. Bypassing the F5 entirely results in a default 404 error page returned.

     

    2. Removing this iRule results in a default 404 error page returned.

     

    3. WITH the irule, the browser reports page canot be displayed.

     

     

    This seems to be the heart of the problem.

     

     

    Don

     

     

  • hoolio's avatar
    hoolio
    Icon for Cirrostratus rankCirrostratus
    Hi Don,

     

     

    So this was case 2?

     

     

     

    Requested "my.domain.com/DJ-Boston.jpg" (modified uri to force a 404 error); Received from browser "Internet Explorer cannot display the webpage":

     

     

    Apr 3 11:32:28 tmm tmm[1627]: Rule stg-errors : 192.168.16.149:64126: Request my.domain.com generated response status: 404

     

    Apr 3 11:32:28 tmm tmm[1627]: Rule stg-errors : 192.168.16.149:64126: Redirecting to 4xx.htm

     

     

     

     

     

    Typically, you'd get the page cannot be displayed error when a TCP reset is sent to the client. If this was due to the iRule, I'd expect to see a TCL error. If you grep for TCL error in the ltm log file, do you find any matches (grep -i 'tcl error' /var/log/ltm')?

     

     

    What version of BIG-IP code are you running? If you remove any ASM-enabled HTTP classes from the VIP, does the client get correctly redirected to 4xx.htm?

     

     

    Aaron
  • Aaron,

     

     

    Thanks for your reply.

     

     

    There were no tcl errors found in the LTM log. However, your last point produced something of interest.

     

     

    When any ASM-enabled HTTP classes were removed - it works as desired. I have no clue why but hold hope that you will enlighten.

     

     

    The version I am running is BIG-IP 9.4.3 Build 14.3 Hotfix HF3.

     

     

    Don

     

     

     

  • hoolio's avatar
    hoolio
    Icon for Cirrostratus rankCirrostratus
    In previous versions of BIG-IP ASM, you'd need to disable ASM when sending a response from an iRule (Click here). I didn't think that would be necessary in 9.4.2+ with the plugin architecture. Can you open a case with F5 Support asking them to investigate this? If you want to try one more thing, you could explicitly disable the ASM plugin when sending a redirect:

    
    when HTTP_REQUEST {
       set myhost [HTTP::host]
    }
    when HTTP_RESPONSE {
        Initialise a variable to track whether we're redirecting this request
       set redirect 0
       log local0. "[IP::client_addr]:[TCP::client_port]: Request $myhost generated response status: [HTTP::status]"
       if { ([HTTP::status] starts_with "4")} {
          log local0. "[IP::client_addr]:[TCP::client_port]: Redirecting to 4xx.htm"
          HTTP::redirect https://$myhost/images/errors/err_4xx.htm
          set redirect 1
       } elseif { ([HTTP::status] starts_with "5")} {
          log local0. "[IP::client_addr]:[TCP::client_port]: Redirecting to 5xx.htm"
          HTTP::redirect https://$myhost/images/errors/err_5xx.htm
          set redirect 1
       } else {
          log local0. "[IP::client_addr]:[TCP::client_port]: Doing nothing"
       }
    }
    when HTTP_CLASS_SELECTED {
        If the request is being redirected, disable ASM
       if {$redirect}{
           Enable ASM by default
          PLUGIN::disable ASM
       } else {
           Enable ASM by default
          PLUGIN::enable ASM
       }
    }

    Aaron
  • Aaron,

     

     

    The above rule did not work. I receive the following TCL error stating that the "redirect" variable does not exist.

     

     

    Apr 9 14:28:25 tmm tmm[1640]: 01220001:3: TCL error: stg-errors - can't read "redirect": no such variable

     

    while executing "if {$redirect}{

     

    log local0. "[IP::client_addr] disabling ASM"

     

    PLUGIN::disable ASM

     

    } else { l

     

    log local0. "[IP::client_addr] enabling ..."

     

     

    :|

     

     

    DJ