The servlet container is responsible for automatically forwarding the following responses received for a proxying operation upstream:
z all informational responses other than 100
z the best response received when final responses have been received from all destinations.
z all 2xx responses for INVITE
z exactly one 2xx response for non-INVITE as per [RFC 3261 16.7, para - Check responses for forwarding]
Additionally, if the supervised flag is true, the servlet engine invokes the application for these responses before forwarding them upstream. The application may modify responses in the notification callback. In this case the modified responses are forwarded upstream. This is useful,
for example, for application level gateways that need to modify addresses in the body of responses.
As in the UAC case, applications are not invoked for incoming 100 responses.
When a 6xx response is received, the server CANCELs all outstanding branches and will not create new branches. Similarly, when a 2xx response is received, the server CANCELs all outstanding branches and will not create new branches unless the proxy is configured to not cancel branches with setNoCancel(true).
When an application is invoked to handle the best final response received and it is not a 2xx or 6xx, the application may add addresses for further destinations through the Proxy.proxyTo method or by creating additional proxy branches and re-starting the proxy. The effect is that a new branch is created for each additional destination, as if the method had been invoked before a (tentative) best answer had been passed to the application. If, in the upcall informing a servlet of the best response received, the servlet proxies to one or more additional destinations, the container does not immediately forward the best response received so far as the new branch may result in a “better” response. The ability to call proxyTo in the callback for best response received is useful, for example, for writing call-forward-no-answer type services.
A consequence of the described behavior is that an application may be notified of more than one final response for a transaction. This can happen either because
1. the application proxied to more destinations in the notification for a final response 2. one or more 2xx retransmissions were received, see 11.2.4.1 Handling 2xx Responses to
INVITE below
3. multiple destinations returned 2xx responses.
In the first two cases, the application may end up being notified of the same final response more than once.
11.2.4.1 Handling 2xx Responses to INVITE
The 2xx responses to INVITEs are special in that they cause both client and server transactions to terminate immediately with retransmissions bypassing the transaction layer [RFC 3261, sections 13.3.1.4 and 17.1.1].
Ordinarily, SIP proxies handle 2xx retransmissions by forwarding them statelessly upstream based on the Via header field. In the case of an application server, we have the additional complication that one or more of the proxying applications (there may be more than one due to application composition) may wish to modify the 2xx response before it’s forwarded upstream.
O p e r a t i o n
In this case it’s necessary to ensure that 2xx retransmissions are modified in the exact same way as the 2xx first received for the INVITE.
This can be achieved in several different ways and it is left to implementations to choose one. One solution is to not terminate INVITE client and server transactions when first seeing a 2xx for an INVITE. This enables the application server to handle 2xx retransmissions in a manner similar to the original 2xx, that is, invoke applications as necessary and then forward it upstream. For this reason, applications proxying INVITEs must be prepared to receive retransmissions of 2xx responses and must modify such retransmissions the same way they did the 2xx originally received.
11.2.4.2 Correlating responses to proxy branches
When notified of an incoming response, it is sometimes useful for applications to be able to determine which of several branches the response was received for when there was more than one branch outstanding. Applications identify branches by request URI, and so to test whether a response was for a particular branch it is sufficient to compare the request URI of that branch with the URI object previously passed to the proxyTo or createProxyBranches method by the application.
For incoming responses to proxied requests, SipServletResponse.getRequest() returns a SipServletRequest object representing the request that was sent on the branch on which the response was received. The request URI can then be obtained from the branch request object and be compared against destination URIs previously passed to the proxyTo or
createProxyBranches method.
Containers are required to ensure that the request URI of the branch’s request object is equal to the URI object that the application passed to the proxyTo method. (Recursion can, of course, cause branches to get created that the application didn’t explicitly request and for which it has no URI.)
Servlets may be interested in being notified of intermediate final responses before the best final response is selected as per [RFC 3261, Section 16.6]. Version 1.0 of this specification did not offer any mechanism to peek at these intermediate responses.
To handle final responses received on each proxy branch, this specification introduces a new method on the Servlet class – doBranchResponse(SipServletResponse resp) . A servlet implementation that is interested in being notified of intermediate final responses received on individual branches must override this method. This method will be invoked by the container only if the supervised flag is true for the Proxy. A typical use-case for using the
doBranchResponse method would be to create and proxy to additional branches on the receipt of a non-2xx final response.
Any attempt to add additional branches in doBranchResponse() for a cancelled branch or a cancelled proxy will result in IllegalStateException. Only after the last branch has received a final response, the container must determine the best final response and pass it to the
doResponse() method. Note that if the doBranchResponse() is not overridden then doResponse() method will be invoked only for the best final response as before.
11.2.4.3 Sequential Search Timeout
As of v1.1 of this specification the sequential search timeout may only be set using the general proxyTimeout parameter rather than the sequentialSearchTimeout parameter which has now been deprecated.
This section clarifies the case where a SIP servlet is acting as a sequential search proxy and the sequential search timout has expired before a final response has been received for the current branch.
The sequential search timeout defined by the SIP servlet API is sematically similar to the Timer C with some differences explained below.
The following procedure describes the handling in case of sequential searches, sequential search timer is referenced as SST:
1. Forward request and start branch.
2. Start the SST on receipt of a provisional response. SST does not start before a provisional response is received.
3. If SST expired but final response not received then send a CANCEL to the INVITE transaction and move on to the next branch.
4. If SST value is greater than Timer-C then Timer-C SHOULD assume the value of SST. 5. If final response received within SST, then process response normally.
11.2.4.4 Handling 3xx responses
If the recurse flag of the proxy is set to false then it is up to the application developer to keep track of the contact addresses received in the redirect (3xx) responses. If the contact addresses received in multiple 3xx responses contain the same URI, the container SHOULD throw an
IllegalStateException if the application attempts to proxy to the same URI again. This is to prevent creation of duplicate branches.
O p e r a t i o n
If the recurse flag of the proxy is set to true then the container SHOULD proxy only to unique contact address ignoring any duplicates. This may result in a case where a branch does not recurse on receiving a 3xx response with an alternate contact as a branch for that contact already exists. Calling getRecursedProxyBranches() on such a branch would result in an empty list. Every recursed contact results in a new branch and duplicate contacts are ignored as per [RFC 3261, Section 16.5]. The container MUST remove the redirect contacts from the 3xx response since they have produced new branches. A 3xx response without any contacts can never be a best response of a proxy according to [RFC 3261 16.7, point 4] and should never be propagated up to the application.