Forum Discussion
ouch_32572
Nimbostratus
Mar 19, 2009irule to rewrite steam in request
Hi All,
I have an issue that i have manged to resolve on another Lb (zxtm)
I need help translating my rule into an irule for f5.
how do i rewite the stream on an incomming request (before it gets sent to the pool)
here is my zxtm rule.
Read the entire request body
$body = http.getBody();
$body = string.regexsub( $body, "https://10.104.30.55", "http://10.104.30.55", "gi" );
It is pretty basic,
in english..
i want to get the body of the request and replace https: with http:
here is what i think the rule should look like, is it correct?
when HTTP_REQUEST {
Disable the stream filter by default
STREAM::disable
STREAM::expression "@https://10.104.30.55@http://10.104.30.55@"
Enable the stream filter for this request only
STREAM::enable
}
32 Replies
- hoolio
Cirrostratus
Hi,
You may want to only enable the stream profile if the request is a POST with a content-length value greater than 0:when HTTP_REQUEST { Check if request is a POST and Content-Length header is > 0 if {[HTTP::method eq "POST" && \ [HTTP::header exists "Content-Length"] and [HTTP::header "Content-Length"] > 0}{ Set the stream find/replace STREAM::expression "@https://10.104.30.55@http://10.104.30.55@" Enable the stream filter for this request only STREAM::enable } else { Disable the stream filter by default STREAM::disable } } when HTTP_RESPONSE Disable the stream filter for the response STREAM::disable }
Make sure you add a blank stream profile to the virtual server and create a custom HTTP profile with response chunking set to rechunk. I think you may also want to disable the stream filter for the response so it's not applied to the response payload.
You can check the STREAM::expression wiki page (Click here) for details on the command.
You could also add code to log the match in the STREAM_MATCHED event (Click here) when debugging the iRule.
Aaron - ouch_32572
Nimbostratus
Hi,
I have tried the rule above and encounter the error below.
01070151:3: Rule [NEW_QAS] error:
line 4: [parse error: PARSE missingBracket 87 {missing close-bracket}] [{[HTTP::method eq "POST" && \ [HTTP::header exists "Content-Length"] and [HTTP::header "Content-Length"] > 0}]
When i tried my rule in the first post i cannot post any files to the system so i am guessing there is also something wrong with my basic rule.
Regards
Garry - lmwf1_55268
Nimbostratus
Try this and post it back here. It saved ok for me without any error.
when HTTP_REQUEST {
if { [HTTP::method] equals "POST" && [HTTP::header exists "Content-Length"] and [HTTP::header "Content-Length"] > 0} {
STREAM::expression "@https://10.104.30.55@http://10.104.30.55@"
STREAM::enable
} else {
STREAM::disable
}
}
when HTTP_RESPONSE {
STREAM::disable
} - hoolio
Cirrostratus
The issue may have been with a trailing space after the forward slash:if {[HTTP::method eq "POST" && \ [HTTP::header exists "Content-Length"] and [HTTP::header "Content-Length"] > 0}{
As lmwf1 pointed out you could also combine these two lines onto one and remove the \.
Aaron - ouch_32572
Nimbostratus
Hi All,
I have now uploaded the rule but it doesnt work, i think the issue is in the way i am aproaching it somehow.
Whats happening now is that when i post a file to the site it just hangs...and then eventually times out.
This is what i am trying to acheive.
request:
https client post request>>Lb rewrites https to http>>http app server
response:
http app server>>Lb rewrites http to https >> https client>
The reponse part of my rule works.
here is my full rule...
when HTTP_REQUEST {
if { [HTTP::method] equals "POST" && [HTTP::header exists "Content-Length"] and [HTTP::header "Content-Length"] > 0} {
STREAM::expression "@https://10.104.30.55@http://10.104.30.55@"
STREAM::enable
} else {
STREAM::disable
}
}
when HTTP_RESPONSE {
Disable the stream filter by default
STREAM::disable
HTTP::header remove "Pragma"
HTTP::header replace Server "NotReplaced"
if { [HTTP::header Content-Type] contains "text/html;charset=UTF-8" or [HTTP::header Content-Type] contains "application/x-javascript" } {
HTTP::header replace Server "Replaced"
STREAM::expression "@http://10.104.30.55@https://10.104.30.55@"
Enable the stream filter for this response only
STREAM::enable
}
}
regards
Garry - hoolio
Cirrostratus
Hi Garry,
I wonder if the problem is with the Content-Length on the request not being updated when you replace https with http (content-length should be updated to what it was minus 1). I was thinking of response rewriting when I suggested adding an HTTP profile with chunking set to rechunk. Unfortunately, the rechunking only applies to responses being sent to the client, not requests being sent to the pool.
You could test this by seeing if it works correctly if you add a space to the replacement string (so the content length doesn't need to be changed:when HTTP_REQUEST { ... STREAM::expression "@https://10.104.30.55@ http://10.104.30.55@"
If this is the issue and you cannot insert a space or other filler character, I think you'd need to use HTTP::collect to collect the request payload and 'HTTP::payload replace' to update it, so the Content-Length header will be updated.
Aaron - hoolio
Cirrostratus
Hi Garry,
Here is an untested example. Try the first one with logging and if it works, then try the second one.when HTTP_REQUEST { Check if request is a POST if {[HTTP::method] eq "POST"}{ Trigger collection for up to 1MB of data if {([HTTP::header exists "Content-Length"]) && ([HTTP::header "Content-Length"] <= 1000000)}{ set content_length [HTTP::header "Content-Length"] } else { set content_length 1000000 } if { [info exists content_length] } { HTTP::collect $content_length } } } when HTTP_REQUEST_DATA { String option to replace https://10.104.30.55 with http://10.104.30.55 in the payload set payload_new [string map "https://10.104.30.55 http://10.104.30.55" [HTTP::payload]] Regex option regsub -all "https://10.104.30.55" [HTTP::payload] "http://10.104.30.55" payload_new log "[IP::client_addr]:[TCP::client_port]: Replacing payload with new data $payload_new" Replace the old payload with the updated one HTTP::payload replace 0 [HTTP::payload length] $payload_new }
Or with fewer intermediate variables:when HTTP_REQUEST { Check if request is a POST if {[HTTP::method] eq "POST"}{ Trigger collection for up to 1MB of data if {([HTTP::header exists "Content-Length"]) && ([HTTP::header "Content-Length"] <= 1000000)}{ set content_length [HTTP::header "Content-Length"] } else { set content_length 1000000 } if { [info exists content_length] } { HTTP::collect $content_length } } } when HTTP_REQUEST_DATA { Replace https://... with http://... in the payload HTTP::payload replace 0 [HTTP::payload length] [string map -nocase "https://10.104.30.55 http://10.104.30.55" [HTTP::payload]] }
Aaron - ouch_32572
Nimbostratus
Hi All,
iI now get the followingin the browser.
Connection Interrupted
The document contains no data.
when HTTP_REQUEST {
if { [HTTP::method] equals "POST" && [HTTP::header exists "Content-Length"] and [HTTP::header "Content-Length"] > 0} {
regsub -all "https://10.104.30.55" [HTTP::payload] "http://10.104.30.55" newdata
log "Replacing payload with new data."
HTTP::payload replace 0 $clen $newdata
HTTP::release
}
}
Is there way of working out the content length of the new stream and replacing the header rather than using payload.
e.g something like..
when HTTP_REQUEST {
if { [HTTP::method] equals "POST" && [HTTP::header exists "Content-Length"] and [HTTP::header "Content-Length"] > 0} {
STREAM::expression "@https://10.104.30.55@http://10.104.30.55@"
HTTP::header replace "Content-Length" [HTTP::payload length]
STREAM::enable
} else {
STREAM::disable
}
}
The network link was interrupted while negotiating a connection. Please try again. - ouch_32572
Nimbostratus
Hi,
Just spotted an error in my rule...i havent defined $clen
when HTTP_REQUEST {
if { [HTTP::method] equals "POST" && [HTTP::header exists "Content-Length"] and [HTTP::header "Content-Length"] > 0} {
regsub -all "https://10.104.30.55" [HTTP::payload] "http://10.104.30.55" newdata
log "Replacing payload with new data."
HTTP::payload replace 0 [HTTP::payload length] $newdata
HTTP::release
}
} - hoolio
Cirrostratus
Can you try the second example I posted before? The rule you posted has a few errors in that it doesn't check the request method and doesn't define $clen.
Thanks,
Aaron
Help guide the future of your DevCentral Community!
What tools do you use to collaborate? (1min - anonymous)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
