Forum Discussion

Filip_Verlaeckt's avatar
Filip_Verlaeckt
Historic F5 Account
Feb 06, 2009

Rewrite links in html response

Hi

 

 

I wrote an iRule to modify the links in html response code to be prefixed with " /be"

 

 

The rule I have so far is:

 

 

when HTTP_RESPONSE {

 

collect response data

 

if { [HTTP::header exists "Content-Length"] }

 

{ set content_length [HTTP::header "Content-Length"] }

 

else { set content_length 4294967295 }

 

if { $content_length > 0 }

 

{ HTTP::collect $content_length }

 

}

 

 

when HTTP_RESPONSE_DATA {

 

regsub -all "/eTime/" [HTTP::payload] "/be/eTime/" newdata

 

log local0. $newdata

 

HTTP::payload replace 0 $content_length $newdata

 

}

 

 

 

the logging of $newdata shows me an 'out of bound' error. I wonder how to avoid this and get the links replaced...

 

I know the STREAM profile is the easy way to tackle this but I need this an ASM standalone which does not include the STREAM profile :-(

 

 

Any help appreciated.

 

 

 

 

1 Reply

  • A few suggestions:

    1. Avoid trying to replace the string in binary content. You can check if the response content type starts with text before trying to perform the replacement:

    if {[HTTP::header "Content-Type"] starts_with "text"}

    2. Limit the collection amount to 1Mb. See SOL6578 (Click here) and this post (Click here) for details.

    3. Consider disabling HTTP 1.1 on the server side connection if you want to prevent the server from sending chunked responses (which won't have a content length). See the Credit Card Scrubber iRule for an example (Click here😞

     
     when HTTP_REQUEST { 
        Don't allow data to be chunked 
       if { [HTTP::version] eq "1.1" } { 
           if { [HTTP::header is_keepalive] } { 
              HTTP::header replace "Connection" "Keep-Alive" 
           } 
           HTTP::version "1.0" 
        } 
     } 
     

    4. I'm not sure whether it would work or not, but I think using string map would theoretically be more efficient than a regex:

    regsub -all "/eTime/" [HTTP::payload] "/be/eTime/" newdata

    ->

    set newdata [string map {/eTime/ /be/eTime/} [HTTP::payload]]

    I'm not sure if string map munges the content though, so if you try this double check the resulting HTML.

    If you still see the out of bounds error, can you post the current iRule and let us know if the error happens on every request or just some?

    Thanks,

    Aaron

     
     when HTTP_REQUEST { 
      
         Prevent the server from sending a compressed response 
         remove the compression offerings from the client 
        HTTP::header remove "Accept-Encoding" 
      
         Don't allow data to be chunked 
        if { [HTTP::version] eq "1.1" } { 
      
            Force downgrade to HTTP 1.0, but still allow keep-alive connections. 
            Since 1.1 is keep-alive by default, and 1.0 isn't, 
            we need make sure the headers reflect the keep-alive status. 
      
            Check if this is a keep alive connection 
           if { [HTTP::header is_keepalive] } { 
      
               Replace the connection header value with "Keep-Alive" 
              HTTP::header replace "Connection" "Keep-Alive" 
           } 
      
            Set server side request version to 1.0 
            This forces the server to respond without chunking 
           HTTP::version "1.0" 
        } 
     } 
     when HTTP_RESPONSE { 
      
         Check if it's a text response 
        if {[HTTP::header "Content-Type"] starts_with "text"}{ 
      
            Determine how much content to collect (no more than 1Mb) 
           if {[HTTP::header exists "Content-Length"] && [HTTP::header "Content-Length"] <= 1048576]}{ 
      
      set content_length [HTTP::header "Content-Length"] 
      
           } else { 
      
       Only collect the first 1Mb of the response content 
               This is a limitation described in SOL6578 
              set content_length 1048576 
           } 
      
           if { $content_length > 0 }{ 
      
               Trigger collection of the payload 
              HTTP::collect $content_length 
      
              log local0. "[IP::client_addr]:[TCP::client_port]: Collecting content: $content_length" 
           } 
        } 
     } 
     when HTTP_RESPONSE_DATA { 
      
        log local0. "[IP::client_addr]:[TCP::client_port]: Original payload: [HTTP::payload]" 
      
         Replace /eTime/ with /be/eTime/ in the payload.  Try using string map. Else use regsub. 
         regsub -all "/eTime/" [HTTP::payload] "/be/eTime/" newdata 
        set newdata [string map {/eTime/ /be/eTime/} [HTTP::payload]] 
      
        log local0. "[IP::client_addr]:[TCP::client_port]: Modified payload: [HTTP::payload]" 
      
        HTTP::payload replace 0 $content_length $newdata 
     }