How to ignore filter for postback calls - ajax

I have a filter which requires an id-parameter (GET). This works fine when I add the parameter in the navigation links. But when I stay at the same site (e.g. ajax calls), the filter shouts and screams, because the id-parameter is lost.
Is there a chance to ignore the filter if the request come from ajax?
something like
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (FacesContext.getCurrentInstance().isPostback()) {...}
...
}
?

I found a solution which works fine
private boolean isAJAXRequest(HttpServletRequest request) {
boolean check = false;
String facesRequest = request.getHeader("Faces-Request");
if (facesRequest != null && facesRequest.equals("partial/ajax")) {
check = true;
}
return check;
}
in the beginning of the filter, just add it like:
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
if(isAJAXRequest(req)){
System.out.println("IGNORE THIS FILTER, AJAX");
chain.doFilter(request, response);
return;
}
...
}

You have to define the functional requirement more clearly. You are currently too vague and mixing several concepts.
What exactly do you want to check on?
It is a GET request.
It is not a JSF ajax POST request.
It is not a POST request.
Your current question title "How to ignore filter for postback calls" covers 2 and 3. Your current question body "which requires an id-parameter (GET)" covers 1. Your own answer covers 2.
This is really not clear. So, I'll just show how to cover each of them:
To check if it's a GET request:
if ("GET".equals(request.getMethod())) {
// It's a GET request.
}
To check if it's not a JSF ajax POST request:
if (!"partial/ajax".equals(request.getHeader("Faces-Request"))) {
// It's not a JSF ajax request.
}
To check if it's not a POST request:
if (!"POST".equals(request.getMethod())) {
// It's not a POST request.
}
They all are quite different:
This not only excludes POST, but also e.g. PUT and OPTIONS requests.
This doesn't exclude synchronous JSF POST requests (e.g. submit button without <f:ajax>).
This also excludes all other kinds of POST requests.
Think twice and ultimately just use the right tool for the job.
An alternative would be to retain the current GET query string in the form action URL (i.e. solving the problem by its roots instead of workarounding it). This is answered here: Retaining GET request query string parameters on JSF form submit.

This workaround just works:
private boolean isAjax(HttpServletRequest request) {
//Return if current request header is equals to "XMLHttpRequest"
return "XMLHttpRequest".equals((request).getHeader("X-Requested-With"));
}

Related

request.getServletPath() returned null from Spring MVC

I made a filter to capture HttpServletRequest sevlet path from all requests
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
// debug to see the output
String path = request.getServletPath();
filterChain.doFilter(request, response);
}
There is a URL in jsp that has no controller or view mapped to it
<div>
<spring:url value="/app" var="app_url" htmlEscape="true"/>
<spring:message code="label_3rd_app" />
</div>
However, when click on the url while debugging on the filter, I see request.getServletPath() value from two request:
/null
/null/app
My question is why request.getServletPath() never returns /app instead?
You're getting null because
request.getServletPath();
is for Servlets, and you're doing it inside a Filter. To get it in a Filter you have to manually build it like this:
HttpServletRequest request = (HttpServletRequest) req;
String path = request.getRequestURI().substring(request.getContextPath().length());
more info why:
How to get request URI without context path?
Mr. Lalibertes solution is not working correctly as the result of getRequestURI is uri-encoded and getServletPath is not.
Better use Springs UrlPathHelper for getting the servlet path in such situations.
new org.springframework.web.util.UrlPathHelper().getPathWithinApplication(servletRequest);
This method delivers the uri-decoded servlet path as getServletPath would have - if it would'nt be null.
For people coming to this question just because your context path was null (like me): I was calling request.getContextPath() in a background thread.
The request then became 'out of scope', if I understand this bug report discussion correctly: https://bugs.eclipse.org/bugs/show_bug.cgi?id=401768
Also, I know I'm not supposed to use normal threads in servlet environments, but use Executor instead. But the problem would probably remain: https://developer.jboss.org/thread/232135.
Solution was to extract all needed info from the request before handing off to background thread.

Spring reading request body twice

