I have searched and seen a couple of answers about this problem, but still don't know how it's possible...
I'm asked to Implement a filter that returns response-time of an HTTP Request in the response header, eg. response-header: XX
in order to get collected by a web analytics client side library.
here's my code :
public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {
HttpServletResponse httpResp = (HttpServletResponse)response;
long startTime = System.nanoTime();
chain.doFilter(request, response);
long endTime = System.nanoTime();
httpResp.addHeader("response-time",endTime-startTime);
}
as well I tried to user HttpServletResponseWrapper
I managed to modify the response using OutputStream but didn't succeed with setting the response headers.
Thanks,Jay
Extend wrapper utility class like HttpServletResponseWrapper (using custom output streams) and pass it to the chain doFilter() method. If you dont do that, after chain doFilter() returns, the original (not wrapped) response will be gone and you will not have a chance to modify it.
Here you can find an example: Looking for an example for inserting content into the response using a servlet filter
Related
I am actually pretty new to the Java EE specifications since I am kind of young. I never learned this things at school and I am facing a weird behaviour with the doFilter method.
Consider the following filter :
#WebFilter(filterName = "URLFilter", value = "/test")
public class URLFilter implements Filter {
public void destroy() {}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
HttpServletResponse response = (HttpServletResponse) resp;
if (response.getStatus() == HttpServletResponse.SC_NOT_FOUND)
response.sendRedirect("/");
chain.doFilter(req, resp);
}
public void init(FilterConfig config) throws ServletException {}
}
There is no servlet or page present in /test and in my browser, the status is obviously a 404 not found error when accessing the URL and so should be the value returned to me by the getStatus() method which isn't. (actually having a 200 status code)
Why is my filter not redirecting me to / as requested ? Do I misunderstand the use of Filters in general ?
UPDATE:
My question was about redirecting the client (using the sendRedirect()) when a page is not found. I did not understand the filter part because I didn't know that resp and req are actually filled with the new data when chain.doFilter() is called. (which I actually found strange since the doFilter is calling the next Filter chained by the COR pattern)
I've made a class inheriting the HttpServletResponseWrapper, implemented it, passed it to the Filter and it's working fine now.
Your filter is invoked before trying to access the actual resource (servlet, page, file, whatever) located at /test. So the response status can't be 404 yet at this time.
Then your filter invokes chain.doFilter(), thus telling the container to actually serve the resource at /test. Since there is no such resource, you get a 404.
In my servlet, req.getQueryString() returns null when an ajax request is sent to it.
Is this because req.getQueryString() only works for GET and not POST?
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
req.getQueryString();
}
The easiest way to get hold of request parameters is to use request.getParameter(). This works for both GET and POST requests.
POST requests typically carry their parameters within the request body, which is why the request.getQueryString() method returns null.
From docs:
This method returns null if the URL does not have a query string.
Since you are in a doPost() handler, we can assume that indeed the request has no query string since it is a POST.
POST request may have a query string, but this is uncommon. POST data is included directly after the HTTP headers that browser sends to the server.
I have two Java web applications that have a single servlet that gets mapped to a specific URL:
red.war/
WEB-INF/classes
com.me.myorg.red.RedServlet (maps to http://red.example.com/doStuff)
blue.war/
WEB-INF/classes
com.me.myorg.blue.BlueServlet (maps to http://blue.example.com/doStuff)
I want to put these application (I'm calling them my "backend apps") behind a "proxy app" (servlet) that will decide which of these two apps will ultimately service a client-side request.
This proxy web app would take an incoming HTTP request, and determines which of the 2 "backend apps" (red or blue) to forward the request onto. The request would then be forwarded on to either http://red.example.com/doStuff (and then processed by RedServlet#doGet(...)) or http://blue.example.com/doStuff (and then processed by BlueServlet#doGet(...)). The returned response from the backend app (again, either RedServlet#doGet(...) or BlueServlet#doGet(...)) would then be returned to the proxy servlet, and ultimately returned to the client.
In other words, in pseudo-code:
public class ProxyServlet extends HttpServlet {
#Override
public doGet(HttpServletRequest request, HttpServletResponse response) {
String forwardingAddress;
if(shouldBeRed(request))
forwardingAddress = "http://red.example.com/doStuff";
else
forwardingAddress = "http://blue.example.com/doStuff";
PrintWriter writer = response.getWriter();
writer.write(getResponseFromBackend(forwardingAddress, request));
}
private String getResponseFromBackend(String addr, HttpServletRequest req) {
// Somehow forward req to addr and get HTML response...
}
}
Is this possible? If so, how and what code would I need to write to make it work?
You could use a RequestDispatcher to forward your request in the following way:
RequestDispatcher dispatcher = httpRequest.getRequestDispatcher(forwardingAddress);
// here you have the choice whether to use include(..) or forward(..) see below
if(useInclude)
dispatcher.include(httpRequest, httpResponse);
else
dispatcher.forward(httpRequest, httpResponse);
... where useInlcude is set to your choice with the following options:
includeThis is probably what you want to do: Load the content from the forwardingAdress into your response.
This means you could even include multiple targets into a single response.
The client will not even realize this procedure nor does he need to be able to see the target document.
forwardSend a forward to the forwardingAddress. This will tell the client to submit a new request to the specified URL.
If you do it in a browser with developer tools, you will see a second request.
The client must be able to see and load the target URL.
You can only forward to a single target.
See, the following links, too:
RequestDispatcher javadoc, especially for the notes:
forward should be called before the response has been committed to the client (before response body output has been flushed). If the response already has been committed, this method throws an IllegalStateException. Uncommitted output in the response buffer is automatically cleared before the forward.
include: The request and response parameters must be either the same objects as were passed to the calling servlet's service method or be subclasses of the ServletRequestWrapper or ServletResponseWrapper classes that wrap them.
URLRewriteFilter examplealthough this example is implemented using a Filter instead of a Servlet the behavior is the same (Note: this example is part of a framework of mine and hence contains some overhead in the parent classes. Just have a look at the relevant section...)
Since there is not yet an approved answer I try to write how I see the solution to this request use apache-http-commons library. In addition I suggest to add a flush on writer.
public class ProxyServlet extends HttpServlet {
#Override
public doGet(HttpServletRequest request, HttpServletResponse response) {
String forwardingAddress;
if(shouldBeRed(request))
forwardingAddress = "http://red.example.com/doStuff";
else
forwardingAddress = "http://blue.example.com/doStuff";
PrintWriter writer = response.getWriter();
writer.write(getResponseFromBackend(forwardingAddress, request));
**writer.flush();**
}
private String getResponseFromBackend(String addr, HttpServletRequest req) {
HttpClient client = new HttpClient();
HttpMethod method = new GetMethod(url);
client.executeMethod(method);
String body=method.getResponseBodyAsString();
return body;
}
}
In order to tackle clickJacking and blocking my site to be opened by iframe I have created a servlet filter in which I am adding below line to add "X-FRAME-OPTIONS" response header. But when I run page and see response headers of that page I never get this header in there. Any Idea why?
public void doFilter(
ServletRequest request, ServletResponse response, FilterChain chain
) throws IOException, ServletException
{
HttpServletResponse res = (HttpServletResponse)response;
chain.doFilter(request, response);
//Specify the mode
res.addHeader("X-FRAME-OPTIONS", "DENY");
}
You need to add the header before calling doFilter. By the time control returns from doFilter the headers and body have already been sent, so your addHeader is ignored.
I'm using ServletRequestListener to attach to new requests, get a ServletRequest object and extract cookies from it.
I've noticed that only HTTPServletRequest has cookies but I haven't found a connection between those two objects.
Is it okay to use
HttpServletRequest request = ((HttpServletRequest) FacesContext.getCurrentInstance()
.getExternalContext().getRequest());
to retrieve the request while in a RequestInitialized method? (I do want to run on every request)
FYI - This is all done in a JSF 1.2 Application
This is not correct. The FacesContext isn't available in a ServletRequestListener per se. The getCurrentInstance() might return null, leading to NPE's.
If you're running the webapp on a HTTP webserver (and thus not some Portlet webserver for example), you could just cast the ServletRequest to HttpServletRequest.
public void requestInitialized(ServletRequestEvent event) {
HttpServletRequest request = (HttpServletRequest) event.getServletRequest();
// ...
}
Note that a more common practice is to use a Filter for this since you can map this on a fixed URL pattern like *.jsf or even on specific servlets so that it runs only when the FacesServlet runs. You might for example want to skip cookie checks on static resources like CSS/JS/images.
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
HttpServletRequest request = (HttpServletRequest) req;
// ...
chain.doFilter(req, res);
}
When you happens to be already inside the JSF context (in a managed bean, phaselistener or whatever), you could just use ExternalContext#getRequestCookieMap() to get the cookies.
Map<String, Object> cookies = externalContext.getRequestCookieMap();
// ...
When running JSF on top of Servlet API, the map value is of type javax.servlet.http.Cookie.
Cookie cookie = (Cookie) cookies.get("name");
Yes, you can do that. In Web scenarios, this will always be ok. If you want to be sure, you could do a check for the type first. (Good practice anyway):
if (FacesContext.getCurrentInstance().getExternalContext().getRequest() instanceof HttpServletRequest) {
...
By the way: Why do you have to use FacesContext? From where are you calling this code?