import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.DataOutputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Random; import java.util.StringTokenizer; /** * Serves Hangman for HTTP (the browser version of the Hangman game). All * methods and fields are static. */ public final class WebServer { // TODO TCP-Server-Socket definition. private static ServerSocket welcomeSocket; /** HTTP EOL sequence. */ private static final String EOL = "\r\n";// TODO /** * Session ID to distinguish between the current and previous game sessions. */ private static int session; /** Session ID cookie of the currently handled request. */ private static int sessionCookie; /** Player number of the currently handled request. */ private static int playerCookie; /** Hangman game object. */ private static Hangman hangman; /** Used to save the result message of the previous action. */ private static String prevMsg; /** Number of players. */ private static final int NUM_PLAYERS = 2; /** Currently active player (0 - n-1). */ private static int curPlayer; /** * Indicates whether we are already in-game or still waiting for some * players. */ private static boolean gameStarted = false; /** Indicates whether the game has ended. */ private static boolean gameEnded = false; /** * Initializes the game. Loops until solution is found or hangman is dead. * * @param argv * Optional command line arguments. * @throws Exception */ public static void main(String[] argv) throws Exception { // TODO Initialize socket, global variables and hangman. welcomeSocket = new ServerSocket(2345); hangman = new Hangman(); curPlayer = 0; session = 0; while (true) { // TODO Accept client request. Socket clientSocket = welcomeSocket.accept(); BufferedReader br = new BufferedReader( new InputStreamReader(clientSocket.getInputStream(), "UTF-8")); // TODO BufferedWriter bw = new BufferedWriter( new OutputStreamWriter(clientSocket.getOutputStream(), "UTF-8")); // TODO if (!gameStarted && !gameEnded) { processInitRequest(br, bw); } else if (gameStarted && !gameEnded) { processGameRequest(br, bw); } else { processEndRequest(br, bw); if (curPlayer == NUM_PLAYERS) break; } br.close(); bw.close(); } welcomeSocket.close(); } /** * Handles HTTP conversation when game has not yet started. Waits for number * of players {@link #NUM_PLAYERS NUM_PLAYERS} to be present. * * @param br * The BufferedReader used to read the request. * @param bw * The BufferedWriter used to write the HTTP response. * @throws Exception */ private static void processInitRequest(BufferedReader br, BufferedWriter bw) throws Exception { // TODO Process request and header lines. String request = processHeaderLines(br, bw); if(request == null) return; String cookieLines = null; String content = "<HTML><HEAD><META http-equiv=\"refresh\" content=\"2\"><TITLE>Hangman</TITLE></HEAD><BODY>" + "<PRE>[ ] [ ]-[ ]<BR> |<BR>[ ] [ ]<BR> | /<BR>[ ]-[ ]<BR>____________</PRE>" + "Willkommen zu I7Hangman!<BR>Du bist Spieler "; // TODO If the player is unknown: set cookies and increment curPlayer. // Add player number to content. if(playerCookie == -1) { cookieLines = "sessionCookie=" +Integer.toString(sessionCookie)+", playerCookie="+ Integer.toString(curPlayer); content += Integer.toString(curPlayer); curPlayer++; System.out.println("\n new player\n"); } else { content += Integer.toString(playerCookie); } content += ".<BR>Es darf reihum ein Buchstabe geraten werden.<BR>Die Seite lädt automatisch neu.<BR>" + "Warte auf alle Spieler...</BODY></HTML>"; // TODO Send response to player. sendOkResponse(bw, cookieLines, content); if (curPlayer == NUM_PLAYERS) { System.out.println("\n Goooooo\n"); gameStarted = true; curPlayer = 0; } } /** * Handles HTTP conversation when game is running. Differentiates between * current player and other players. * * @param br * The BufferedReader used to read the request. * @param bw * The BufferedWriter used to write the HTTP response. * @throws Exception */ private static void processGameRequest(BufferedReader br, BufferedWriter bw) throws Exception { // TODO Process request and header lines. String requestLine = processHeaderLines(br, bw); if(requestLine == null) return; requestLine = requestLine.replace("/?", ""); requestLine = requestLine.replace(" ", "="); String[] requestLineArray = requestLine.split("="); // Construct the response message. String content = "<HTML><HEAD><TITLE>Hangman</TITLE>"; if (session == 1 && curPlayer == playerCookie)// TODO Player is current player and form was submitted. { session = 0; System.out.println("\n\n\n"+requestLineArray[0]+"-"); System.out.println(""+requestLineArray[1]+"\n\n\n"); if (requestLineArray[1].equals("letter"))// TODO Handle single character guess. { String answer = hangman.checkCharHtml(requestLineArray[2].charAt(0)); prevMsg = answer; } else if (requestLineArray[1].equals("solution"))// TODO Handle word guess. { String answer = hangman.checkWordHtml(requestLineArray[2]); prevMsg = answer; } // TODO Set curPlayer to next player. curPlayer++; if(curPlayer == NUM_PLAYERS) curPlayer = 0; content += "<META http-equiv=\"refresh\" content=\"0;url=/\"></HEAD><BODY>" + "<PRE>[ ] [ ]-[ ]<BR> |<BR>[ ] [ ]<BR> | /<BR>[ ]-[ ]<BR>____________</PRE>" + prevMsg + hangman.getHangmanHtml() + "Spieler " + curPlayer + " ist an der Reihe."; } else if (curPlayer == playerCookie)// TODO Player is current player. { content += "</HEAD><BODY>" + "<PRE>[ ] [ ]-[ ]<BR> |<BR>[ ] [ ]<BR> | /<BR>[ ]-[ ]<BR>____________</PRE>" + prevMsg + hangman.getHangmanHtml() + "Du bist an der Reihe, Spieler " + curPlayer + "!" + "<FORM action=\"/\" method=\"get\">"; for (char i = 'a'; i <= 'z'; ++i) { content += "<INPUT type=\"submit\" name=\"letter\" value=\"" + i + "\">"; } content += "</FORM><BR><FORM action=\"/\" method=\"get\">" + "<LABEL>Suchbegriff <INPUT name=\"solution\"></LABEL>" + "<BUTTON>Lösen</BUTTON></FORM>"; session = 1; } else { content += "<META http-equiv=\"refresh\" content=\"2;url=/\"></HEAD><BODY>" + "<PRE>[ ] [ ]-[ ]<BR> |<BR>[ ] [ ]<BR> | /<BR>[ ]-[ ]<BR>____________</PRE>" + prevMsg + hangman.getHangmanHtml() + "Spieler " + curPlayer + " ist an der Reihe."; } content += "</BODY></HTML>"; // TODO Send response to player. sendOkResponse(bw, null, content); if (hangman.win() || hangman.dead()) { gameStarted = false; gameEnded = true; curPlayer = 0; } } /** * Handles HTTP conversation when game ended. * * @param br * The BufferedReader used to read the request. * @param bw * The BufferedWriter used to write the HTTP response. * @throws Exception */ private static void processEndRequest(BufferedReader br, BufferedWriter bw) throws Exception { // TODO Process request and header lines. String requestLine = processHeaderLines(br, bw); if(requestLine == null) return; String content = "<HTML><HEAD><TITLE>Hangman</TITLE></HEAD><BODY>" + "<PRE>[ ] [ ]-[ ]<BR> |<BR>[ ] [ ]<BR> | /<BR>[ ]-[ ]<BR>____________</PRE>" + prevMsg + hangman.getHangmanHtml(); // TODO Add success/fail line with solution word. content += "</BODY></HTML>"; ++curPlayer; // TODO Send response to player. String cookieLine = "sessionCookie=" +Integer.toString(-1)+"; playerCookie="+ Integer.toString(-1); sendOkResponse(bw, cookieLine, content); } /** * Processes the HTTP request and its header lines. * * @param br * The BufferedReader used to read the request. * @param bw * The BufferedWriter used to write the HTTP response. * @return The request line of the HTTP request if it is a valid game * related request, otherwise null. * @throws Exception */ private static String processHeaderLines(BufferedReader br, BufferedWriter bw) throws Exception { /* * TODO Get the request line of the HTTP request message. Return null if * its length is zero or if end of stream is reached. Print out the * request line to the console. If the request is for "/favicon.ico", * send a 404 response and return null. */ String request = br.readLine(); if(request == null) { sendNotFoundResponse(bw); return null; } if(request.isEmpty()) { sendNotFoundResponse(bw); return null; } String[] rqst_array = request.split(" "); if(rqst_array[1].equals("/favicon.ico")) { sendNotFoundResponse(bw); return null; } System.out.println(request); sessionCookie = -1; playerCookie = -1; // TODO Step through all remaining header lines and extract cookies if // present (yamyam). Optionally print the header lines to the console. String r; while(!(r = br.readLine()).isEmpty()) { System.out.println(r); if(r.startsWith("Cookie")) { r = r.replace(",", ""); String[] cookieArray = r.split(" "); sessionCookie = Integer.parseInt(cookieArray[1].split("=")[1]); playerCookie = Integer.parseInt(cookieArray[2].split("=")[1]); } } // TODO Return return request; } /** * Sends a 404 HTTP response. * * @param bw * The BufferedWriter used to write the HTTP response. * @throws Exception */ private static void sendNotFoundResponse(BufferedWriter bw) throws Exception { // TODO Construct and send a valid HTTP/1.0 404-response. bw.write("HTTP/1.1 404 Not Found"+EOL); bw.write("Content-Length: 0"+EOL); bw.write(EOL); bw.flush(); } /** * Sends a HTTP response with cookies (if set) and HTML content. * * @param bw * The BufferedWriter used to write the HTTP response. * @param cookieLines * Optional header lines to set cookies. * @param content * The actual HTML content to be sent to the browser. * @throws Exception */ private static void sendOkResponse(BufferedWriter bw, String cookieLines, String content) throws Exception { // TODO Construct and send a valid HTTP/1.0 200-response with the given // cookies (if not null) and the given content. bw.write("HTTP/1.1 200 OK"+ EOL); bw.write("Connection: close"+ EOL); bw.write("Date: " + new java.util.Date() + EOL); bw.write("Server: Java HTTP Server 1.0" + EOL); bw.write("Content-Length: "+Integer.toString(content.length())+EOL); bw.write("Content-Type: text/html; charset=utf8"+ EOL); if(cookieLines != null && !cookieLines.isEmpty()) { bw.write("Set-Cookie: "+cookieLines+EOL); } bw.write(EOL); bw.write(content); bw.flush(); } }