Get beautified URL from HttpServletRequest - servlets

I am using the org.omnifaces.filter.HttpFilter to redirect visitors on login page when nobody is logged in.
#Override
public void doFilter(HttpServletRequest req, HttpServletResponse res, HttpSession session, FilterChain chain) throws ServletException, IOException {
String loginUrl = "/myapp/login?redirect_url=" + req.getRequestURL();
boolean loggedIn = (req.getRemoteUser() != null);
if (loggedIn) {
chain.doFilter(req, res); // So, just continue request.
} else {
Servlets.facesRedirect(req, res, loginUrl);
}
}
I want to redirect not logged in users to /login?redirect_url=previous_page_url
The problem is that all my URLs are beautified by pretty-faces and when I try to get the previous URL with HttpServletRequest.getRequestURI(), it gives me the ugly URL.
For example, I configured an url /myapp/my-page-3 which displays /views/module1/page3.xhtml.
But HttpServletRequest.getRequestURI() is giving me /views/module1/page3.xhtml and not /myapp/my-page-3.
Any ideas ?

When the servlet based URL rewrite engine uses under the covers RequestDispatcher#forward() to forward an incoming friendly-URL request to the desired resource, then you can use request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI) to find out the original request URI.
String originalRequestURI = request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI);
As you're already using OmniFaces, you can use Servlets#getRequestURI() to automatically detect it and return it when present, else fall back to the default HttpServletRequest#getRequestURI().
String requestURI = Servlets.getRequestURI(request);

Related

how to save cookies and redirect in spring mvc?

I get a task that to provide a login api , once user login, then i redirect to the index.html page, and save username as cookies.
I tried this but does not working.
#RequestMapping(value = "/direct", method = RequestMethod.GET)
public void login(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.addCookie(new Cookie("foo", String.valueOf(RandomUtils.nextInt())));
return "redirect:/index.html";
}
it redirect successed,but no cookies saved.
I save the cookie when I set the path:
Cookie coocie= new Cookie("X-COOKIE-NAME", "val");
coocie.setPath("/");
httpResponse.addCookie(coocie);
String redirectURL = "http://localhost:...";
httpResponse.sendRedirect(redirectURL);

Cannot call sendRedirect() after downloading PDF

