Forum Discussion

Anthony_Vaz_547's avatar
Anthony_Vaz_547
Icon for Nimbostratus rankNimbostratus
Jul 07, 2009

Stream::expression irule problem

Hi guys

 

I'm sure this is just me being an airhead but I can't get this irule to work. Any input greatly appreciated

 

 

We have a need to rewrite the content of a HTTP response. I am searching for what I want to find (which is "top.") and replacing it (with "top.child1.")

 

 

This is the irule code for the above (and this works).

 

 

When HTTP_RESPONSE {

 

Disable the stream filter by default

 

STREAM::disable

 

Check if response type is text

 

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

 

Replace any "top. instance with self.

 

STREAM::expression "@top\.@top.child1.@"

 

Enable the stream filter for this response only

 

STREAM::enable

 

}

 

}

 

However, annoyingly, there are occassions when "top." is too generic. There are a number of IMG SRC tags that end in top.jpg. Therefore, those image tags are being rewritten to top.child1.jpg.

 

 

I would like to have an "unless" stream expression. The STREAM::expression wiki page suggests that this can be done (http://devcentral.f5.com/wiki/default.aspx/iRules/stream__expression)

 

 

I have therefore modified my STREAM::expression to be

 

STREAM::expression {@top\.(?!jpg)@top.child1.@}

 

 

I infer, from the Wiki page, that this expression should always rewrite top. to top.child1. unless the original string is top.jpg

 

 

However this doesn't work - Can anyone help me out with what the correct syntax should be?

 

 

Many thanks in advance

 

4 Replies

  • That looks about right. The regex doesn't match top.jpg:

    % regexp

    wrong args: should be "regexp ?switches? exp string ?matchVar? ?subMatchVar subMatchVar ...?"

    % regexp -inline -all {top\.(?!jpg)} top.test

    top.

    % regexp -inline -all {top\.(?!jpg)} top.jpg

    %

    Is it possible that jpg is in mixed case? If so, you could use character classes to avoid matching:

    regexp -inline -all {top\.(?![jJ][pP][gG])}

    Else, you could do more extensive checks of the match by setting the replacement string in STREAM_MATCHED using STREAM::replace. There is an example of this in the last sample of the STREAM::expression wiki page:

     
      http://devcentral.f5.com/wiki/default.aspx/iRules/stream__expression 
     when HTTP_RESPONSE {   
         
         Disable the stream filter by default   
        STREAM::disable   
         
         Check if response type is text   
        if {[HTTP::header value Content-Type] contains "text"}{   
         
            Match any http:// instance and replace it with nothing  
           STREAM::expression {&http://.*?example\.com&&} 
         
            Enable the stream filter for this response only   
           STREAM::enable   
        }   
     }    
     when STREAM_MATCHED {   
        log local0. "[IP::client_addr]:[TCP::local_port]: matched: [STREAM::match],\ 
           replaced with: [string map {http:// https://} [STREAM::match]]"   
        STREAM::replace "[string map {http:// https://} [STREAM::match]]"   
     } 
     

    Aaron
  • Thanks Aaron

    Apologies, I wasn;t clear in my message before. It wasn;t so much that the regular expression was wrong, but when I include the regular expression in the expression, the web pages do not load.

    I thought I was using the wrong syntax, and I have changed my irule as you suggested to utilise STREAM_MATCHED. As you suspected this has allowed me to trouble shoot further.

    The new rule now looks as follows

     
      when HTTP_RESPONSE {    
           
          Disable the stream filter by default    
         STREAM::disable    
           
          Check if response type is text    
         if {[HTTP::header value Content-Type] contains "text"}{    
           
             Match any 'top.' instance and replace it with nothing   
            STREAM::expression {&top\.(?!jpg)&&}  
           
             Enable the stream filter for this response only    
            STREAM::enable    
         }    
      }     
      when STREAM_MATCHED {    
         if {[STREAM::match] contains "jpg"} { 
               return 
         } else { 
         STREAM::replace "[string map {top. top.child2.} [STREAM::match]]"    
         } 
      }  
     

    Again, when enabling this new irule, no web pages will load. However, I am now getting the following error message in the /var/log/ltm file

    Jul 7 15:39:57 tmm tmm[925]: 01220001:3: TCL error: Rule irule_EPMResponseTopToSelfTST - couldn't compile regular expression pattern: quantifier operand invalidIllegal argument (line 1) invoked from within "STREAM::expression {&top\.(?!jpg)&&} "

    Jul 7 15:40:20 tmm tmm[925]: 01220005:3: Can't compile regular expression - (top\.(?:?!jpg))

    Jul 7 15:40:20 tmm tmm[925]: 01220001:3: TCL error: Rule irule_EPMResponseTopToSelfTST - couldn't compile regular expression pattern: quantifier operand invalidIllegal argument (line 9) invoked from within "STREAM::expression {&top\.(?!jpg)&&} "

    It's curious that it thinks the regular expression is ' (top\.(?:?!jpg)) ' rather than ' top\.(?!jpg)'

    Our BigIP is running 9.3.1 but have so far not found any regular expression bugs that may cause this

    Does this help shed any more light on what the problem may be?

  • That's odd... regexp handles this correctly in an iRule:

     

     

     
     when RULE_INIT { 
      
        log local0. "\[regexp -inline -all {top\.(?!jpg)} top.test\]: [regexp -inline -all {top\.(?!jpg)} top.test]" 
        log local0. "\[regexp -inline -all {top\.(?!jpg)} top.jpg\]: [regexp -inline -all {top\.(?!jpg)} top.jpg]" 
     } 
     

     

     

    Rule : [regexp -inline -all {top.(?!jpg)} top.test]: top.

     

    Rule : [regexp -inline -all {top.(?!jpg)} top.jpg]:

     

     

    This might be a bug in the stream filter's handling of the regex. It looks like something is trying to optimize the code by adding a colon. This colon would normally stop the regex engine from saving the matched value into a backreference. In this case though, it's a lookbehind and the ?: breaks the matching:

     

     

     
     when RULE_INIT { 
        log local0. "\[regexp -inline -all {(top\.(?:?!jpg))} top.jpg\]: [regexp -inline -all {(top\.(?:?!jpg))} top.jpg]" 
     } 
     

     

     

    01220001:3: TCL error: couldn't compile regular expression pattern: quantifier operand invalid while executing "regexp -inline -all {(top\.(?:?!jpg))} top.jpg"

     

     

    I'd suggest opening a case with F5 Support on this.

     

     

    As a workaround, you could replace the regex with

     

     

    top\.

     

     

    and then check the STREAM::match output to see if it doesn't end in jpg before performing the replacement.

     

     

    Aaron
  • Thanks ever so much for your help - will get a call raised and will add the results onto this thread