diff --git a/src/xdvrx1_serverProject/ClientRequest.java b/src/xdvrx1_serverProject/ClientRequest.java index cb2ac60..e7764d9 100644 --- a/src/xdvrx1_serverProject/ClientRequest.java +++ b/src/xdvrx1_serverProject/ClientRequest.java @@ -1,6 +1,6 @@ package xdvrx1_serverProject; -/* +/** * This is where the request of a client * is being processed. When we say `client`, * it can be Google Chrome or any other browser. @@ -8,249 +8,170 @@ * `FileWebServer` class. */ -import java.nio.file.Files; import java.io.*; import java.net.*; import java.util.logging.*; public class ClientRequest implements Runnable { - - FileNotFoundMessage message1 = new FileNotFoundMessage(); - NotSupportedMessage message2 = new NotSupportedMessage(); - - private String defaultPage = "index.html"; - private File rootDirectory; - private Socket connection; - - private final static Logger requestLogger = - Logger.getLogger(ClientRequest.class.getCanonicalName()); - - //the constructor - public ClientRequest(File rootDirectory, - String defaultPage, - Socket connection) { - - //check if the given rootDirectory is a file - //and will explicitly throw an exception - if (rootDirectory.isFile()) { - throw new - IllegalArgumentException("rootDirectory must be" - + "a directory, not a file"); - } - - //will try to get the canonical pathname - //from the supplied `rootDirectory` argument - try { - rootDirectory = rootDirectory.getCanonicalFile(); - } catch (IOException ex) { - requestLogger.log(Level.WARNING, "IOException", ex); - } - - //constructors `rootDirectory` is assigned to - //the successful `rootDirectory` - this.rootDirectory = rootDirectory; - - if (defaultPage != null) { - this.defaultPage = defaultPage; - } - - this.connection = connection; - - } - - @Override - public void run() { - - try { - //remember, once the connection is established - //the server will use the Socket to pass - //data back and forth - - //raw output stream, - //in case it is not a text document - //this will be used purely to pass - //the data as bytes - OutputStream raw = - new BufferedOutputStream(connection.getOutputStream()); - - //for text files that uses the - //underlying output stream - Writer out = - new OutputStreamWriter(raw); - - //needed to add new line correctly - //for different platforms - BufferedWriter bufferedOut = - new BufferedWriter(out); - - BufferedInputStream bis = - new BufferedInputStream(connection.getInputStream()); - - //for reading the GET header from a browser - Reader in = - new - InputStreamReader(bis, "US-ASCII"); - - //the request send by a client - //take note, this can be loaded into a data structure - //instead of using StringBuffer to generate string - //but, it's up to you, for demonstration - //I will just use the StringBuffer to build - //the string object - StringBuffer userRequest = new StringBuffer(); - - //this will be the basis to get - //all the bytes from the stream - int bufferSize = bis.available(); - - while (true) { - if (userRequest.length() > bufferSize-1) { - //for performance, always shutdown - //after breaking from this loop - connection.shutdownInput(); - break; - } + + private String defaultPage = "index.html"; + private File rootDirectory; + private Socket connection; + + private final static Logger requestLogger = + Logger.getLogger(ClientRequest.class.getCanonicalName()); + + //the constructor + public ClientRequest(File rootDirectory, + String defaultPage, + Socket connection) { + + //check if the given rootDirectory is a file + //and will explicitly throw an exception + if (rootDirectory.isFile()) { + throw new + IllegalArgumentException("rootDirectory must be" + + "a directory, not a file"); + } + + //will try to get the canonical pathname + //from the supplied `rootDirectory` argument + try { + rootDirectory = rootDirectory.getCanonicalFile(); + } catch (IOException ex) { + requestLogger.log(Level.WARNING, "IOException", ex); + } + + //constructors `rootDirectory` is assigned to + //the successful `rootDirectory` + this.rootDirectory = rootDirectory; + + if (defaultPage != null) { + this.defaultPage = defaultPage; + } + + this.connection = connection; + + } + + @Override + public void run() { + + try { + //remember, once the connection is established + //the server will use the Socket to pass + //data back and forth - //read() of Reader is actually a blocking - //method, and without proper algorithm - //this will hang the entire program - int c = in.read(); - userRequest.append((char) c); + //raw output stream, + //in case it is not a text document + //this will be used purely to pass + //the data as bytes + OutputStream raw = + new BufferedOutputStream(connection.getOutputStream()); - //ignore the line endings, - //the Reader will interpret this as end of buffer - //we need to read the entire content of the buffer - if (c == '\n' || c == '\r' || c == 1) continue; - } - - //build a string object from StringBuffer - String userRequestToString = userRequest.toString(); - - //get the first line through this index - int indexOfFirst = userRequestToString.indexOf("\r\n"); - String firstLine = userRequestToString - .substring(0,indexOfFirst); - - //express it in the logger, mostly for debugging purposes - requestLogger - .info(connection - .getRemoteSocketAddress() + " " + firstLine); - - //`token` are the words separated from the request line, - //for example, `GET /data/ HTTP/1.1` - String[] token = firstLine.split("\\s+"); - //0 index tells the method - String method = token[0]; - //null at first - String http_version = ""; - - if (method.equals("GET")) { - String fileName = token[1]; + //for text files that uses the + //underlying output stream + Writer out = + new OutputStreamWriter(raw); - //add manually the default page - if (fileName.endsWith("/")) { - fileName = fileName + defaultPage; - } + //needed to add new line correctly + //for different platforms + BufferedWriter bufferedOut = + new BufferedWriter(out); - //get the content type for proper encoding of data - String contentType = - URLConnection.getFileNameMap().getContentTypeFor(fileName); + BufferedInputStream bis = + new BufferedInputStream(connection.getInputStream()); - if (token.length > 2) { - http_version = token[2]; - } + //for reading the GET header from a browser + Reader in = + new + InputStreamReader(bis, "US-ASCII"); - File actualFile = - new File(rootDirectory, - fileName.substring(1, fileName.length())); + //the request send by a client + //take note, this can be loaded into a data structure + //instead of using StringBuffer to generate string + //but, it's up to you, for demonstration + //I will just use the StringBuffer to build + //the string object + ReadInputStream readInputStream = new ReadInputStream(); + StringBuffer userRequest = + readInputStream.readUserRequest(bis, in, connection); - String root = rootDirectory.getPath(); - - // restrict clients inside the document root - if (actualFile.canRead() - && actualFile.getCanonicalPath().startsWith(root)) { - - byte[] _data = Files.readAllBytes(actualFile.toPath()); - - if (http_version.startsWith("HTTP/")) { - // send a MIME header - ServerHeader - .serverHeader(out, - "HTTP/1.0 200 OK", - contentType, - _data.length); - } - - // still send the file; - //and use the underlying stream - //instead of the writer - raw.write(_data); - raw.flush(); - - } else { - - // file not found - if (http_version.startsWith("HTTP/")) { - // send a MIME header - ServerHeader - .serverHeader(out, - "HTTP/1.0 404 File Not Found", - "text/html; charset=utf-8", - message1.body.length()); - } - - out.write(message1.body); - out.flush(); - } + //build a string object from StringBuffer + String userRequestToString = userRequest.toString(); - } else if(method.equals("POST")) { + //get the first line through this index + int indexOfFirst = userRequestToString.indexOf("\r\n"); + String firstLine = userRequestToString + .substring(0,indexOfFirst); - //get the request body for POST method - //add 4, because the index that - //will be returned is relative to the - //very first occurence of the string - String requestBody = - userRequestToString - .substring(userRequestToString.lastIndexOf("\r\n\r\n") + 4); + //express it in the logger, mostly for debugging purposes + requestLogger + .info(connection + .getRemoteSocketAddress() + " " + firstLine); - //just showing the input data back to the client - //a lot of things can be done for the request body - //it can go directly to a file or a database, - //or be loaded into an XML file for further processing + //`token` are the words separated from the request line, + //for example, `GET /data/ HTTP/1.1` + String[] token = firstLine.split("\\s+"); + //0 index tells the method + String method = token[0]; + //null at first + String http_version = ""; - //we use also the buffered out writer - //to make sure that the new line will be correct - //for all platforms - bufferedOut.write("data recorded:"); - bufferedOut.newLine(); - bufferedOut.write(requestBody); - bufferedOut.flush(); - - } else { - - //not yet implemented methods - if (http_version.startsWith("HTTP/")) { - // send a MIME header - ServerHeader.serverHeader(out, - "HTTP/1.0 501 Not Implemented", - "text/html; charset=utf-8", - message2.body.length()); + if (method.equals("GET")) { + + GETMethod getMethod = new GETMethod(); + byte[] _data = getMethod.processGET(rootDirectory, + token, + defaultPage, + http_version, + out); + // still send the file; + //and use the underlying stream + //instead of the writer + raw.write(_data); + raw.flush(); + + } else if(method.equals("POST")) { + + POSTMethod postMethod = new POSTMethod(); + + String requestBody = + postMethod.returnPOSTData(userRequestToString); + + //we use also the buffered out writer + //to make sure that the new line will be correct + //for all platforms + bufferedOut.write("data recorded:"); + bufferedOut.newLine(); + bufferedOut.write(requestBody); + bufferedOut.flush(); + + } else { + + //not yet implemented methods + if (http_version.startsWith("HTTP/")) { + // send a MIME header + ServerHeader.serverHeader(out, + "HTTP/1.0 501 Not Implemented", + "text/html; charset=utf-8", + NotSupportedMessage.content.length()); + } + + out.write(NotSupportedMessage.content); + out.flush(); } - - out.write(message2.body); - out.flush(); - } - } catch (IOException ex) { - requestLogger - .log(Level.WARNING, "Can't talk to: " - + connection.getRemoteSocketAddress(), ex); - } finally { - try { - connection.close(); - } catch (IOException ex) { - requestLogger.log(Level.WARNING, "IO exception", ex); - } - } - } - + } catch (IOException ex) { + requestLogger + .log(Level.WARNING, "Can't talk to: " + + connection.getRemoteSocketAddress(), ex); + } finally { + try { + connection.close(); + } catch (IOException ex) { + requestLogger.log(Level.WARNING, "IO exception", ex); + } + } + } + } diff --git a/src/xdvrx1_serverProject/FileNotFoundMessage.java b/src/xdvrx1_serverProject/FileNotFoundMessage.java index d325488..ee7599c 100644 --- a/src/xdvrx1_serverProject/FileNotFoundMessage.java +++ b/src/xdvrx1_serverProject/FileNotFoundMessage.java @@ -1,14 +1,14 @@ package xdvrx1_serverProject; class FileNotFoundMessage { - - String body = - new StringBuilder("\r\n") - .append("