HTTP POST redirect preserving POST data
Problem this snippet solves:
Use Javascript in an iRule to redirect HTTP POST requests to HTTPS. When an HTTP 30x redirect it sent to a client that has sent a POST request, the user-agent transparently issues a new GET request. As a result, the original POST request payload is lost.
The idea behind this iRule is when client sends a POST to an HTTP virtual server, LTM replies with an HTML page which contains a form. The form contains post-data that the client just sent. The form will be auto-submitted by Javascript via HTTPS.
Here is how this iRule works:
- if method = post, it issues HTTP::collect, which will invoke HTTP_REQUEST_DATA
-
then it scans POST-data and prepares new content to respond to client. the new content will include
- form with all INPUT field names retrieved from POST-data
- the "action" parameter in the form points to external server
- all input fields are set as hidden (so client won't see the data during the process)
- Javascript that submits the form automatically
- then iRule replies to client with HTTP::respond command with content prepared in step 2
Code :
when RULE_INIT {
set static::ext_url "https://10.10.71.3/test.post"
}
when HTTP_REQUEST {
# Check if request was a POST
if { [string tolower [HTTP::method]] eq "post" } {
# Check if there is a Content-Length header
if { [HTTP::header exists "Content-Length"] } {
if { [HTTP::header "Content-Length"] > 1048000 }{
# Content-Length over 1Mb so collect 1Mb
set content_length 1048000
} else {
# Content-Length under 1Mb so collect actual length
set content_length [HTTP::header "Content-Length"]
}
} else {
# Response did not have Content-Length header, so use default of 1Mb
set content_length 1048000
}
# Don't collect content if Content-Length header value was 0
if { $content_length > 0 } {
HTTP::collect $content_length
}
}
}
when HTTP_REQUEST_DATA {
set content "< script type=text/javascript language=javascript> \
function s(){ document.f.submit(); } \
"
HTTP::respond 200 content $content
}4 Comments
- Victor_Plohod
Nimbostratus
Hello, I'm trying to use your code on a VS where I configured https://devcentral.f5.com/s/articles/redirect-non-ssl-requests-on-ssl-virtual-server-rule I'm a noob in the irule world. 1. What is the role of ext_url "; . 2. Should I merge the code into one irule or apply two distinct irules on the VS
 
- Stanislas_Piro2
Cumulonimbus
Hi,
A 307 status code is created to ask the client to preserve the method and the content on the new location
- Stanislas_Piro2
Cumulonimbus
@victor Plohod, try this irule
when HTTP_REQUEST { Check if the client used an SSL cipher if {not ([catch {SSL::cipher version} result]) && [string tolower $result] ne "none"}{ Client did use a cipher log local0. "\$result: $result. Allowing encrypted request." } else { Client did not use a cipher log local0. "\$result: $result. Redirecting unencrypted request." if { [HTTP::method] eq "POST" } { HTTP::respond 307 "https://[HTTP::host]/" } else { HTTP::respond 302 "https://[HTTP::host]/" } } } - Chris_Baiocchet
Nimbostratus
Hello,
Am curios about the statement:
set static::ext_url ";
is test.post generic and able to be used anywhere, or would I need to replace it with an entry specific to my environment?
Thanks in advance,
Chris
Help guide the future of your DevCentral Community!
What tools do you use to collaborate? (1min - anonymous)