I saw many questions like the one I am asking, but they are not exactly about what I am looking for.
I am using Command pattern, and want to create PDF-file and download it. Creating is perfect, but when I want to download it, it's starts downloading and throws an exception.
java.lang.IllegalStateException: Cannot call sendRedirect() after the response has been committed
org.apache.jasper.JasperException: java.lang.IllegalStateException: getOutputStream() has already been called for this response
java.lang.IllegalStateException: getOutputStream() has already been called for this response
Here is my code from Command Pattern
#Override
public String execute(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException, AppException {
String fontPath = request.getServletContext().getRealPath(AppConstants.FONT_PATH);
DBManager db = DBManager.getInstance();
String ticketCode = request.getParameter("ticketCode");
String place = request.getParameter("place");
int amountTickets = Integer.valueOf(place);
String flightName = Encoding.encoding(request.getParameter("flightName"));
User user = (User) request.getSession().getAttribute("client");
String locale = (String) request.getServletContext().getAttribute("currentLocale");
db.updateFlightTickets(flightName, --amountTickets);
///////create pdf document and represent it to the byte array
ByteArrayOutputStream baos =ReportCreator.createReport(locale, fontPath, ticketCode, place, user,
db.getFlightByName(flightName));
response.setContentType("application/pdf");
response.setContentLength(baos.size());
response.setHeader("Content-Transfer-Encoding", "binary");
response.setHeader("Content-Disposition","attachment; filename=\"Ticket\"");
OutputStream os = response.getOutputStream();
baos.writeTo(os);
os.flush();
os.close();
return Path.SUCCESS;
}
Here is my "success page", sorry but can not add more, not enough reputation
<fmt:message key="success_jsp.label.success" />
And here is my servlet code
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
process(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
process(request, response);
}
private void process(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
String commandName = request.getParameter("command");
Command command = CommandContainer.get(commandName);
String forward = "";
try {
forward = command.execute(request, response);
} catch (AppException ex) {
request.setAttribute("errorMessage", ex.getMessage());
}
if (forward.equals(Path.SUCCESS)) {
response.sendRedirect(forward);
} else {
request.getRequestDispatcher(forward).forward(request, response);
}
}
Part of code in JSP, where click is calling the servlet
<td><button><fmt:message key="welcome_jsp.submit.buy_ticket" /></button></td>
How can i avoid it?
The exception says you are trying to working with the request/response once you redirect it or viceversa, and it's not valid.
Once you redirect a request, you cannot do anything else with the request/response, so getting the output stream and writing something to it is completely insane.
It's true about vice-versa situation, writing something and then redirect it will cause the browser will ignore the response data, or exception on server as I'm guessing you got.(but it depends on container)
So you either do not redirect the browser, or provide the pdf file with the target servlet/cgi where you are trying to redirect.
=================
And your current situation/problem:
Server sets the content-length, content-type,... and starts to write down some stream to the browser, since you haven't set any status, container will set default 200 OK which indicates there is some right response for the request.
Then browser will get some data(the pdf file) as 200 OK data(and consider it done), now how would you redirect the user once the response is almost done?!!?!!?!
I still do not understand why do you like to redirect a request when it's almost closed? you like to redirect the user after download complete? you cannot.

How do I extract the username and password out of a URL in a servlet filter?

I've created a BasicAuthFilter and it has this signature:
#Override
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException, ServletException
This is working if someone calls the filter with an Authorization header set the right way. But, if someone on chrome or firefox visits the url like this:
http://username:password#localhost:8888
The browsers are not populating the Authorization header with that information (which surprised me). I looked at the information sent by chrome and the username and password are in the request URL but nowhere else.
I can't figure out how to extract that information from the URL. I've tried a lot of getters on the HttpServletRequest, but haven't found anything that gives me the username and password.
NOTE: Yes, I know this is insecure, it's just really convenient to use when you're trying to test your system.
URL url = new URL(custom_url);
String userInfo = url.getUserInfo();
String[] userInfoArray = userInfo.split(":");
System.out.println("username"+userInfoArray[0]);
System.out.println("password"+userInfoArray[1]);
My coworker found this thread that implies this isn't possible in modern browsers. They refuse to send the username:password part of a url over the wire for security reasons.
I'll add something to this answer
If the password contains the character :, you must specify a limit on your split.
So:
String[] userInfoArray = userInfo.split(":");
Becomes:
String[] userInfoArray = userInfo.split(":", 2);
2 means the pattern : is applied only one time (so the resulting length array is at maximum 2)
For passwords with '#', e.g. "http://user:p#ssw0rd#private.uri.org/some/service":
final String authority = uri.getAuthority();
if (authority != null) {
final String[] userInfo = authority.split(":", 2);
if (userInfo.length > 1) {
this.username = userInfo[0];
int passDelim = userInfo[1].lastIndexOf('#');
if (passDelim != -1) {
this.password = userInfo[1].substring(0, passDelim);
}
}
}
Note that in this case trying to use getUserInfo() won't help since userInfo of the URI is null.

Servlet filter mapped on /* results in browser error "server is redirecting the request for this address in a way that will never complete"

I am developing a dynamic JSP/Servlet web application. In order to handle the session, I am using a filter which is mapped on /* in web.xml. When I'm opening a page in Firefox, it gives the following Firefox-specific error message:
Firefox has detected that the server is redirecting the request for this address in a way that will never complete
A similar error is shown in Chrome. How is this caused and how can I solve it?
Your filter is redirecting to an URL which is invoking the very same filter with the very same conditions again which in turn thus results in a new redirect, etcetera. Your filter is basically redirecting to itself in an infinite loop. The webbrowser is blocking the infinite loop after ~20 requests to save the enduser from badly designed webapplications.
You need to fix your filter accordingly that it is not performing a redirect when it has already been performed. Let's assume a basic real world example of a login filter which is mapped on /* which should be redirecting to the login page when the user is not logged in which is identified by user attribute in session. You obviously want that the filter should not redirect to the login page if the login page itself is currently been requested.
#WebFilter("/*")
public class LoginFilter implements Filter {
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession(false);
String loginURL = request.getContextPath() + "/login.jsp";
boolean loggedIn = session != null && session.getAttribute("user") != null;
boolean loginRequest = request.getRequestURI().equals(loginURL);
if (loggedIn || loginRequest) {
chain.doFilter(request, response); // Logged-in user found or already in login page, so just continue request.
} else {
response.sendRedirect(loginURL); // No logged-in user found and not already in login page, so redirect to login page.
}
}
// ...
}
You see, if you want to allow/continue a request, just call chain.doFilter() instead of response.sendRedirect(). Use redirect only if you want to change a request to a different destination.

Url Redirection error if url contains reserved characters

I am trying to access particular url
DefaultHttpClient httpclient = new DefaultHttpClient();
httpclient.getCredentialsProvider().setCredentials(new AuthScope("abc.com", 443),
new UsernamePasswordCredentials("user", "Passwd"));
HTTPHelper http = new HTTPHelper(httpclient);
http.get("http://abc.com/**aaa**/w/api.php?param=timestamp%7Cuser&format=xml");
where %7C= |
which is redirecting me to the following url internally
http://abc.com/**bbb**/w/api.php?param=timestamp%257Cuser&format=xml
and because of that I am not able to get the correct output...
| ==>%7C
%==> %25
%7C == %257C
I want query to be timestamp|user
but because of circular redirection it is changed into timestamp%7Cuser
Is there any way to avoid this??
I wrote my own Custom Redirect Strategy also
httpclient.setRedirectStrategy(new DefaultRedirectStrategy() {
public boolean isRedirected(HttpRequest request, HttpResponse response, HttpContext context) {
boolean isRedirect = false;
try {
isRedirect = super.isRedirected(request, response, context);
LOG.info(response.getStatusLine().getStatusCode());
LOG.info(request.getRequestLine().getUri().replaceAll("%25", "%"));
} catch (ProtocolException e) {
e.printStackTrace();
}
if (!isRedirect) {
int responseCode = response.getStatusLine().getStatusCode();
if (responseCode == 301 || responseCode == 302) {
return true;
}
}
return isRedirect;
}
});
But I am not sure how to replace %25C with %7C from redirected url
It looks like the site's URL rewrite rules are simply broken. If it's not your site, you may want to contact its maintainers and inform them about the issue.
In the mean time, is there some reason why you can't simply use the target URLs (i.e. http://abc.com/**bbb**/w/api.php?...) directly, avoiding the redirect?
Does just http.get("http://abc.com/**aaa**/w/api.php?param=timestamp|user&format=xml");
work?
What's your meaning "redirecting me to the following url internally"? It's like that your url are encoded again. Can you post code in HTTPHelper? My below test code work correctly.
Client Code:
HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet("http://localhost:8080/test/myservlet?param=timestamp%7Cuser&format=xml");
client.execute(get);
Servlet Code:
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String param = request.getParameter("param"); //get timestamp|user
String format = request.getParameter("format");
}

Resources