private void addPrebuiltJsp(String path, String className) { try { Class clazz = Class.forName( className); // ttt2 see if possible to not use this, preferably without doing // redirections like RedirectServlet Object obj = clazz.newInstance(); addServlet(new ServletHolder((Servlet) obj), path); LOG.info("Added prebuilt JSP: " + obj.toString()); } catch (Exception e) { LOG.fatal(String.format("Failed to load prebuilt JSP for %s and %s", path, className), e); } }
// !!! IDEA reports this as unused, but it is called from JSP public static FeedInfo getFeedInfo(String feedPath) { if (feedPath.startsWith(PATH_FEED + "/")) { try { if (feedPath.endsWith("/")) { feedPath = feedPath.substring(0, feedPath.length() - 1); } int k = PATH_FEED.length() + 1; int p = feedPath.indexOf('/', k); return p >= 0 ? new FeedInfo(feedPath.substring(k, p), Integer.parseInt(feedPath.substring(p + 1))) : new FeedInfo(feedPath.substring(k), -1); } catch (Exception e) { LOG.error("Exception trying to parse the feed info", e); } } LOG.error("Invalid path from feed: " + feedPath); return new FeedInfo("INVALID", -1); }
private void logOut(String browserId) throws Exception { // ttt2 the right way to do it is to go through all the sessions of the current browser, which // would require a new field and a new index; // not sure if it's worth it, but this would work: A logs in, forgets to log out, B delets the // cookies, logs in, A sees B is logged in, then B // restores the cookies and uses A's account if (browserId == null) { return; } List<LoginInfo> loginInfos = loginInfoDb.getLoginsForBrowser(browserId); long expireTarget = System.currentTimeMillis() - Utils.ONE_DAY; for (LoginInfo loginInfo : loginInfos) { if (loginInfo.expiresOn <= expireTarget) { LOG.info(String.format("LoginInfo %s is enough in the past", loginInfo)); } else { LOG.info(String.format("Logging out: %s", loginInfo)); loginInfoDb.updateExpireTime(browserId, loginInfo.sessionId, expireTarget); } } }
private void handleRemoveFeedPost(Request request, HttpServletResponse httpServletResponse) throws Exception { LOG.info("removing feed"); User user = userHelpers.getUser(request); try { if (user == null) { LOG.error("User not found"); return; } String feedId = request.getParameter(PARAM_FEED_ID); LOG.info(String.format("Removing feed %s for user %s", feedId, user)); // ttt1 add some validation; probably best try to actually get data, set the title, ... if (feedId == null || feedId.equals("")) { LOG.error("feed not specified"); // ttt1 show some error return; } if (user.feedIds.remove( feedId)) { // ttt2 clean up the global feed table; that's probably better done if nobody // accesses a feed for 3 months or so userDb.updateFeeds(user); LOG.info(String.format("Removed feed %s for user %s", feedId, user)); } else { LOG.info(String.format("No feed found with ID %s for user %s", feedId, user)); } } finally { httpServletResponse.sendRedirect(PATH_FEED_ADMIN); } }
private void handleAddFeedPost(Request request, HttpServletResponse httpServletResponse) throws Exception { LOG.info("adding feed"); User user = userHelpers.getUser(request); try { if (user == null) { LOG.error("User not found"); return; } String url = request.getParameter(PARAM_NEW_FEED_URL); // ttt1 add some validation; probably best try to actually get data, set the title, ... if (url == null || url.equals("")) { LOG.error("New feed not specified"); // ttt1 show some error return; } MessageDigest digest = MessageDigest.getInstance("MD5"); String feedId = PrintUtils.byteArrayAsUrlString(digest.digest(url.getBytes("UTF-8"))); feedId = feedId.substring(0, Config.getConfig().feedIdSize); Feed feed = feedDb.get(feedId); if (feed == null) { feed = new Feed(feedId, url); feedDb.add(feed); } if (user.feedIds.contains(feedId)) { LOG.error(String.format("Trying to add existing feed %s to user %s", feedId, user)); } else { user.feedIds.add(feedId); userDb.updateFeeds(user); } } finally { httpServletResponse.sendRedirect(PATH_FEED_ADMIN); } }
private void handleLoginPost( Request request, HttpServletResponse httpServletResponse, boolean secured) throws Exception { String userId = request.getParameter(PARAM_USER_ID); String password = request.getParameter(PARAM_PASSWORD); String rememberAccountStr = request.getParameter(PARAM_REMEMBER_ACCOUNT); boolean rememberAccount = Boolean.parseBoolean(rememberAccountStr); LoginInfo.SessionInfo sessionInfo = UserHelpers.getSessionInfo(request); logOut(sessionInfo.browserId); User user = userDb.get(userId); if (user == null) { WebUtils.redirectToError("User " + userId + " not found", request, httpServletResponse); return; } if (!user.checkPassword(password)) { WebUtils.redirectToError("Invalid password", request, httpServletResponse); return; } if (!user.active) { WebUtils.redirectToError( "Account for User " + userId + " needs to be activated", request, httpServletResponse); return; } LOG.info("Logged in user " + userId); sessionInfo.sessionId = null; if (sessionInfo.browserId == null) { sessionInfo.browserId = getRandomId(); } else { for (LoginInfo loginInfo : loginInfoDb.getLoginsForBrowser(sessionInfo.browserId)) { if (userId.equals(loginInfo.userId)) { sessionInfo.sessionId = loginInfo.sessionId; break; } } } long expireOn = System.currentTimeMillis() + Config.getConfig().loginExpireInterval; if (sessionInfo.sessionId == null) { sessionInfo.sessionId = getRandomId(); Config config = Config.getConfig(); loginInfoDb.add( new LoginInfo( sessionInfo.browserId, sessionInfo.sessionId, userId, expireOn, rememberAccount, config.defaultStyle, config.defaultItemsPerPage, config.defaultFeedDateFormat)); LOG.info(String.format("Logging in in a new session. User: %s", user)); } else { loginInfoDb.updateExpireTime(sessionInfo.browserId, sessionInfo.sessionId, expireOn); LOG.info(String.format("Logging in in an existing session. User: %s", user)); } WebUtils.saveCookies( httpServletResponse, secured, sessionInfo.browserId, sessionInfo.sessionId); httpServletResponse.sendRedirect("/"); }
private void handleUpdateFeedListPost(Request request, HttpServletResponse httpServletResponse) throws Exception { LOG.info("updating feed list"); // ttt2 implement httpServletResponse.sendRedirect(PATH_FEED_ADMIN); }
/** * Normally sets the path and a few attributes that the JSPs are likely to need. Also verifies the * login information. If necessary, just redirects to the login page. * * @param target * @param request * @param httpServletResponse * @param secured * @return true if the request is already handled so the .jsp shouldn't get called * @throws Exception */ private boolean prepareForJspGet( String target, Request request, HttpServletResponse httpServletResponse, boolean secured) throws Exception { LoginInfo.SessionInfo sessionInfo = UserHelpers.getSessionInfo(request); LOG.info( String.format( "hndl - %s ; %s; %s ; %s", target, request.getPathInfo(), request.getMethod(), secured ? "secured" : "not secured")); String path = request.getUri().getDecodedPath(); boolean redirectToLogin = path.equals(PATH_LOGOUT); LoginInfo loginInfo = null; if (sessionInfo.isNull()) { redirectToLogin = true; LOG.info("Null session info. Logging in again."); } else { loginInfo = loginInfoDb.get( sessionInfo.browserId, sessionInfo.sessionId); // ttt2 use a cache, to avoid going to DB if (loginInfo == null || loginInfo.expiresOn < System.currentTimeMillis()) { LOG.info("Session has expired. Logging in again. Info: " + loginInfo); redirectToLogin = true; } } if (!path.equals(PATH_LOGIN) && !path.equals(PATH_SIGNUP) && !path.equals(PATH_ERROR)) { if (redirectToLogin) { // ttt2 perhaps store URI, to return to it after login logOut(sessionInfo.browserId); addLoginParams(request, loginInfo); httpServletResponse.sendRedirect(PATH_LOGIN); return true; } User user = userDb.get(loginInfo.userId); if (user == null) { WebUtils.redirectToError("Unknown user", request, httpServletResponse); return true; } if (!user.active) { WebUtils.redirectToError("Account is not active", request, httpServletResponse); return true; } request.setAttribute(VAR_FEED_DB, feedDb); request.setAttribute(VAR_USER_DB, userDb); request.setAttribute(VAR_ARTICLE_DB, articleDb); request.setAttribute(VAR_READ_ARTICLES_COLL_DB, readArticlesCollDb); request.setAttribute(VAR_USER, user); request.setAttribute(VAR_LOGIN_INFO, loginInfo); MultiMap<String> params = new MultiMap<>(); params.put(PARAM_PATH, path); request.setParameters(params); } if (path.equals(PATH_LOGIN)) { addLoginParams(request, loginInfo); } return false; }
@Override public void doHandle( String target, Request request, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException, ServletException { LOG.info("handling " + target); // !!! doHandle() is called twice for a request when using redirectiion, first time with // request.getPathInfo() // set to the URI and target set to the path, then with request.getPathInfo() set to null and // target set to the .jsp try { // request.setHandled(true); boolean secured; if (request.getScheme().equals("https")) { secured = true; } else if (request.getScheme().equals("http")) { secured = false; } else { httpServletResponse .getWriter() .println( String.format( "<h1>Unknown scheme %s at %s</h1>", request.getScheme(), request.getUri().getDecodedPath())); return; } if (request.getMethod().equals("GET")) { if (isInJar || target.endsWith(".jsp")) { // !!! when not in jar there's no need to do anything about params if it's not a .jsp, // as this will get called again for the corresponding .jsp if (prepareForJspGet(target, request, httpServletResponse, secured)) { return; } } if (target.startsWith(PATH_OPEN_ARTICLE)) { handleOpenArticle(request, httpServletResponse, target); return; } super.doHandle(target, request, httpServletRequest, httpServletResponse); LOG.info("handling of " + target + " went to super"); // httpServletResponse.setDateHeader("Date", System.currentTimeMillis()); //ttt2 review // these, probably not use // httpServletResponse.setDateHeader("Expires", System.currentTimeMillis() + 60000); return; } if (request.getMethod().equals("POST")) { if (request.getUri().getDecodedPath().equals(PATH_LOGIN)) { handleLoginPost(request, httpServletResponse, secured); } else if (request.getUri().getDecodedPath().equals(PATH_SIGNUP)) { handleSignupPost(request, httpServletResponse); } else if (request.getUri().getDecodedPath().equals(PATH_CHANGE_PASSWORD)) { handleChangePasswordPost(request, httpServletResponse); } else if (request.getUri().getDecodedPath().equals(PATH_UPDATE_FEED_LIST)) { handleUpdateFeedListPost(request, httpServletResponse); } else if (request.getUri().getDecodedPath().equals(PATH_ADD_FEED)) { handleAddFeedPost(request, httpServletResponse); } else if (request.getUri().getDecodedPath().equals(PATH_REMOVE_FEED)) { handleRemoveFeedPost(request, httpServletResponse); } else if (request.getUri().getDecodedPath().equals(PATH_CHANGE_SETTINGS)) { handleChangeSettingsPost(request, httpServletResponse); } } /*{ // for tests only; httpServletResponse.getWriter().println(String.format("<h1>Unable to process request %s</h1>", request.getUri().getDecodedPath())); request.setHandled(true); }*/ } catch (Exception e) { LOG.error("Error processing request", e); try { // redirectToError(e.toString(), request, httpServletResponse); //!!! redirectToError leads // to infinite loop, probably related to // the fact that we get 2 calls for a regular request when redirecting httpServletResponse .getWriter() .println( String.format( "<h1>Unable to process request %s</h1>", // ttt1 generate some HTML request.getUri().getDecodedPath())); request.setHandled(true); } catch (Exception e1) { LOG.error("Error redirecting", e1); } } }