From 178f881d571b97de5bf408a998103fe8820f8bdd Mon Sep 17 00:00:00 2001 From: Ziver Koc Date: Wed, 19 Apr 2017 17:55:34 +0200 Subject: [PATCH] Fixed http server session recreated every connection --- src/zutil/Timer.java | 7 ++ src/zutil/net/http/HttpServer.java | 48 +++++----- .../net/http/page/HttpGuessTheNumber.java | 89 +++++++++++-------- 3 files changed, 82 insertions(+), 62 deletions(-) diff --git a/src/zutil/Timer.java b/src/zutil/Timer.java index e0e29e5..83706c2 100755 --- a/src/zutil/Timer.java +++ b/src/zutil/Timer.java @@ -70,4 +70,11 @@ public class Timer { public boolean hasTimedOut(){ return timestamp + period < System.currentTimeMillis(); } + + public String toString(){ + if (hasTimedOut()) + return "Timed out"; + else + return "Timeout in "+StringUtil.formatTimeToString((timestamp+period)-System.currentTimeMillis()); + } } diff --git a/src/zutil/net/http/HttpServer.java b/src/zutil/net/http/HttpServer.java index b6863a9..ed0330d 100755 --- a/src/zutil/net/http/HttpServer.java +++ b/src/zutil/net/http/HttpServer.java @@ -25,6 +25,7 @@ package zutil.net.http; import zutil.StringUtil; +import zutil.Timer; import zutil.log.LogUtil; import zutil.net.threaded.ThreadedTCPNetworkServer; import zutil.net.threaded.ThreadedTCPNetworkServerThread; @@ -33,8 +34,11 @@ import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; import java.net.Socket; -import java.util.*; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; @@ -48,15 +52,15 @@ import java.util.logging.Logger; public class HttpServer extends ThreadedTCPNetworkServer{ private static final Logger logger = LogUtil.getLogger(); - public static final String SESSION_ID_KEY = "session_id"; - public static final String SESSION_TTL_KEY = "session_ttl"; - public static final String SERVER_VERSION = "Zutil HttpServer"; + public static final String SESSION_KEY_ID = "session_id"; + public static final String SESSION_KEY_TTL = "session_ttl"; + public static final String SERVER_NAME = "Zutil HttpServer"; public static final int SESSION_TTL = 10*60*1000; // in milliseconds private Map pages; private HttpPage defaultPage; - private Map> sessions; + private Map> sessions; private int nextSessionId; /** @@ -83,8 +87,8 @@ public class HttpServer extends ThreadedTCPNetworkServer{ sessions = new ConcurrentHashMap<>(); nextSessionId = 0; - Timer timer = new Timer(); - timer.schedule(new SessionGarbageCollector(), 10000, SESSION_TTL / 2); + ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor(); + exec.scheduleWithFixedDelay(new SessionGarbageCollector(), 10000, SESSION_TTL / 2, TimeUnit.MILLISECONDS); logger.info("HTTP"+(keyStore==null?"":"S")+" Server ready!"); } @@ -92,10 +96,8 @@ public class HttpServer extends ThreadedTCPNetworkServer{ /** * This class acts as an garbage collector that * removes old sessions from the session HashMap - * - * @author Ziver */ - private class SessionGarbageCollector extends TimerTask { + private class SessionGarbageCollector implements Runnable { public void run(){ Object[] keys = sessions.keySet().toArray(); int count = 0; @@ -103,7 +105,7 @@ public class HttpServer extends ThreadedTCPNetworkServer{ Map session = sessions.get(key); // Check if session is still valid - if((Long)session.get(SESSION_TTL_KEY) < System.currentTimeMillis()){ + if(((Timer) session.get(SESSION_KEY_TTL)).hasTimedOut()){ sessions.remove(key); ++count; } @@ -190,28 +192,28 @@ public class HttpServer extends ThreadedTCPNetworkServer{ //**************************** HANDLE REQUEST ********************************* // Get the client session or create one - long ttlTime = System.currentTimeMillis() + SESSION_TTL; - String sessionCookie = header.getCookie(SESSION_ID_KEY); + String sessionCookie = header.getCookie(SESSION_KEY_ID); if (sessionCookie != null && sessions.containsKey(sessionCookie) && - (Long) sessions.get(sessionCookie).get(SESSION_TTL_KEY) < System.currentTimeMillis()) { // Check if session is still valid + !((Timer) sessions.get(sessionCookie).get(SESSION_KEY_TTL)).hasTimedOut()) { // Check if session is still valid session = sessions.get(sessionCookie); - // renew the session TTL - session.put(SESSION_TTL_KEY, ttlTime); + ((Timer) sessions.get(sessionCookie).get(SESSION_KEY_TTL)).start(); // renew the session TTL } else { - session = Collections.synchronizedMap(new HashMap()); - session.put(SESSION_ID_KEY, nextSessionId); - session.put(SESSION_TTL_KEY, ttlTime); - sessions.put(nextSessionId, session); - ++nextSessionId; + synchronized (sessions) { + session = new ConcurrentHashMap<>(); + session.put(SESSION_KEY_ID, ""+nextSessionId); + session.put(SESSION_KEY_TTL, new Timer(SESSION_TTL).start()); + sessions.put(""+nextSessionId, session); + out.setCookie(SESSION_KEY_ID, ""+nextSessionId); + ++nextSessionId; + } } //**************************** RESPONSE ************************************ out.setHttpVersion("1.0"); out.setStatusCode(200); - out.setHeader("Server", SERVER_VERSION); + out.setHeader("Server", SERVER_NAME); out.setHeader("Content-Type", "text/html"); - out.setCookie(SESSION_ID_KEY, "" + session.get(SESSION_ID_KEY)); if (header.getRequestURL() != null && pages.containsKey(header.getRequestURL())) { HttpPage page = pages.get(header.getRequestURL()); diff --git a/test/zutil/net/http/page/HttpGuessTheNumber.java b/test/zutil/net/http/page/HttpGuessTheNumber.java index 9b05160..bf35750 100755 --- a/test/zutil/net/http/page/HttpGuessTheNumber.java +++ b/test/zutil/net/http/page/HttpGuessTheNumber.java @@ -24,6 +24,8 @@ package zutil.net.http.page; +import zutil.log.CompactLogFormatter; +import zutil.log.LogUtil; import zutil.net.http.HttpHeader; import zutil.net.http.HttpPage; import zutil.net.http.HttpPrintStream; @@ -31,12 +33,24 @@ import zutil.net.http.HttpServer; import java.io.IOException; import java.util.Map; +import java.util.logging.Level; + +import static zutil.net.http.HttpServer.SESSION_KEY_ID; public class HttpGuessTheNumber implements HttpPage { + private static final String SESSION_KEY_NUMBER = "random_number"; + private static final String REQUEST_KEY_GUESS = "guess"; + private static final String COOKIE_KEY_LOW = "low"; + private static final String COOKIE_KEY_HIGH = "high"; + + public static void main(String[] args) throws IOException{ - //HttpServer server = new HttpServer("localhost", 443, FileFinder.find("keySSL"), "rootroot");//SSL + LogUtil.setGlobalLevel(Level.ALL); + LogUtil.setGlobalFormatter(new CompactLogFormatter()); + + //HttpServer server = new HttpServer("localhost", 443, FileFinder.find("keySSL"), "rootroot");//SSL HttpServer server = new HttpServer(8080); server.setDefaultPage(new HttpGuessTheNumber()); server.run(); @@ -52,55 +66,52 @@ public class HttpGuessTheNumber implements HttpPage { out.println(""); out.println("

Welcome To The Number Guess Game!

"); - if(session.containsKey("random_nummber") && request.containsKey("guess") && !request.get("guess").isEmpty()){ - int guess = Integer.parseInt(request.get("guess")); - int nummber = (Integer)session.get("random_nummber"); - try { - if(guess == nummber){ - session.remove("random_nummber"); - out.println("You Guessed Right! Congrats!"); - out.println(""); - return; - } - else if(guess > nummber){ - out.println("To High
"); - if(Integer.parseInt(cookie.get("high")) > guess){ - out.setCookie("high", ""+guess); - cookie.put("high", ""+guess); - } - } - else{ - out.println("To Low
"); - if(Integer.parseInt(cookie.get("low")) < guess){ - out.setCookie("low", ""+guess); - cookie.put("low", ""+guess); - } - } - } catch (Exception e) { - e.printStackTrace(); - } + String low = cookie.get(COOKIE_KEY_LOW); + String high = cookie.get(COOKIE_KEY_HIGH); + + if(session.containsKey(SESSION_KEY_NUMBER)){ + if (request.containsKey(REQUEST_KEY_GUESS)) { + int guess = Integer.parseInt(request.get(REQUEST_KEY_GUESS)); + int number = (Integer) session.get(SESSION_KEY_NUMBER); + + if (guess == number) { + session.remove(SESSION_KEY_NUMBER); + out.println("You Guessed Right! Congrats!"); + out.println(""); + return; + } else if (guess > number) { + out.println("To High
"); + if (Integer.parseInt(high) > guess) { + high = String.valueOf(guess); + out.setCookie(COOKIE_KEY_HIGH, high); + } + } else { + out.println("To Low
"); + if (Integer.parseInt(low) < guess) { + low = String.valueOf(guess); + out.setCookie(COOKIE_KEY_LOW, low); + } + } + } } else{ - session.put("random_nummber", (int)(Math.random()*99+1)); - try { - out.setCookie("low", "0"); - out.setCookie("high", "100"); - cookie.put("low", "0"); - cookie.put("high", "100"); - } catch (Exception e) { - e.printStackTrace(); - } + session.put(SESSION_KEY_NUMBER, (int)(Math.random()*99+1)); + low = "0"; + high = "100"; + out.setCookie(COOKIE_KEY_LOW, low); + out.setCookie(COOKIE_KEY_HIGH, high); } out.println("
"); - out.println(cookie.get("low")+" < X < "+cookie.get("high")+"
"); + out.println(low+" < X < "+high+"
"); out.println("Guess a number between 0 and 100:
"); out.println(""); out.println(""); out.println(""); out.println("
"); out.println(""); - out.println("DEBUG: nummber="+session.get("random_nummber")+"
"); + out.println("DEBUG: session_id="+session.get(SESSION_KEY_ID)+"
"); + out.println("DEBUG: number="+session.get(SESSION_KEY_NUMBER)+"
"); out.println(""); }