Skip to main content
Last updated December 02, 2011 20:19, by Shing Wai Chan
=== Introduction and Assumption * 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: <pre name="java"> package javax.servlet.http; import javax.servlet.ServletInputStream; import javax.servlet.ServletOutputStream; public interface WebConnection { public ServletInputStream getInputStream(); public ServletOutputStream getOutputStream(); public void shutdownInput(); public void shutdownOutput(); public boolean isInputShutdown(); public boolean isOutputShutdown(); } </pre> <pre name="java"> package javax.servlet.http; public interface ProtocolHandler { public void init(WebConnection wc); public void inputAvailable(WebConnection wc); public void outputReady(WebConnection wc); } </pre> * 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: <pre name="java"> /** * This notifies the servlet container that the given ProtocolHandler would be * to upgrade the request. * * @param handler */ protected void upgrade(ProtocolHandler handler); </pre> ** 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. ** 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. ** 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: ** check that it's a GET request (or any other limitations on the type of request allowed for web sockets) ** check that the "Upgrade" header contains "webSocket" and the "Connection" header is "Upgrade" ** if not, return an error response to the client ** 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. ** call: req.upgrade(handler). Tell the web container to upgrade the connection to the new protocol specified by the web sockets protocol handler. ** send a success response with status code 101 to the client ** 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.
Please Confirm