https://issues.apache.org/bugzilla/show_bug.cgi?id=54728
Bug ID: 54728 Summary: HttpServletRequest#upgrade() and other interfaces don't match spec; change may be impossible to implement Product: Tomcat 8 Version: trunk Hardware: All OS: All Status: NEW Severity: critical Priority: P2 Component: Catalina Assignee: dev@tomcat.apache.org Reporter: nicho...@nicholaswilliams.net Classification: Unclassified Created attachment 30081 --> https://issues.apache.org/bugzilla/attachment.cgi?id=30081&action=edit Patch that doesn't work #1 More information in http://tomcat.markmail.org/thread/wsvablpkzagyrg6g. Spec change discussed here: http://java.net/projects/servlet-spec/lists/jsr340-experts/archive/2012-11/message/9 As discussed in Servlet spec mailing list, Shing's idea was: <quote> And we will require that the class passed in has a no ops constructor. In this case, the user can configure the HttpUpgradeHandler instance before upgrade processing and will be benefited by dependency injection. </quote> In the Proposed Final Draft of the spec, this was further defined: <quote> When an upgrade request is received, the servlet can invoke the HttpServletRequest.upgrade method, which starts the upgrade process. This method instantiates the given HttpUpgradeHandler class. The returned HttpUpgradeHandler instance may be further customized. The application prepares and sends an appropriate response to the client. After exiting the service method of the servlet, the servlet container completes the processing of all filters and marks the connection to be handled by the HttpUpgradeHandler. It then calls the HttpUpgradeHandler's init method, passing a WebConnection to allow the protocol handler access to the data streams. </quote> There are some fundamental problems here, and this may need to be escalated to the spec level (in my opinion, this change was a significant DISimprovement of the spec): 1) In Tomcat, specifically, this change shakes the foundation of how WebSockets has been implemented. The HttpUpgradeHandler's init() method is supposed to be called AFTER the Servlet's service() method returns. But how? Who is supposed to call this? The constructor for AbstractProcessor is the only thing currently calling init(). I tried to dive into how to refactor that, and my eyes started bleeding. It goes deep into event dispatching in the Nio, Bio and Ajp processors. I don't see a clean way (I don't see ANY way) to change this. At the very least, someone with MUCH more Tomcat expertise than I will have to tackle that. 2) The original purpose of the upgrade() method, supposedly, is to upgrade the request. But, according to the paragraph above, the only purpose of the upgrade() method now is to construct an instance of the class you pass into it and return that instance...as if you couldn't do that more easily by simply using the constructor. It sounds like the request doesn't ACTUALLY get upgraded until LATER. What it boils down to is that you need a fully-wired HttpUpgradeHandler in order to actually upgrade the request, so either init() cannot be called from upgrade() (in which case the upgrade() method is now pointless, IMO), or an already-wired instance of HttpUpgradeHandler (not a class) needs to be passed in to upgrade, like it was before. I took two approaches to this. The first (obvious) one was to create an doAfterUpgrade() method on WsUpgradeHandler to be called by WsServlet after it calls upgrade(). This method took the parameters originally passed to the constructor. Unfortunately, by the time execution got to the doAfterUpgrade() method, the socket was already trying to read/write data and it had no endpoint to do it to. NullPointerExceptions abounded (in o.a.coyote.http11.upgrade.AbstractProcessor#upgradeDispatch()). It compiles, but it doesn't upgrade. I've attached that patch. I then tried a trick to achieve wiring-before-instantiation using a local class, but Java was too smart for me. It replaced my no-arg constructor with an arg constructor, and it couldn't be instantiated. I'll attach that patch in a comment to follow this up. -- You are receiving this mail because: You are the assignee for the bug. --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org