Hi All,
Please review and provide input on the initial draft of upgrade proposal.
Thanks.
Shing Wai Chan
Introduction and Assumptions
* Upgrade requests for protocols that should be transparent to
existing servlets (e.g., "TLS") will be handled by built-in code in
the web container; we do not intend to make this support extensible.
* Upgrade requests for new protocols that will be exposed through new
APIs (e.g., web sockets), are the subject of this upgrade support in
the servlet API.
* We assume that a given endpoint need only support "one" of these
protocols. That is, we don't have to design to support an upgrade
request to "websockets, wombats", where websockets and wombats are
independent protocols. This means the servlet at a given endpoint
can be specific to the protocol expected to be used with that endpoint.
* TBD is how to handle an upgrade to "websockets, TLS", where one of
the protocols is a built-in protocol.
* There will be a single URL namespace on the server, shared by all
endpoints no matter which protocol they might be using.
* The interface between the web container and the protocol handler can
be in terms of byte streams, with the protocol handler assembling
the byte streams into messages or whatever abstraction it wants to
present to its clients. The web sockets API is not expected to
expose byte streams.
APIs
* We define two new classes in javax.servlet.http:
package javax.servlet.http;
public interface WebConnection {
public InputStream getInputStream();
public OutputStream getOutputStream();
}
package javax.servlet.http;
public interface ProtocolHandler {
public void init(WebConnection wc);
public void inputAvailable(WebConnection wc);
public void outputReady(WebConnection wc);
}
Note: the use of streams and notification methods in these interfaces
will need to be made consistent with any non-blocking I/O support added
to the Servlet API. Consider this a rough sketch to give you the general
idea of how this could work.
* Servlet container will provide a HTTP upgrade mechanism. And Servlet
container itself will have no knowledge about the upgraded protocol.
The protocol processing is encapsulated in
javax.servlet.http.ProtocolHandler. And a new API will be added to
javax.servlet.http.HttpServletRequest:
/**
* This notifies the servlet container that the given ProtocolHandler would be
* to upgrade the request.
*
* @param handler
*/
protected void upgrade(ProtocolHandler handler);
o When a upgrade request is sent to web container and if one
decides to do an upgrade,
HttpServletRequest#upgrade(ProtocolHandler) will then be
invoked. The application prepares and sends an appropriate
response to the client as usual.
o At this point the web container unwinds all the servlet filters
and marks the connection to be handled by the protocol handler.
It then calls the protocol handler's init method with a
WebConnection object that provides access to the data streams.
o When new data on the connection is ready to read, the web
container notifies the protocol handler by calling
#inputAvailable method. The protocol handler read the data, and
can assemble it into a new protocol message if necessary. When
it has enough data to form a complete message, the message will
be passed to a new protocol component. Then a response of the
given protocol will be prepared and written to the client when
the ProtocolHandler#outputReady method is invoked. Both input
and output will be non-blocking (depending on non-blocking support.)
* The servlet filters only process the initial http request and
response. They aren't invoked at all for subsequent data on the
connection. In other words, it does "not" process the "upgraded"
request and response.
WebSocket as an example of upgrade (not part of Servlet spec)
* The web sockets runtime provides a ServletContainerInitializer
annotated with @HandlesTypes(WebSocket.class). The initializer
handles all the web socket components and uses
ServletContext.addServlet() to add an implementation-specific
WebSocketsServlet at the endpoint corresponding to each web sockets
component.
The WebSocketServlet.service method does this:
o check that it's a GET request (or any other limitations on the
type of request allowed for web sockets)
o check that the "Upgrade" header contains "webSocket" and the
"Connection" header is "Upgrade"
o if not, return an error response to the client
o call: new WebSocketsProtocolHandler(req, res)
That is, construct an implementation-specific protocol handler
for this web sockets request, passing it the HttpServletRequest
and HttpServletResponse objects that contain all the context
information the protocol handler might need.
o call: req.upgrade(handler)
Tell the web container to upgrade the connection to the new
protocol specified by the web sockets protocol handler.
o send a success response with status code 101 to the client
o return from the service method
* WebSocket will build on the top of the HttpServlet#upgrade mechanism.
As an example, it can be as follows:
One may define an annotation @WebSocket. The annotated class will
implement an interface having methods processing the Web Socket request,
for instance, #onOpen, #onClose, #onTimeout, #onMessage. And the web
socket runtime will also provide a WebSocketServlet.
* WebSocketsProtocolHandler is an implementation-specific class,
written by the same person who wrote the WebSocketsServlet class.
The constructor gave it all the context it needed about the request
to find the web sockets component corresponding to this endpoint and
to pass messages to the component.