HTTP method conversion
Problem this snippet solves:
This is one way that allows you to convert HTTP method from GET to POST or POST to GET transparently by LTM.
Why?
- you want to hide something from users. (make it simpler for them)
- create meta proxy that also proxy auth and does auto-logon (or limited SSO)
- I don't know. I think it is fun.
What technique are used here?
- vip targeting vip
- HTTP::retry
- HTTP::respond
How does it work?
- configure 2 virtual servers one for normal HTTP load balance and another one to receive http request from virtual www1 and return back converted request. For example virtual www1 listens on 10.10.10.10:80 and point to pool webpool. Virtual www2 listen on 10.10.10.10:81 and has no pool assigned.
- virtual www1 receives http request from external clients and send selected request to virtual www2
- virtual www2 converts http request (for GET-to-POST, turn GET uri query string to POST data and for POST-to-GET, turn POST data to GET uri query string)
- virtual www2 responds back with "converted request" as its content
- virtual www1 receives HTTP_RESPONSE and do HTTP::retry with this "converted request"
Note: * This iRule is not perfect. It needs more development if you would like to use it. Feel free to put comment.
Code :
# rule for virtual www1
when HTTP_REQUEST {
log local0. "[HTTP::request]"
# send httprequest which you want to convert to another virtual
# if [HTTP::uri] match what I want
virtual www2
# else do nothing
}
when HTTP_RESPONSE {
# use special status and/or remote_addr to identify
# whether it comes back from real server or virtual www2
if { [HTTP::status] == 555 } {
HTTP::collect [HTTP::header Content-Length]
set reselect 1
}
}
when HTTP_RESPONSE_DATA {
# probably add routine to verify
# send converted http_request to real server
log local0. "[HTTP::payload]"
HTTP::retry [HTTP::payload]
}
when LB_SELECTED {
# if http_retry is called, same destination may be picked (which is virtual www2)
# change the destination to real server (use node or pool command)
if { [info exists reselect ] } {
LB::reselect node 10.10.72.1 80
unset reselect
}
log local0. "[LB::server]"
}
# rule for virtual www2
when HTTP_REQUEST {
switch [HTTP::method] {
GET {
log local0. "uri = [HTTP::uri]"
log local0. "query = [HTTP::query]"
set query [HTTP::query]
# strip off query string
HTTP::uri [HTTP::path]
# add Content-Type and Content-Length header
HTTP::header insert Content-Type "application/x-www-form-urlencoded"
HTTP::header insert "Content-Length" [string length $query]
# strip off "GET "
set request [substr [HTTP::request] 4]
# create new request starts with POST
# follow by original header (with modified uri)
# and POST data (derived from query string)
# according to http encoding, some characters may need attention
# for example, space is %20 in GET uri but + in POST data
HTTP::respond 555 content "POST $request$query"
}
POST {
log local0. "len = [HTTP::header Content-Length]"
log local0. "req = [HTTP::request]"
# collect POST data
HTTP::collect [HTTP::header Content-Length]
}
}
}
when HTTP_REQUEST_DATA {
# prepare GET uri query string
set query [HTTP::payload]
# according to http encoding, some characters may need attention
# for example, space is %20 in GET uri but + in POST data
HTTP::uri "[HTTP::uri]?$query"
# we don't need Content-Type and Content-Length anymore
HTTP::header remove Content-Type
HTTP::header remove Content-Length
# remove POST data
HTTP::payload replace 0 [HTTP::payload length] ""
# strip off "POST "
set request [substr [HTTP::request] 5]
HTTP::respond 555 content "GET $request"
}Published Mar 18, 2015
Version 1.0Nat_Thirasuttakorn
Employee
Joined September 25, 2004
Nat_Thirasuttakorn
Employee
Joined September 25, 2004
2 Comments
- IheartF5_45022
Nacreous
Hi there. Thanks for the idea for this - I've managed to streamline this into a single virtual/iRule and the code is here https://devcentral.f5.com/s/feed/0D51T00006j2lHBSAY at the bottom, but it's based on my reading this post. - Przemyslaw_Wyr1
Altocumulus
Hi There. The link does not works