In spring I have a controller with an endpoint like so:
#RequestMapping(method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
#ResponseBody
public OutputStuff createStuff(#RequestBody Stuff stuff) {
//my logic here
}
This way if doing a POST on this endpoint, the JSON in request body will be automatically deserialized to my model (Stuff). The problem is, I just got a requirement to log the raw JSON as it is coming in! I tried different approaches.
Inject HttpServletRequest into createStuff, read the body there and log:
Code:
#RequestMapping(method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
#ResponseBody
public OutputStuff createStuff(#RequestBody Stuff stuff, HttpServletRequest req) {
StringBuilder sb = new StringBuilder();
req.getReader().getLines().forEach(line -> {
sb.append(line);
});
//log sb.toString();
//my logic here
}
The problem with this is that by the time I execute this, the reader's InputStream would have already been executed to deserialize JSON into Stuff. So I will get an error because I can't read the same input stream twice.
Use custom HandlerInterceptorAdapter that would log raw JSON before the actual handler is called.
Code (part of it):
public class RawRequestLoggerInterceptor extends HandlerInterceptorAdapter {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
StringBuilder sb = new StringBuilder();
req.getReader().getLines().forEach(line -> {
sb.append(line);
});
//log sb.toString();
return true;
}
}
The problem with this tho is, that by the time the deserialization to stuff happens, the InputStream from the request would have been read already! So I would get an exception again.
Another option I considered, but not implemented yet, would be somehow forcing Spring to use my custom implementation of HttpServletRequest that would cache the input stream and allow multiple read of it. I have no idea if this is doable tho and I can't find any documentation or examples of that!
Yet another option would be not to read Stuff on my endpoint, but rather read the request body as String, log it and then deserialize it to Stuff using ObjectMapper or something like that. I do not like this idea either tho.
Are there better solutions, that I did not mention and/or am not aware of? I would appreciate help. I am using the latest release of SpringBoot.
To read the request body multiple times, we must cache the initial payload. Because once the original InputStream is consumed we can't read it again.
Firstly, Spring MVC provides the ContentCachingRequestWrapper class which stores the original content. So we can retrieve the body multiple times calling the getContentAsByteArray() method.
So in your case, you can make use of this class in a Filter:
#Component
public class CachingRequestBodyFilter extends GenericFilterBean {
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest currentRequest = (HttpServletRequest) servletRequest;
ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(currentRequest);
// Other details
chain.doFilter(wrappedRequest, servletResponse);
}
}
Alternatively, you can register CommonsRequestLoggingFilter in your application. This filter uses ContentCachingRequestWrapper behind the scenes and is designed for logging the requests.
As referenced in this post: How to Log HttpRequest and HttpResponse in a file?, spring provides the AbstractRequestLoggingFilter you can use to log the request.
AbstractRequestLoggingFilter API Docs, found here
I also tried to do that in Spring but i could not find way to pass my custom http request to chain so what did was,i have written traditional j2ee filter in that i have passed my custom http request to chain that is it then onward i can read http request more than once
Check this example http://www.myjavarecipes.com/how-to-read-post-request-data-twice-in-spring/

JSF ajax request calls filter (should be ignored!)

I have some filters, which grab e.g. a parameter like "id" to check some right (used to load some contents). These filters should ignore all ajax-requests, because e.g. the rights does not have to be checked after every little request (only on page load)
The Problem is, that when I perform an ajax-request, it throws me a null-pointer, because I don't append the ID with ajax requests. I found out, that it still works, when I use and it fails, when I use (both perform ajax requests).
This is my filter:
public class ExtendedAccessFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
//ignore filter if it is an ajax-request (DOES NOT WORK if not p:commandButton!)
if(isAJAXRequest(req)){
chain.doFilter(request, response);
System.out.println("ABORT FILTER, AJAX");
return;
}
//Nullpointer thrown here (because no Id is submitted)
int requestedId = Integer.parseInt(request.getParameter("id"));
}
private boolean isAJAXRequest(HttpServletRequest request) {
boolean check = false;
String facesRequest = request.getHeader("Faces-Request");
if (facesRequest != null && facesRequest.equals("partial/ajax")) {
check = true;
}
return check;
}
}
Am I doing something wrong?
You are doing it right way. You can also do it using JSF API by checking if PartialViewContext exists and it is an Ajax Request
if(FacesContext.getCurrentInstance().getPartialViewContext() !=null &&
FacesContext.getCurrentInstance().getPartialViewContext().isAjaxRequest()) {
}

