cancel
Showing results for 
Search instead for 
Did you mean: 
Nat_Thirasuttakorn
F5 Employee
F5 Employee

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:

  1. if method = post, it issues HTTP::collect, which will invoke HTTP_REQUEST_DATA
  2. 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
  3. 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(); }  \
        
" foreach p [split [HTTP::payload] &] { set name [URI::decode [getfield $p = 1]] set value [URI::decode [getfield $p = 2]] set content "${content}" } set content "${content}
" HTTP::respond 200 content $content }
Comments
Victor_Plohod
Nimbostratus
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
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
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
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

 

Version history
Last update:
‎17-Mar-2015 17:07
Updated by:
Contributors