Custom annotations to set HTTP response headers in a JAX-RS service - java

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).

Related

ContentCachingRequestWrapper only captures POST request with Content-Type:application/x-www-form-urlencoded

I am trying to intercept all incoming HTTP requests and process the body attached to these requests in my Spring MVC (not Spring Boot) app. To implement this "inbound-interceptor", I am using Spring's HandlerInterceptor interface. Once the request is intercepted, I am trying to retrieve the body as follows:
ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request);
Map<String, String[]> params = requestWrapper.getParameterMap();
byte[] body = requestWrapper.getContentAsByteArray();
Referring to this article, the limitations of trying to extract the body this way are:
Content-type of the request must be x-www-form-urlencoded
Method-type must be POST
For the application I am building, I cannot enforce either of these constraints as the calls come from heterogeneous sources beyond my control. Is there some way to override this behavior to allow extraction of the body for requests not supported by default? Or, alternatively, is there another approach to performing this task?
P.S. I am performing logging + some custom processing on the body. So solutions such as the ones mentioned in this answer are not too helpful
Have you tried Logbook? https://github.com/zalando/logbook Works with pure Spring.
Their Default Log Writer looks promising: https://github.com/zalando/logbook/blob/main/logbook-core/src/main/java/org/zalando/logbook/DefaultHttpLogWriter.java
And you may just want to extend this class to log to all Loggers you want.
You can even do something completely different with the request besides logging.

Java interceptor reading request body makes the request empty

I have written an interceptor using spring that reads the request body from the HTTPServletRequest, in preHandle method. Request body contains json. I am able to read the request body also but something is happening to the request object and the request body is getting blank. And beause of this the request is becoming a bad request. Any help will be much appreciated. Thanks in advance.
I haven't used either JEE interceptors or Spring interceptors and don't know how they work.
But it sounds like the easier way would be to go with a filter (as configured from the web.xml). Since filters call each other in a chain, you could easily replace the HttpServletRequest object that is forwarded with a wrapped one (where you provide the body).
This could probably be accomplished by creating a class of your own, extending the HttpServletRequestWrapper and then override the appropriate methods (getInputStream sounds like the way to go here, yes?).
Your version of getInputStream would then return a ByteArrayInputStream of the body you already read, or whatever you kind of InputStream you feel is appropriate.

Max file size with resteasy and multipart/form-data request

