Spring: How to use #RequestBody after reading inputStream - java

I'm having the issue described here but it's not clear to me how to address it.
The issue is that I have an AuthenticationProvider which has to read the body of the request. When my controller method wants to use that data via #RequestMapping, however, it's empty because the Provider has already read the inputStream.
Is there a way to obtain an inputReader from Request which supports mark/reset so my provider can simply roll the stream back to it's initial state after it does the authentication? It seems crazy that the default behavior of the filter is destructive modification of the request object.

The Provider should be triggered only in specific cases, so it shouldn't affect your whole application. But if you need the body in the requests handled by the provider, then you still have a workaround:
implement a servlet Filter
wrap the request
in the wrapper cache the request body, and then override the getInputStream() method to return a ByteArrayInputStream with the cached request body. That way it can be read muiltiple times.
spring's AbstractRequestLoggingFilter does something similar and has an example wrapper, you can check it.

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.

Disable Jersey Provider per request

Currently I have registered a Gson Provider which correctly is
used whenever my request is consuming or producing json.
The problem is that I have a request that needs the Post data as
either a byte[], InputStream, Reader, or String.
The reason I need the "raw" data is that I have some third party code where
it expects to do its own deserialization.
No matter which of these four types I specify my Post method to expect,
the GsonReader will complain and rightly so.
Expected a string but was BEGIN_OBJECT
Depending on the type there is a different error, but it all boils down to the
fact that I don't want this Provider/MessageBodyReader to run.
Also, I don't have control of the Accept and Content-type headers of the Posted data.
They will be application/json.
You can "modify" the accept/content-type headers of a request in a filter. So, if there is any way you can recognize that for this request, you don't want to use GSON, you can write a ContanerRequestFilter that modifies the headers.
If using GSON provider depends on a method the request gets matched to, you can implement ResourceFilterFactory that applies (returns) the ContainerRequestFilter (that modifies the content-type header to something other than json) just for the applicable methods (you can even introduce a custom annotation, annotate such methods with it and in the resourcefilterfactory return the containerrequestfilter only if the method passed to it is annotated with that annotation).
Here are the relevant links:
ContainerRequestFilter javadoc
ResourceFilterFactory javadoc
RolesAllowedResourceFilterFactory - you can use this as an example of a resource filter factory implementation

Is there a way to get post parameters from a http request in a filter but keep the input stream intact for servlet?

I am trying to fix a bug in sitebricks where it consumes the input stream in of the data of all servlets even those not using site bricks.
HiddenMethodFilter.java line:66
String methodName = httpRequest.getParameter(this.hiddenFieldName);
See http://code.google.com/p/google-sitebricks/issues/detail?id=45
Yes you can provide your own request, see Modify request parameter with servlet filter.
Furthermore may be extending the wrong sitebricks filter might be easier than chaining.
Obivously not, since the servlet container is required to read and consume the data in the InputStream before it is able to give you the request parameters. The other way around if you consume the InputStream first, the container won't have access to the request parameters later.
Why can't you fix the bug using the suggestion in the linked issue suggesting to configure the HiddenMethodFilter only for the URLs related to Site Bricks?

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

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

Categories

Resources