Optimize delegation with HTTP options

The delegation mechanism for a service can be optimized using HTTP OPTIONS.

The delegation mechanism can be configured to avoid sending the original request body destined for the final proxy to the delegate service, when it is not needed as part of an authorization request.

When configured, only the headers are sent, from which the delegate service determines whether the original request body can be sent to the final proxy. Use the DELEGATE_OPTIONS element for this configuration.

Delegate optimization example

When DELEGATE_OPTIONS with verb="OPTIONS" is set, the following original HTTP POST request is transformed as shown in the example requests:

POST /ws/r/my_service HTTP/1.1
Content-Type: text/plain
Authorization: Bearer Token_ID
User-Agent: GWS Agent
Date: Mon, 16 Jul 2018 14:39:43 GMT
Host: localhost:6363
Connection: close
Content-Length: 11
X-FourJs-Environment-Variable-REMOTE_ADDR: 127.0.0.1
X-FourJs-Environment-Variable-SERVER_NAME: localhost

Hello world

It is then for optimization purpose, transformed by the dispatcher as an HTTP OPTIONS request to the delegation service:

OPTIONS /ws/r/my_delegate/Delegate?url=http://localhost:6363/ws/r/my_service HTTP/1.1
Content-Type: text/plain
Authorization: Bearer Token_ID
User-Agent: GWS Agent
Date: Mon, 16 Jul 2018 14:39:43 GMT
Host: localhost:6363
Connection: close
Access-Control-Request-Method: POST
Content-Length: 0
X-FourJs-Environment-Variable-REMOTE_ADDR: 127.0.0.1
X-FourJs-Environment-Variable-SERVER_NAME: localhost
In this example, you can see:
  1. It removes the body of the original request, ("Hello World").
  2. It keeps the original headers (it sets the body length to zero, Content-Length: 0).
  3. It adds a new HTTP header (Access-Control-Request-Method: POST) to provide the original HTTP request verb (for example POST) to the delegate service.

Delegate service responses

The delegate service may return one of the following responses to the optimized request, and the dispatcher takes appropriate action:
  • If the delegate service agrees to transmit the request to the final proxy, it returns the HTTP code 307 response. The dispatcher then forwards the original request plus the message body to the final proxy.
  • In the case that the delegate service returns something other than HTTP code 307, the dispatcher will then discard the original request body and the original request will get the delegate response (plus body) as response (standard delegation mechanism).

Example

In this sample web service server code you see it is using OPTIONS to handle RESTful requests to optimize delegation.

FUNCTION DoDelegate(req)
  DEFINE  req           com.HttpServiceRequest
  DEFINE  query         WSHelper.WSQueryType
  DEFINE  ori_url       STRING
  DEFINE  access_token  STRING
  DEFINE  ind           INTEGER
  DEFINE  method        STRING

  # Ensure we work in optimized delegation via OPTIONS
  IF req.getMethod()!="OPTIONS" THEN
    CALL req.sendResponse(400,"bad delete request, HTTP OPTIONS verb required");
    RETURN
  END IF

  # Ensure we got the Access-Control-Request-Method header
  LET method = req.getRequestHeader(C_ACCESS_CONTROL_REQUEST_METHOD)
  IF method IS NULL THEN
    CALL req.sendResponse(400,"bad delete request, Access-Control-Request-Method is missing");
    RETURN
  END IF

  # Ensure we have a valid delegate request
  CALL req.getUrlQuery(query)
  IF query[1].name!="url" THEN
    CALL req.sendResponse(400,"bad delete request, no url found");
    RETURN
  END IF

  # Extract original URL
  LET ori_url = query[1].value
  CALL query.deleteElement(1)

  # Retrieve access token from query string
  LET ind = query.search("name","access_token")
  IF ind>0 THEN
    LET access_token = query[1].VALUE
  ELSE
    CALL req.sendResponse( 401, "No access token found")
    RETURN
  END IF

  # Check Access
  IF CheckAccess(req, baseURL, method, ori_url, access_token) THEN

    CALL req.sendResponse( 307, "GENERO_INTERNAL_DELEGATE")
  ELSE

    CALL req.sendResponse( 403, "Forbidden")
  END IF

END FUNCTION