How can I control the max file size and/or the max request size when using resteasy to handle a multipart/form-data request ?
My code looks like this:
#POST
#Path("/somerestresource")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response handleForm(#MultipartForm MyForm form) {
...
}
With a Servlet I can control stuff with the #MultipartConfig annotation.
So I'm thinking about bypassing resteasy and using #Context to inject a HttpServletRequest and having my servlet configured inside the web.xml but I'm unsure of the side effects.
With JAX-RS 2.0, you could use a ContainerRequestFilter bound to your upload method using a #NameBinding annotation. In this filter, you would look at the content-length request header and discard the request if the content length exceeds the maximum value you plan to accept (requestContext.abortWith(...))
With JAX-RS 1.1 and RESTEasy, you could probably do the same thing using a PreProcessInterceptor (http://docs.jboss.org/resteasy/docs/1.1.GA/userguide/html/Interceptors.html#PreProcessInterceptors) and follow a logic logic similar to the one described above.
In addition to the answer by Xavier, you can also get the content-length header from an injected #Context HttpServletRequest. Furthermore, this is not enough, because the header may not be available (e.g. when chunking is used for the POST body). You then have two options: let the call fail, because you don't know the length of the stream, or resort to using, e.g., BoundedInputStream to read the body of the upload part of the request.
Minor detail: the content-length header is usually sent along with the main request, and not with each part of the multipart data. It therefore does not accurately represent the size of the upload.

Easy REST resource versioning in JAX-RS based implementations?

Best practice for REST resource versioning is putting version information into Accept/Content-Type headers of HTTP request leaving URI intact.
Here is the sample request/response to REST API for retrieving system information:
==>
GET /api/system-info HTTP/1.1
Accept: application/vnd.COMPANY.systeminfo-v1+json
<==
HTTP/1.1 200 OK
Content-Type: application/vnd.COMPANY.systeminfo-v1+json
{
“session-count”: 19
}
Pay attention that version is specified in MIME type.
Here is another request/response for version 2:
==>
GET /api/system-info HTTP/1.1
Accept: application/vnd.COMPANY.systeminfo-v2+json
<==
HTTP/1.1 200 OK
Content-Type: application/vnd.COMPANY.systeminfo-v2+json
{
“uptime”: 234564300,
“session-count”: 19
}
See http://barelyenough.org/blog/tag/rest-versioning/ for more explanation and examples.
Is it possible to implement this approach easily in Java-targeted JAX-RS based implementations, such as Jersey or Apache CXF?
The goal is to have several #Resource classes with the same #Path value, but serving the request based on actual version specified in MIME type?
I've looked into JAX-RS in general and Jersey in particlaur and found no support for that. Jersey doesn't give a chance to register two resources with the same path. Replacement for WebApplicationImpl class needs to implemented to support that.
Can you suggest something?
NOTE: It is required for multiple versions of the same resource needs to be available simultaneously. New versions may introduce incompatibale changes.
JAX-RS dispatches to methods annotated with #Produces via the Accept header. So, if you want JAX-RS to do your dispatching, you'll need to leverage this mechanism. Without any extra work, you would have to create a method (and Provider) for every media type you wish to support.
There's nothing stopping you from having several methods based on media type that all call a common method to do that work, but you'd have to update that and add code every time you added a new media type.
One idea is to add a filter that "normalizes" your Accept header specifically for dispatch. That is, perhaps, taking your:
Accept: application/vnd.COMPANY.systeminfo-v1+json
And converting that to, simply:
Accept: application/vnd.COMPANY.systeminfo+json
At the same time, you extract the version information for later use (perhaps in the request, or some other ad hoc mechanism).
Then, JAX-RS will dispatch to the single method that handles "application/vnd.COMPANY.systeminfo+json".
THAT method then takes the "out of band" versioning information to handle details in processing (such as selecting the proper class to load via OSGi).
Next, you then create a Provider with an appropriate MessageBodyWriter. The provider will be selected by JAX-RS for the application/vnd.COMPANY.systeminfo+json media type. It will be up to your MBW to figure out the actual media type (based again on that version information) and to create the proper output format (again, perhaps dispatching to the correct OSGi loaded class).
I don't know if an MBW can overwrite the Content-Type header or not. If not, then you can delegate the earlier filter to rewrite that part for you on the way out.
It's a little convoluted, but if you want to leverage JAX-RS dispatch, and not create methods for every version of your media type, then this is a possible path to do that.
Edit in response to comment:
Yea, essentially, you want JAX-RS to dispatch to the proper class based on both Path and Accept type. It is unlikely that JAX-RS will do this out of the box, as it's a bit of an edge case. I have not looked at any of the JAX-RS implementations, but you may be able to do what you want by tweaking one of the at the infrastructure level.
Possibly another less invasive option is to use an age old trick from the Apache world, and simply create a filter that rewrites your path based on the Accept header.
So, when the system gets:
GET /resource
Accept: application/vnd.COMPANY.systeminfo-v1+json
You rewrite it to:
GET /resource-v1
Accept: application/vnd.COMPANY.systeminfo-v1+json
Then, in your JAX-RS class:
#Path("resource-v1")
#Produces("application/vnd.COMPANY.systeminfo-v1+json")
public class ResourceV1 {
...
}
So, your clients get the correct view, but your classes get dispatched properly by JAX-RS. The only other issue is that your classes, if they look, will see the modified Path, not the original path (but your filter can stuff that in the request as a reference if you like).
It's not ideal, but it's (mostly) free.
This is an existing filter that might do what you want to do, if not it perhaps can act as an inspiration for you to do it yourself.
With current version of Jersey, I would suggest an implementation with two different API methods and two different return values that are automatically serialised to the applicable MIME type. Once the requests to the different versions of the API are received, common code can be used underneath.
Example:
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
#GET
#Path("/{id}")
#Produces(MediaType.APPLICATION_JSON)
public VersionOneDTO get(#PathParam("id") final String id) {
return new VersionOneDTO( ... );
}
#GET
#Path("/{id}")
#Produces("application/vnd.COMPANY.systeminfo-v2+json;qs=0.9")
public VersionTwoDTO get_v2(#PathParam("id") final String id) {
return new VersionTwoDTO( ... );
}
If method get(...) and get_v2(...) use common logic, I would suggest to put that in a common private method if it's API related (such as session or JWT handling) or else in a common public method of a Service Layer that you access via inheritance or Dependency Injection. By having two different methods with different return types, you ensure that the structure returned is of correct type for the different versions of the API.
Note that some old client may not specify Accept header at all. That means implicitly that they would accept any content type, thus any version of your API. In practice, this is most often not the truth. For this reason you should specify a weight to newer versions of the API using the qs extension of the MIME type as shown in the #Produces annotation in the example above.
If you are testing with restAssured it would look something like this:
import static com.jayway.restassured.RestAssured.get;
import static com.jayway.restassured.RestAssured.given;
#Test
public void testGetEntityV1() {
given()
.header("Accept", MediaType.APPLICATION_JSON)
.when()
.get("/basepath/1")
.then()
.assertThat()
... // Some check that Version 1 was called
;
}
#Test
public void testGetEntityV1OldClientNoAcceptHeader() {
get("/basepath/1")
.then()
.assertThat()
... // Some check that Version 1 was called
;
}
#Test
public void testGetEntityV2() {
given()
.header("Accept", "application/vnd.COMPANY.systeminfo-v2+json")
.when()
.get("/basepath/1")
.then()
.assertThat()
... // Some check that Version 2 was called
;
}
One possible solution is to use one #Path with
Content-Type:
application/vnd.COMPANY.systeminfo-{version}+json
Then, inside the method of the given #Path you can call the version of the WebService
If you're using CXF, you could use the technique specified here to build a new serialization provider (building off the existing infrastructure) which produces the data in the specific format desired. Declare a couple of those, one for each specific format that you want, and use the #Produces annotation to let the machinery handle the rest of the negotiation for you, though it might also be an idea to support the standard JSON content type too so that normal clients can handle it without needing to grok your specialness. The only real question then becomes what is the best way to do the serialization; I presume you can figure that out for yourself…
[EDIT]: Further digging in the CXF documentation leads to the revelation that both the #Consumes and #Produces annotations are considered to be axes for doing selection. If you want to have two methods that handle the production of the response for different media types, you most certainly can. (You'll have to add the serialization and/or deserialization providers if you're using custom types, but you can do the delegation of the majority of the work to the standard providers.) I'd still like to caution that you should still ensure that the resource indicated by the path should be the same in both cases; to do otherwise is not RESTful.
You should be able to use different classes with the same path provided they consume/produce different media types. So this should work with any jax-rs provider:
#Path("/api/system-info")
#Consumes("application/vnd.COMPANY.systeminfo-v1+json")
#Produces("application/vnd.COMPANY.systeminfo-v1+json")
public class SystemInfoResourceV1 {
}
and
#Path("/api/system-info")
#Consumes("application/vnd.COMPANY.systeminfo-v2+json")
#Produces("application/vnd.COMPANY.systeminfo-v2+json")
public class SystemInfoResourceV2 {
}

ServletRequestWrapper or ServletResponseWrapper in production?

Hi have you seen anything really useful extending HttpServletResponseWrapper/HttpServletRequestWrapper or ServletRequestWrapper/ ServletResponseWrapper in production environment?
Trim whitespace from generated HTML, can save over 50% of bandwidth. I've had a project which displays large tabular data (with nicely indented HTML source), response size went from ~200KB to ~70KB by just trimming all whitespace away.
Process multipart/form-data requests transparently by putting multipart form data back in request parameter map so that you can use request.getParameter() and consorts the usual way again (Servlet <=2.5 example, Servlet >=3.0 example).
Capture the outputstream, either to have a copy or to MD5-hash it.
Disabling URL rewriting.
Etcetera.. Etcetera.. All just to override and change the default behaviour of certain HttpServletRequest/HttpServletResponse methods.
I've used it to "capture" the output of a JSP, so that it can be transformed by the forwarding controller. This was done by overriding the getWriter() / getOutputStream() methods.
SiteMesh does a similar thing, capturing the "target" in order to decorate the response.
We use it to
overwrite getRemoteAddr() to return values from X-Forwarded-For or X-Real-IP (set by our nginx proxy)
filter certain headers, e.g. to avoid content negotiation in 3rd party servlets
gzip response
Many frameworks (richfaces, myfaces on my current classpath at least) use a request wrapper to handle multipart requests
Spring has ContextExposingHttpServletRequest so that spring beans are accessible as request attributes.
myfaces orchestra uses the response wrapper to rewrite the URL in order to ensure multiple-window conversation context
I've used it just recently to capture outgoing response headers for debugging purposes (getHeaderNames() and getHeader() were only added on the response side in the Servlet 3.0 spec.
We've also used it for gathering metrics on our servlets, by overriding getOutputStream() to return an OutputStream implementation which increases a counter on every byte that passes through it so we can tell what our high-network-traffic servlets are.

Categories

Resources