Forum Discussion

Sake_Blok's avatar
Sake_Blok
Icon for Nimbostratus rankNimbostratus
Mar 28, 2006

Workaround for invalid 304 content-length

Hi,

In a migration towards the BigIP, I encounter a problem with http-304 responses. In the http-header there is a "Content-Length" header with a value greater than 0. The http-rfc clearly states that a 304 MUST NOT have a body, therefore a content-length is also invalid. The effect of this content-length-header is that the BigIP is waiting for the amount of data that the header is announcing. Only after the server terminates the connection the BigIP will send the 304-response back to the client. This is an unacceptable delay.

The problem will be fixed on the http-server, but in the meantime I would like to build an iRule as a temporary workaround.

I have tried many things already and only the following iRule is working:


when HTTP_RESPONSE {
   if {([HTTP::status] == 304) && [HTTP::header exists Content-Length]} {
      log local0. "304 found with content-length" 
      HTTP::respond 304
      HTTP::disable
   }
}

But the HTTP::disable disables HTTP-parsing for subsequent http-requests in the TCP-session (OneConnect is enabled also on this virtual). If I do a 'HTTP::header replace "Content-Length" "0"' the header is altered towards the client, but I guess there is still an internal variable that is holding the content-length value, so the BigIP will still try to collect that amount of data from the http-response and this will result in the timeout on the server and the delay towards the client.

Is there a way to change this internal variable? Or is there another way the stop the BigIP from waiting on this (nonexisting) content?

Cheers, Sake

8 Replies

  • Hi Colin,

     

     

    Yes, I did try "HTTP::release", as well as "HTTP::collect 0". The first did not help, the BigIP still waited for the announced amount of data. The second gave an error, the parameter needs to be greater than 0.

     

     

    I have a case for this issue also (C260102), there seem to be some CR's, but unfortunately it seems our configuration (on 9.1.1) is still vulnerable. It also looks like this is not fixed in later releases, hence the iRule-workaround...

     

     

    So far, the only thing that stops the BigIP from waiting for the content that neven comes is "HTTP::disable", but I'm afraid that'll break other stuff.

     

     

     

    Cheers, Sake
  • bl0ndie_127134's avatar
    bl0ndie_127134
    Historic F5 Account
    Unfortunately the only work around (at the moment) is to do a 'TCP::collect' and replace the data at the TCP layer on the server response. We have seen applications (Sharepoint) that do send data on a 304 response. There should be examples of 'TCP::collect' and 'TCP::payload replace' in the forum.
  • Hi Bl0ndie, Uhmm... this application does not send data on the 304, it only adds a "Content-Length" header *as if* it is going to send data. I don't think a TCP::collect will accept a "0" as parameter. But tomorrow I will be on site, I might give it a shot.

     

     

    IMHO the only way to solve this issue is to tell the BigIP that there is no data to collect. That way it will not enter the HTTP::collect or TCP::collect that happens between the HTTP_RESPONSE and the HTTP_RESPONSE_DATE (please correct me if my interpretation of how iRules work is incorrect). I'm just not sure if this is possible, and if it is how it can be done...

     

     

     

    Cheers, Sake
  • bl0ndie_127134's avatar
    bl0ndie_127134
    Historic F5 Account
    Give this a try ...

    
    when SERVER_CONNECTED {
       TCP::collect 12
    }
    when HTTP_REQUEST_SEND {
       set response_pending 1
       TCP::collect 12
    }
    when SERVER_DATA {
       if {$response_pending == 1} {
           Check for 304 response
          if {[TCP::payload] starts_with "HTTP/1.1 304"} {
              set index [string first "Content-Length" [TCP::payload]]
               Check if header is found
              if {$index != -1} {
                 TCP::payload replace $index 2 "X-"
              }
              elseif {[string first "\r\n\r\n" [TCP::payload]] == -1} {
                  Dont have the end of header. Collect more.
                 TCP::collect
                 return
             }
        }
        set response_pending 0
    }
  • bl0ndie_127134's avatar
    bl0ndie_127134
    Historic F5 Account
    Ok one more try, here it is again. Looks like I lost some text when pasting.

    
    when SERVER_CONNECTED {
       TCP::collect 12
    }
    when HTTP_REQUEST_SEND {
       set response_pending 1
       TCP::collect 12
    }
    when SERVER_DATA {
        if {$response_pending == 1} {
             Check for 304 response
            if {[TCP::payload] starts_with "HTTP/1.1 304"} {
                set index [string first "Content-Length" [TCP::payload]]
                 Check if header is found
                if {$index != -1} {
                    TCP::payload replace $index 2 "X-"
                }
                elseif {[string first "\r\n\r\n" [TCP::payload]] == -1} {
                     Dont have the end of header. Collect more.
                    TCP::collect
                    return
                }
            }
            set response_pending 0
        }
        TCP::release
        TCP::collect
    }
  • Hi Bl0ndie,

     

     

    Changing the tcp-payload before the http-parser gets hold of it does indeed do the trick. I now get the http-reponse straight away. Thanks a lot for your help!

     

     

    Cheers, Sake

     

     

     

     

    PS I reread your initial reply about tcp:collect and realise I misunderstood you. I thought you meant reading out the http-response-data (by tcp-collect) instead of http-resonse-header. Sorry for that...
  • Hi,

     

     

    This bug is return in version 9.2.3 !!!! I have applies workaround in my bigip.... ..

     

     

    []´s