Alter request header before controller method using #RequestHeader is called

I have a few controllers that use the #RequestHeader annotation to get the logged in user. I cannot seem to find the correct way to alter the header before the method is called.
I already tried to wrap the request and using an interceptor (in the prehandle method, if I'm not mistaken) and pass along the request,but it seems like the headers are not being queried. An exception is thrown by the servlet dispatcher that the username is missing in the header.
Therefore I'm wondering whether someone knows how and when spring handles this annotation, so I can write the proper interceptor.
Don't have the code at hand, but if needed, I will post fragments later on. But the question is simple: how to inject a param into the request header when #RequestHeader is used on a controller method?
Kind regards,
Tom
First edit:
#Sotirios
I tried using the Filter, which works. But this is less convenient for me than the handlerinterceptor. Since I only need the filter for debugging. So again the better question: why isn't this not working with an interceptor?
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
final HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletRequestWrapper wrapper = new HttpServletRequestWrapper(httpRequest) {
#Override
public Enumeration getHeaders(String name) {
Enumeration headers = super.getHeaders(name);
if( isUseFilter() && Constants.REMOTE_USER.equalsIgnoreCase(name) ){
String user = super.getHeader(name);
headers = enumeration(asList(isEmpty(user)? getDebuggingUserId() :user));
}
return headers;
}
};
chain.doFilter(wrapper, response);
}

Store url when #Controller is accessed Spring MVC

Is there a way to access the URL resolved from a Spring MVC controller - e.g.
#RequestMapping("/{language}/news/{articleId}")
public String newsPage(...) {
}
Resolves to:
/en/news/63421
I'd like to store this with the session so I can keep a track of last place visited. The motivation here is if the page is secured the login filter will come into play and we have used
SavedRequestAwareAuthenticationSuccessHandler
to route users back to the page they were trying to access.
However if they are viewing unsecured pages and choose to log in using a form that drops down from the top of the screen (the page's menu bar) the 'last page' seems to be the login form so the success handler drops them back to the root context.
I'd like to intercept controller calls and store a single URL with the session, override SavedRequestAwareAuthenticationSuccessHandler to allow us to modify the RequestCache and then let Spring redirect on login success.
Ideally we'd like a generic way to do this across all controllers but not sure if there is a filter we can use to pick this up - filtering requests gets all sorts of noise like css, js, images and html fragment pages so we're hoping someone knows a way to do this just with the controllers themselves.
There are two questions:
1) obtain the url in a controller method
#RequestMapping("/{language}/news/{articleId}")
public String newsPage(..., HttpServletRequest request) {
String uri = request.getRequestUri();
...
}
If you need this very often then you can implement a HandlerMethodArgumentResolver. *See this answer https://stackoverflow.com/a/8769670/280244 for an example (it implements a HandlerMethodArgumentResolver for the current user, but you can easyly adapt it for urls)
2.) store the url for each request in the session
You can implement a Servlet Filter or Spring HandlerInterceptor, both get a HttpServletRequest (In a Servlet Filter you need to cast the ServletRequest to an HttpServletRequest first.
Then you can obtain the url and the Session httpServletRequest.getSession() and then store the url in the session.
public class MyFilter implements Filter {
#Override
public void init(final FilterConfig filterConfig) throws ServletException {
//do nothing
}
#Override
public void doFilter(ServletRequest requ, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
if (requ instanceof HttpServletRequest) {
HttpServletRequest httpServletRequest = (HttpServletRequest) requ;
httpServletRequest.getSession().setAttribute(
"myFilter.LAST_URL",
httpServletRequest .getRequestURI());
}
chain.doFilter(request, response);
}
#Override
public void destroy() {
}
}
To get the URL path you can use the HttpServletRequest - so for example you have:
www.mysite.com/en/news/63421
req.getPathInfo() = /en/news/63421
Storing it in the session though could cause problems if someone is to use your site with multiple tabs open.

Resources