I was playing around with Jetty (9.2.3v20140905) by connecting a web socket endpoint where I tried to use my own ServerEndpointConfig when I came across Jetty's code to see how it was used.
I notice that it is used in JsrCreator when a web socket object is created:
Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp){
...
// modify handshake
configurator.modifyHandshake(config,hsreq,hsresp);
...
}
I read the javadoc of modifyHandshake of ServerEndpointConfig (javax.websocket-api 1.0) that states:
Called by the container after it has formulated a handshake response resulting from
a well-formed handshake request. The container has already
checked that this configuration has a matching URI, determined the
validity of the origin using the checkOrigin method, and filled
out the negotiated subprotocols and extensions based on this configuration.
Custom configurations may override this method in order to inspect
the request parameters and modify the handshake response that the server has formulated.
and the URI checking also.
If the developer does not override this method, no further
modification of the request and response are made by the implementation.
Here's what Jetty does:
Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp){
...
// modify handshake
configurator.modifyHandshake(config,hsreq,hsresp);
// check origin
if (!configurator.checkOrigin(req.getOrigin())){...}
...
resp.setAcceptedSubProtocol(subprotocol);
...
resp.setExtensions(configs);
}
As you can see, the origin is checked after the configurator as been called. The response is modified after the configurator as been called.
The method acceptWebSocket of WebSocketServerFactory makes a call to the WebSocketCreator:
Object websocketPojo = creator.createWebSocket(sockreq, sockresp);
And after that calls:
private boolean upgrade(HttpConnection http, ServletUpgradeRequest request, ServletUpgradeResponse response, EventDriver driver)
which also modifies the response via HandshakeRFC6455:
// build response
response.setHeader("Upgrade","WebSocket");
response.addHeader("Connection","Upgrade");
response.addHeader("Sec-WebSocket-Accept",AcceptHash.hashKey(key));
So I have no way modifying the response only with my configurator because Jetty will change it anyway.
It seems to me Jetty does not comply with JSR 356, the Java API for WebSocket, does it?
Ah, one of the many ambiguous and ill defined parts of the JSR-356 spec.
You might want to read the open bugs against the spec.
There are many real world examples of scenarios that are rendered impossible if the original 1.x spec is follow exactly.
Now, to tackle the specific details of your question:
Why is checkOrigin called after modifyHandshake in the Jetty implementation?
This is because there are valid scenarios (esp with CDI and Spring) where the information needed by a checkOrigin implementation by the end user is not valid, or exists, until the modifyHandshake call is called.
Basically, the endpoint Configurator is created, the modifyHandshake is called, and at that point, all of the library integration (CDI, Spring, etc.) starts, that's when the endpoint enters the WebSocket (RFC6455) CONNECTING state. (once the endpoint's onOpen is called, then the WebSocket RFC6455 state goes to the OPEN state)
As you have probably noticed, there's no definitions in the spec of the scopes and lifetimes of objects when CDI (or Spring) is involved.
The 1.x JSR356 spec actually distances itself from servlet container specific behavior, it was done to make the spec as generic as possible, with the ability to have non-servlet websocket server containers too. Unfortunately, that also means that there are many use cases in a servlet container that doesn't mesh with the 1.x JSR356 spec.
Once the JSR356 spec is updated to properly define the CDI scopes on WebSocket, then this quirk of checkOrigin after modifyHandshake can be fixed.
Why is the implementation modifying the response after modifyHandshake?
The implementation has to modify the response, otherwise the response is invalid for HTTP/1.1 upgrade, the need of the implementation to cooperate with the endpoint and its configuration, for sub protocols, and extensions makes this a reality. (Notice that the the JSR356 spec punts on Extensions?)
This is also an area that is promised to be corrected in the next JSR356 revision.
The current work on the WebSocket over HTTP/2 spec makes this even more interesting, as it isn't (currently) using the HTTP/1.1 upgrade semantic. It just comes into existence with a handshake only (no Upgrade, no Origin, etc).
Related
Jetty has this functionality where it can evict idle HttpSession objects out of memory and persist them on disk (passivation). Once a new request arrives with the same session id, it'll be brought back into memory (activation).
Jetty 9.2 and 9.3 source code for HashSessionManager and HashedSession reveals that the actual HttpSession instances are not discarded during idle eviction process but merely the attributes within them are cleared.
That tells me it is safe to keep a reference to a HttpsSession for a period longer than its active lifespan. And that I should not be worried about having a duplicate of the same session after it is de-idled.
I'm curious to know whether this is a standard behavior of all web server implementations. I could not find any documentation confirming that.
Since session management is completely rewritten in jetty 9.4, is it true there as well?
The HttpSession you access from a HttpServletRequest is only garunteed to be valid for the duration of the Http exchange, once your request is processed, and a response is produced, and the request dispatch is completed, the specific HttpSession instance you accessed is now invalid, and recycled.
It is highly unwise to hold onto it beyond that timeframe, as the object, and its information could be recycled (from an object pool) into a different request/response for a different user.
WebSocket is another animal.
Once the HTTP connection is upgraded to WebSocket, all of the HTTP specific information is invalid.
Why? That's because WebSocket is not HTTP, and the Upgrade stops/terminates the active HTTP exchange.
The implementation in Jetty will recycle the HttpServletRequest, HttpServletResponse, and HttpSession at the point of the upgrade for use on a later HTTP request.
Also of note, the context, lifetime, and lifecycle of the HttpServletRequest, HttpServletResponse, and HttpSession are not defined in the Servlet spec, or the CDI spec. Meaning that if you use/require those objects in a WebSocket, know that you have entered into undefined behavior. It would be wise to copy the information you need from those objects for your WebSocket endpoint to use.
The implementation in Jetty will recycle the HttpServletRequest, HttpServletResponse, and HttpSession at the point of the upgrade for use on a later HTTP request.
In jetty 9.4 UpgradeHttpServletRequest holds on to HttpSession ref but nulls HttpServletRequest ref on completion.
I'm currently taking advantage of this to share attributes with multiple sockets.
I have a web service that I access from multiple domains. For reasons I'm unable to fathom, the session seems to be shared between different sites.
So, I make a request from WebAppA to the API. This works.
Then I make a same request from WebAppB, to the same web service. This reports that it's blocked due to the CORS policy, e.g.
The 'Access-Control-Allow-Origin' header has a value 'WebAppA' that is not equal to the supplied origin.
Origin 'WebAppB' is therefore not allowed access.
But the Tomcat code for the web service claims that it allows CORS:
I have this in my web.xml:
<param-name>Access-Control-Allow-Origin</param-name>
<param-value>*</param-value>
and this in the java class that handles requests:
if (StringUtils.isNotBlank(origin)) {
response.setHeader("Access-Control-Allow-Origin", origin);
}
Logically, this should be allowing the requests from WebAppB through, but instead it still sees WebAppA as the only permitted origin. Given the snippet above, one option that springs to mind is that the Origin header might be blank. But if it was, then surely it wouldn't say WebAppB isn't allow access, because it wouldn't know that the origin was WebAppB!?
Clearing the cache fixes the issue, so it's clearly session-associated somehow, but I can't see any cookies that look like they're relevant.
Question How can I fix this so that both webapp A and B can access the same web service, without clearing the cache in between?
Disclaimer: This is a follow-on from Possible CORS issue. What's going on and how can I fix it?, but I've done a lot more investigation since so I can define the issue more clearly. (I hope).
I suspect an error in org/intermine/webservice/server/WebService.java.
It says
origin = StringUtils.defaultIfBlank(
webProperties.getProperty("ws.response.origin"),
request.getHeader("Origin"));
The method parameters (src,default) are supplied in a wrong order, which causes the server to always return a default value in "Access-control-allow-origin", instead of considering the actual current request...
I'm using Apache HttpComponents (core - 4.1.3, httpclient 4.1.1) to make http requests in a REST client I've written. The web service requires OAuth, which I've implemented using signpost. Recently, the webservice has introduced 301 redirects to endpoints that also require oauth. So, I've implemented a custom RedirectStrategy which builds a new request and signs it with signpost, just like I would do normally. However, the first two lines (in DefaultRequestDirector) immediately after I return my new request are setting all the headers to those that were sent in the initial request, effectively wiping my new Authorization header and causing all redirect requests to fail.
Does anyone know a way around this? I've considered always returning false in my custom RedirectStrategy and handing this in the ResponseHandler that I've attached to my request, but there's no trivial way of reconstructing the request and submitting it back through the proper client.
These are lines 1021-1023 in the DefaultRequestDirector where it calls to my custom RedirectStrategy and then wipes my headers (I'll try to link to source, shortly):
HttpUriRequest redirect = redirectStrategy.getRedirect(request, response, context);
HttpRequest orig = request.getOriginal();
redirect.setHeaders(orig.getAllHeaders());
I'm guessing a bit here, but if the code that you are referring to is line 349 of DefaultRequestDirector, then a bit further down on line 452 there is a call to requestExec.preProcess(wrapper, httpProcessor, context).
Would it be possible to register a processor here that signs the request?
If not, the BasicHttpProcessor (which is probably the processor used here) allows you to register interceptors that allow you to participate in the pre-processing of the request.
This might be another option to sign the request.
Alternatively, there is a HttpContext object. The Javadoc for this object suggests that it can be used to hold contextual data for the request, and your data would fit this description. So park it there and regather when you need it later.
I have a RESTful web service that responds to /user/{userId} with a marshalled XML representation of a User domain object (using JAXB). What's an appropriate way of communicating back to the client additional details about their request, particularly if it doesn't return the information they're expecting? In a non-distributed Java application, you might have a catch block that deals with data access, or security exceptions. In the event that /user/{userId} doesn't return anything (e.g. the web services persistence mechanism isn't working, there is a security restriction, etc...) how do I include meaningful information in the response to the client?
I don't think DTOs are what I need because I'm not looking for different representations of a domain object. Rather, I'm looking for information about what happened during the request that may have prevented it from returning the information the client expected. Would it be appropriate to enclose the domain object within some kind of ResponseObject that holds the relevant metadata? The downside to this approach is that I'd rather not have my service layer interfaces all have ResponseObject as their return type because I may very well provide a non-RESTful implementation that doesn't have the same metadata requirements.
What's an appropriate way of communicating back to the client additional details about their request, particularly if it doesn't return the information they're expecting.
In the event that /user/{userId} doesn't return anything (e.g. the web services persistence mechanism isn't working, there is a security restriction, etc...) how do I include meaningful information in the response to the client?
This is what the HTTP Status Code is used for in a RESTful service.
To indicate that a requested userId doesn't correspond to an actual user, you can return a 404 Not Found.
To indicate an internal error within your application (such as not being able to connect to the database), you can return 500 Internal Server Error.
The option you are describing - wrapping your returns in a ResponseObject which then includes the true "response status" - sounds an awful lot like SOAP.
The beauty of REST, or at least what people claim, is that you can use the already-existing HTTP response status code to model almost all statuses of your actual response.
If it's really error situation (security problems, no DB connection or even user with provided ID not found), then just throw an Exception. Client receives fault and can behave according to information contained in it.
Which implementation do you use? In Apache CXF, for example, you can define exception handler and render XML for exception yourself, and there you are free to include any meta-info you like.
I would capture the information using exceptions, then map those exceptions to an HTTP response with the appropriate status code. You can achieve this by creating an implementation of ExceptionMapper if you're using JAX-RS, or you can subclass StatusService if you're using Restlet.
http://wikis.sun.com/display/Jersey/Overview+of+JAX-RS+1.0+Features
http://wiki.restlet.org/docs_2.0/13-restlet/27-restlet/331-restlet/202-restlet.html
I have a JAX-RS web service for which I would like to disable the same-origin policy via the new CORS HTTP headers. (I am fully aware of the security implications.)
I'd like to have a custom annotation that lets me set HTTP response headers. For example,
#ResponseHeaders({"Access-Control-Allow-Origin: *",
"Access-Control-Allow-Methods: GET"})
// Or, alternatively:
#AllowOrigins({"*"})
public String resourceMethod() { ... }
This approach minimizes boilerplate code, but I'm not sure if there's a subtle technical limitation; JAX-RS provides many annotations to handle the HTTP request but not the response, with #Produces seeming to be the sole exception.
I also prefer to stay away from too much web.xml configuration, if possible. Without explicitly needing to use a ResponseBuilder (it's OK if an annotation uses one), is there a clean way to set custom HTTP response headers?
To clarify, I'm looking for annotations that integrate with the various ways of setting HTTP response headers in order to minimize boilerplate code.
Perhaps the only spec driven approach is to use a custom MessageBodyWriter. In the writeTo() method, you are passed in a MultivaluedMap which you can set response headers on. You are also passed the annotations on the resource method invoked (so you can get whatever custom annotation you want). So read the annotations, set the headers via MultivaluedMap, and then use the OutputStream passed in to write the message body.
In Apache Wink and possibly other JAX-RS frameworks, you can create custom server side handlers that can also read the annotations on the resource method and do whatever you want (like setting response headers by default).