redirects with get / post

We have created iRules to perform redirects on existing web services. All the rules appear to work correctly when performing a HTTPGet. However, when connecting from another application, the request comes across as an HTTPPost and is never redirected. I have verfied in the IIS logs that the request is never sent to its final destination (the server trying to redirect to). Is this something that can be fixed on the iRule, profile or the vip?

below is my irule.

when HTTP_REQUEST { if { ([string tolower [HTTP::host]]) contains “unity.mysite.com” } { switch -glob -- [string tolower [HTTP::uri]] { “akcelrons.asmx” { HTTP::redirect “https://webservice.mysite.com/Unity/akcelrons.asmx” } “credispher.asmx" { HTTP::redirect “http://webservice.mysite.com/Unity/credispher.asmx.asmx” } "interfaceser.asmx” { HTTP::redirect “https://webservice.mysite.com/Unity/interfaceser.asmx” } ::“meridian.asmx” { HTTP::redirect “https://webservice.mysite.com/Unity\[HTTP::uri]” } “unitysale.asmx" { HTTP::redirect “https://webservice.mysite.com/Unity/unitysale.asmx” } "unitywep.asmx” { HTTP::redirect “https://webservice.mysite.com/Unity/unitysale.asmx” } “weblott.asmx” { HTTP::redirect “https://webservice.mysite.com/Unity/Unityweblott.asmx” } } } }

If you look through the IIS logs there will most likely be a get request. When a POST request get a redirect it will be retried as a get request. you can use the following iRule to force the browser to send the request to the correct location

Please explain in more detail. If i already have the iRule from above where would I place HTTP_POST_redirectNew118.ashx. So how and where would I use your example?

the basic issue is that you can’t redirect (HTTP 3xx) a POST request, that is simply how redirects were designed.

the iRule that Richard mentions uses a trick to still be able to get the POST data through. it builds a piece of javascript that will take the information from the POST and send it again when the page loads.

if you want to include this into your code you could include the HTTP_REQUEST section completely. add a HTTP_REQUEST_DATA section and build a similar switch statement for the different POST urls based on URI.

Not to throw the conversation into a tangent, but are you certain that the iRule works with GET requests? You’re using a glob switch but no glob patterns, so not sure where the matches are being made. Here’s a slightly modified version of your iRule:

when HTTP_REQUEST { 
    if { ( [string tolower [HTTP::host]]) contains "unity.mysite.com" } { 
        switch -glob [string tolower [HTTP::uri]] { 
            "*akcelrons.asmx*" { 
                HTTP::redirect "https://webservice.mysite.com/Unity/akcelrons.asmx" 
            } 
            "*credispher.asmx*" { 
                HTTP::redirect "http://webservice.mysite.com/Unity/credispher.asmx.asmx" 
            } 
            "*interfaceser.asmx*" { 
                HTTP::redirect "https://webservice.mysite.com/Unity/interfaceser.asmx" 
            } 
            "*meridian.asmx*" { 
                HTTP::redirect "https://webservice.mysite.com/Unity[HTTP::uri]" 
            } 
            "*unitysale.asmx*" { 
                HTTP::redirect "https://webservice.mysite.com/Unity/unitysale.asmx" 
            } 
            "*unitywep.asmx*" { 
                HTTP::redirect "https://webservice.mysite.com/Unity/unitysale.asmx" 
            } 
            "*weblott.asmx*" { 
                HTTP::redirect "https://webservice.mysite.com/Unity/Unityweblott.asmx" 
            } 
        } 
    } 
}

First, thank you all for your help, Still having trouble understanding. Below is the exact irule from the LTM, other comments are from the Web Developer. Im in the middle F5 Admin and the HTTP Developer says it fails the Post. So help me to bridge the gap. Lets startover.. Kevin, let me give you the current iRule, below. Richard, Boneyard, are your comments for me of http developer?

when HTTP_REQUEST { if { ([string tolower [HTTP::host]]) contains “unitynet.mysite.com” } { switch -glob -- [string tolower [HTTP::uri]] { “akcelerantws.asmx” { HTTP::redirect “https://webservices.mysite.com/Unity/Akcelerantws.asmx” } “credispherewsv2.asmx" { HTTP::redirect “http://webservices.mysite.com/Unity/CrediSphereWSV2.asmx” } "interfaceservice.asmx” { HTTP::redirect “https://webservices.mysite.com/Unity/InterfaceService.asmx” } ::“meridianlinkws.asmx” { HTTP::redirect “https://webservices.mysite.com/Unity\[HTTP::uri]” } "unitysailws.asmx" { HTTP::redirect “https://webservices.mysite.com/Unity/UnitySAILWS.asmx”

} "unityweblet.asmx" { HTTP::redirect “https://webservices.mysite.com/Unity/UnityWeblet.asmx”

} “weblet.asmx” { HTTP::redirect “https://webservices.mysite.com/Unity/UnityWeblet.asmx” } } } }

The iRule was for the f5. The browser sending the post request will not resend the post request to the 302, it mite work if you send it a 307 that depends on the browser but it open up a security risk. The iRule in question will cause the browser to run some Javascript to redirect to the post to the correct location.

So are you saying that a POST request doesn’t get redirected at all, or that a POST request gets redirected, but is turned into a GET?

It get redirected to a GET request

Ok guys, so I have my original iRule and sample link from Richard. Now how in the heck to I merge these irule. Im not at the admin level need to script this, so I f you could help please.

::! This is my irule. : when HTTP_REQUEST { if { ([string tolower [HTTP::host]]) contains “unitynet.mysite.com” } { switch -glob -- [string tolower [HTTP::uri]] { “*akcelerantws.asmx*” { HTTP::redirect “https://webservices.mysite.com/Unity/Akcelerantws.asmx” } “*credispherewsv2.asmx*” { HTTP::redirect “http://webservices.mysite.com/Unity/CrediSphereWSV2.asmx” } “*interfaceservice.asmx*” { HTTP::redirect “https://webservices.mysite.com/Unity/InterfaceService.asmx” } ::“*meridianlinkws.asmx*” { HTTP::redirect “https://webservices.mysite.com/Unity\[HTTP::uri]” } “*unitysailws.asmx*” { HTTP::redirect “https://webservices.mysite.com/Unity/UnitySAILWS.asmx” } “*unityweblet.asmx*” { HTTP::redirect “https://webservices.mysite.com/Unity/UnityWeblet.asmx” } “*weblet.asmx*” { HTTP::redirect “https://webservices.mysite.com/Unity/UnityWeblet.asmx” } } } } ================================= ::! This is from https://clouddocs.f5.com/api/irules/HTTP\_POST\_redirectNew118.html : 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 switch -glob -- [string tolower [HTTP::uri]] { “*akcelerantws.asmx*” { HTTP::redirect “https://webservices.mysite.com/Unity/Akcelerantws.asmx” } “*credispherewsv2.asmx*” { HTTP::redirect “http://webservices.mysite.com/Unity/CrediSphereWSV2.asmx” } “*interfaceservice.asmx*” { HTTP::redirect “https://webservices.mysite.com/Unity/InterfaceService.asmx” } ::”*meridianlinkws.asmx*" { HTTP::redirect “https://webservices.mysite.com/Unity\[HTTP::uri]” } “*unitysailws.asmx*” { HTTP::redirect “https://webservices.mysite.com/Unity/UnitySAILWS.asmx” } “*unityweblet.asmx*” { HTTP::redirect “https://webservices.mysite.com/Unity/UnityWeblet.asmx” } “*weblet.asmx*” { HTTP::redirect “https://webservices.mysite.com/Unity/UnityWeblet.asmx” } } }

So how can I merge these to iRules.

as i posted earlier: if you want to include this (get into put irule) into your code you could include the HTTP_REQUEST section completely. add a HTTP_REQUEST_DATA section and build a similar switch statement for the different POST urls based on URI. just start with something simple and expand on it. please remember everyone here is answering in their spare time, cant expect them to do all the work for you. also try to format your posts, like they are now makes it really hard to read.

e.g.

root@(ve11a)(cfg-sync Not All Devices Synced)(Active)(/Common)(tmos) list ltm virtual bar
ltm virtual bar {
    destination 172.28.20.111:80
    ip-protocol tcp
    mask 255.255.255.255
    pool foo
    profiles {
        http { }
        tcp { }
    }
    rules {
        myrule
    }
    source 0.0.0.0/0
    source-address-translation {
        type automap
    }
    vs-index 28
}
root@(ve11a)(cfg-sync Not All Devices Synced)(Active)(/Common)(tmos) list ltm rule myrule
ltm rule myrule {
    when HTTP_REQUEST {
  if { ([string tolower [HTTP::host]]) contains "unitynet.mysite.com" } {
    switch -glob -- [string tolower [HTTP::uri]] {
      "*akcelerantws.asmx*" { set ext_url "https://webservices.mysite.com/Unity/Akcelerantws.asmx" }
      "*credispherewsv2.asmx*" { set ext_url "http://webservices.mysite.com/Unity/CrediSphereWSV2.asmx" }
      "*interfaceservice.asmx*" { set ext_url "https://webservices.mysite.com/Unity/InterfaceService.asmx" }
      "*meridianlinkws.asmx*" { set ext_url "https://webservices.mysite.com/Unity[HTTP::uri]" }
      "*unitysailws.asmx*" { set ext_url "https://webservices.mysite.com/Unity/UnitySAILWS.asmx" }
      "*unityweblet.asmx*" { set ext_url "https://webservices.mysite.com/Unity/UnityWeblet.asmx" }
      "*weblet.asmx*" { set ext_url "https://webservices.mysite.com/Unity/UnityWeblet.asmx" }
      default {
        return
      }
    }
  } else {
    return
  }

  if { [string tolower [HTTP::method]] eq "get" } {
    HTTP::redirect $ext_url
  } elseif { [string tolower [HTTP::method]] eq "post" } {
    if { [HTTP::header exists "Content-Length"] } {
      if { [HTTP::header "Content-Length"] > 1048000 }{
        set content_length 1048000
      } else {
        set content_length [HTTP::header "Content-Length"]
      }
    } else {
      set content_length 1048000
    }
    if { $content_length > 0 } {
      HTTP::collect $content_length
    }
  } else {
     do something
  }
}
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
}
}

 GET

[root@ve11a:Active:Not All Devices Synced] config  curl -i http://172.28.20.111/something/akcelerantws.asmx -H "Host: unitynet.mysite.com"
HTTP/1.0 302 Found
Location: https://webservices.mysite.com/Unity/Akcelerantws.asmx
Server: BigIP
Connection: Keep-Alive
Content-Length: 0

 POST

[root@ve11a:Active:Not All Devices Synced] config  curl -i --data "para1=value1&para2=value2" http://172.28.20.111/something/akcelerantws.asmx -H "Host: unitynet.mysite.com"
HTTP/1.0 200 OK
Server: BigIP
Connection: Keep-Alive
Content-Length: 372

< script type=text/javascript language=javascript>  function s(){ document.f.submit(); }

I trying to work on it and so are our developers. But we are having a problem understanding. Even if you could help with a sample. So I have the first part is by iRule and second part is your recommendation. We are havinging problems adding our current irule to your sample.

check what nitass posted, most of the work is done there already

All,

I am looking at this iRule and I have a few questions. Boneyard stated to build a similar switch statement for the different POST urls based on URI but is this really necessary? Won’t it work as is for all the URL/uri combos listed?

If I hit a site and requires the inputting of three pieces of data: UserName Password EmployeeID

Based on Nitass’ example, won’t it grab all three pieces of data automatically. If not, can you show a modification of the script to do just that? Please forgive my ignorance and educate me a bit, please…:slight_smile:

Thank you,

you might get confused because of the up vote of nitas last reply, which made it show up first, my comments were on the original question. nitas upvoted reply does the trick.

Got it. Makes sense Basically the last post by Nitass does the trick. My only concern is that this script still wouldn’t be the most efficient if there were many fields. If there are many fields of input, I work with the web developers and architect a different solution. Just my two cents. Any feedback is always appreciated.

it might work if there is full uniformity in the post URL then it might work without switch, but in this case the number of switch statements are required i believe.