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.0
  • 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.