Added test for http parser and fixed some issues

This commit is contained in:
Ziver Koc 2020-11-10 21:18:36 +01:00
parent c196a7cca0
commit 9934ff1df5
8 changed files with 163 additions and 55 deletions

View file

@ -35,31 +35,34 @@ import java.util.TreeMap;
public class HttpHeader {
// Constants
public static final String HEADER_CACHE_CONTROL = "Cache-Control";
public static final String HEADER_COOKIE = "Cookie";
public static final String HEADER_CONTENT_TYPE = "Content-Type";
public static final String HEADER_CONTENT_LENGTH = "Content-Length";
public static final String HEADER_COOKIE = "Cookie";
public static final String HEADER_SET_COOKIE = "Set-Cookie";
public static final String HEADER_SERVER = "Server";
public static final String HEADER_USER_AGENT = "User-Agent";
public static final String HEADER_IF_NONE_MATCH = "If-None-Match";
// Variables
private boolean isRequest = true;
/** Specifies the protocol that should be used */
private String protocol = "HTTP";
private String protocol = null;
/** The protocol version specified in the header */
private float protocolVersion = 1.0f;
private float protocolVersion = -1;
/** HTTP type specified in a HTTP request, e.g GET POST DELETE PUT etc */
private String requestType = "GET";
private String requestType = null;
/** String containing the target URL */
private String requestUrl = "/";
private String requestUrl = null;
/** Map containing all the properties from the URL */
private Map<String, String> requestUrlAttributes = new HashMap<>();
/** Status code specified in a HTTP response message */
private int responseStatusCode = 200;
private int responseStatusCode = -1;
private String responseStatusString = null;
/** An Map of all header fields */
private Map<String, String> headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
@ -136,8 +139,16 @@ public class HttpHeader {
public void setResponseStatusCode(int code) {
this.responseStatusCode = code;
this.responseStatusString = getResponseStatusString(code);
}
public String getResponseStatusString() {
return responseStatusString;
}
public void getResponseStatusString(String msg) {
this.responseStatusString = msg;
}
/**
* @return the URL that the client sent the server
@ -303,10 +314,6 @@ public class HttpHeader {
}
public String getResponseStatusString() {
return getResponseStatusString(responseStatusCode);
}
public static String getResponseStatusString(int type) {
switch (type) {
case 100: return "Continue";

View file

@ -101,28 +101,34 @@ public class HttpHeaderParser {
* @param statusLine the status line String
*/
private static void parseStatusLine(HttpHeader header, String statusLine) {
String[] lineArr = statusLine.split(" ", 3);
if (lineArr.length != 3)
return;
// Server Response
if (statusLine.startsWith("HTTP/")) {
if (lineArr[0].contains("/")) {
header.setIsRequest(false);
header.setProtocolVersion(Float.parseFloat(statusLine.substring(5, 8)));
header.setResponseStatusCode(Integer.parseInt(statusLine.substring(9, statusLine.indexOf(' ', 9))));
header.setProtocol(lineArr[0].substring(0, lineArr[0].indexOf('/')));
header.setProtocolVersion(Float.parseFloat(lineArr[0].substring(lineArr[0].indexOf('/')+1)));
header.setResponseStatusCode(Integer.parseInt(lineArr[1]));
header.getResponseStatusString(lineArr[2]);
}
// Client Request
else if (statusLine.contains("HTTP/")) {
else {
header.setIsRequest(true);
header.setRequestType(statusLine.substring(0, statusLine.indexOf(" ")).trim());
header.setProtocolVersion(Float.parseFloat(statusLine.substring(statusLine.lastIndexOf("HTTP/") + 5).trim()));
statusLine = (statusLine.substring(header.getRequestType().length() + 1, statusLine.lastIndexOf("HTTP/")));
header.setRequestType(lineArr[0]);
header.setProtocol(lineArr[2].substring(0, lineArr[2].indexOf('/')));
header.setProtocolVersion(Float.parseFloat(lineArr[2].substring(lineArr[2].indexOf('/')+1)));
String url = lineArr[1];
// parse URL and attributes
int index = statusLine.indexOf('?');
if (index > -1) {
header.setRequestURL(statusLine.substring(0, index));
statusLine = statusLine.substring(index + 1);
parseURLParameters(header.getURLAttributeMap(), statusLine);
} else {
header.setRequestURL(statusLine);
int paramStartIndex = url.indexOf('?');
if (paramStartIndex >= 0) {
url = statusLine.substring(0, paramStartIndex);
parseURLParameters(header.getURLAttributeMap(), statusLine.substring(paramStartIndex + 1));
}
header.setRequestURL(url.trim());
}
}

View file

@ -78,7 +78,20 @@ public class HttpPrintStream extends OutputStream {
*/
public HttpPrintStream(OutputStream out, HttpMessageType type) {
this.out = new PrintStream(out);
header.setIsRequest(type == HttpMessageType.REQUEST);
// Set defaults
header.setProtocol("HTTP");
header.setProtocolVersion(1.0f);
if (type == HttpMessageType.REQUEST) {
header.setIsRequest(true);
header.setRequestType("GET");
header.setRequestURL("/");
} else {
header.setIsRequest(false);
header.setResponseStatusCode(200);
}
}

View file

@ -50,11 +50,12 @@ public class HttpFilePage implements HttpPage{
private static final Logger log = LogUtil.getLogger();
private static final int MAX_CACHE_AGE_SECONDS = 120;
private File resource_root;
private final File resource_root;
private boolean showFolders;
private boolean redirectToIndex;
private HashMap<File,FileCache> cache;
private final HashMap<File,FileCache> cache;
private static class FileCache{
public long lastModified;
public String hash;
@ -64,6 +65,9 @@ public class HttpFilePage implements HttpPage{
* @param file a reference to a root directory or a file.
*/
public HttpFilePage(File file){
if (file == null)
throw new IllegalArgumentException("Root path cannot be null.");;
this.resource_root = file;
this.showFolders = true;
this.redirectToIndex = true;
@ -76,7 +80,7 @@ public class HttpFilePage implements HttpPage{
HttpHeader headers,
Map<String, Object> session,
Map<String, String> cookie,
Map<String, String> request) throws IOException{
Map<String, String> request) {
try {
// Is the root only one file or a folder
@ -95,15 +99,21 @@ public class HttpFilePage implements HttpPage{
}
// Show folder contents
else if (showFolders) {
out.println("<HTML><BODY><H1>Directory: " + headers.getRequestURL() + "</H1>");
out.println("<HR><UL>");
for (String f : file.list()) {
out.println("<html>");
out.println("<body>");
out.println(" <h1>Directory: " + headers.getRequestURL() + "</h1>");
out.println(" <hr>");
out.println(" <ul>");
for (String containingFile : file.list()) {
String url = headers.getRequestURL();
out.println("<LI><A href='" +
url + (url.charAt(url.length()-1)=='/'?"":"/")+ f
+"'>" + f + "</A></LI>");
out.println(" <li><a href='" +
url + (url.endsWith("/") ? "" : "/") + containingFile
+"'>" + containingFile + "</a></li>");
}
out.println("</UL><HR></BODY></HTML>");
out.println(" </ul>");
out.println(" <hr>");
out.println("</body>");
out.println("</html>");
}
else {
throw new SecurityException("User not allowed to view folder: root=" + resource_root.getAbsolutePath());
@ -133,13 +143,13 @@ public class HttpFilePage implements HttpPage{
private void deliverFileWithCache(HttpHeader headers, File file, HttpPrintStream out) throws IOException {
String eTag = getFileHash(file);
out.setHeader("Cache-Control", "max-age=" + MAX_CACHE_AGE_SECONDS);
out.setHeader(HttpHeader.HEADER_CACHE_CONTROL, "max-age=" + MAX_CACHE_AGE_SECONDS);
if (eTag != null) {
out.setHeader("ETag", "\"" + eTag + "\"");
if (headers.getHeader("If-None-Match") != null &&
eTag.equals(StringUtil.trimQuotes(headers.getHeader("If-None-Match")))) { // File has not changed
if (headers.getHeader(HttpHeader.HEADER_IF_NONE_MATCH) != null &&
eTag.equals(StringUtil.trimQuotes(headers.getHeader(HttpHeader.HEADER_IF_NONE_MATCH)))) { // File has not changed
out.setResponseStatusCode(304);
} else {
deliverFile(file, out);
@ -150,8 +160,8 @@ public class HttpFilePage implements HttpPage{
String fileExt = FileUtil.getFileExtension(file);
if (MimeTypeUtil.getMimeByExtension(fileExt) != null)
out.setHeader("Content-Type", MimeTypeUtil.getMimeByExtension(fileExt).toString());
out.setHeader("Content-Length", "" + file.length());
out.setHeader(HttpHeader.HEADER_CONTENT_TYPE, MimeTypeUtil.getMimeByExtension(fileExt).toString());
out.setHeader(HttpHeader.HEADER_CONTENT_LENGTH, "" + file.length());
out.flush();
InputStream in = new FileInputStream(file);