Forum Discussion
smp_86112
Cirrostratus
Feb 08, 2008STREAM::replace
I'm trying to write a simple iRule using a STREAM profile on an LTM running 9.1.2. According to the iRules wiki, the STREAM::replace was introduced in 9.0.0. However this simple iRule generates the error:
line 2: [wrong args] [STREAM::replace @string1@string2@]
when HTTP_RESPONSE {
STREAM::replace @string1@string2@
}
I've tried lots of different permutations, like changing the character delimiter, adding quotes, etc... What's going on here?
- hoolio
Cirrostratus
- smp_86112
Cirrostratus
So you're telling me this doc is inaccurate? - hoolio
Cirrostratus
Sorry, I thought you'd gotten the answer in the other thread and was just updating this one to indicate the answer was in that one. - smp_86112
Cirrostratus
What I'm trying to do is replace all occurrences of the string "about:blank" with a different string in any HTTP_RESPONSE_DATA if { HTTP::header "Content-Type"] contains "application/x-javascript"}. My LTMs are running 9.1.2, and it appeared the only STREAM command available to me was STREAM::replace. I was hoping I could apply a blank stream profile to the VIP, then use the STREAM::replace command to accomplish the replacement. I misunderstood the explanation of the command. - hoolio
Cirrostratus
If you're trying to collect response content and replace multiple instances of one string with another string of a different length, it gets pretty complicated. You need to update the indices for subsequent matches based on the length of the current replacement string. - smp_86112
Cirrostratus
If you're trying to collect response content and replace multiple instances of one string with another string of a different length - hoolio
Cirrostratus
No warranty on this, but it worked in tests I tried. I tested by using a few different 'find regexes' and replacement strings. I tested to see that variable length matches were replaced correctly. Note that I only tested with a single global replacement string. The rule would need to be tweaked if you want to dynamically set the replacement text per response.when RULE_INIT { Log debug messages to /var/log/ltm? 1=yes, 0=no. set ::collect_debug 1 A regular expression which describes what strings to replace (wrap the regex in curly braces). set ::find_regex {about:blank} set ::find_regex {[a-zA-Z]+} set ::find_regex {[0-9]+} The string to insert in replacement of the matched string(s) set ::replacement_string "abc" set ::replacement_string "x" } when HTTP_REQUEST { Don't allow response data to be chunked if { [HTTP::version] eq "1.1" } { Check if this is a keep alive connection if { [HTTP::header is_keepalive] } { Replace the Connection header with Keep-Alive HTTP::header replace "Connection" "Keep-Alive" } Set the serverside version to 1.0 HTTP::version "1.0" } } when HTTP_RESPONSE { Only check responses that are a javascript content type if {[HTTP::header "Content-Type"] eq "application/x-javascript"} { if {$::collect_debug}{log local0. "Received javascript response"} Get the content length to collect if { [HTTP::header exists "Content-Length"] } { set content_length [HTTP::header "Content-Length"] } else { set content_length 1000000000 } if { $content_length > 0 } { if {$::collect_debug}{log local0. "Collecting $content_length"} Collect the content HTTP::collect $content_length } } } when HTTP_RESPONSE_DATA { if {$::collect_debug}{log local0. "original payload: [HTTP::payload]"} Find all the match strings in one pass (-indices saves the start and end index of each match to a list) set match_indices [regexp -all -inline -indices $::find_regex [HTTP::payload]] if {$::collect_debug}{log local0. "match_indices = $match_indices"} Initialize a variable to track the offset of the match set match_offset_len 0 Loop through the indices and replace the matching strings with the replacement string foreach match_index $match_indices { Take the first match's start index and adjust it if the payload has already been changed by a previous match set match_start [expr [lindex $match_index 0] - $match_offset_len] if {$::collect_debug}{log local0. "match_start = $match_start"} Take the first match's end index and adjust it if the payload has already been changed by a previous match set match_end [expr [lindex $match_index 1] - $match_offset_len + 1] if {$::collect_debug}{log local0. "match_end = $match_end"} Calculate the length of the match set match_len [expr $match_end - $match_start] if {$::collect_debug}{log local0. "match_len = $match_len"} Calculate the length of the offset based on the past offset plus the difference between the current match and the replacement string set match_offset_len [expr $match_offset_len + $match_len - [string length $::replacement_string]] if {$::collect_debug}{log local0. "match_offset_len = $match_offset_len"} For debug purposes, save and log the string which was matched set match_string [string range [HTTP::payload] $match_start [expr $match_end - 1]] if {$::collect_debug}{log local0. "match string = $match_string"} Replace the match with the replacement string HTTP::payload replace $match_start $match_len $::replacement_string Log the updated payload if {$::collect_debug}{log local0. "updated payload: [HTTP::payload]"} } }
- smp_86112
Cirrostratus
I'm sorry I never got around to thanking you for this post. Very thorough and nicely written. Worked great!
Recent Discussions
Related Content
DevCentral Quicklinks
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com
Discover DevCentral Connects