/**
Copyright (C) 2004 Juho Vähä-Herttua
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
import java.io.*;
import java.util.*;
import java.text.*;
import java.net.URLDecoder;
public class HttpParser {
private static final String[][] HttpReplies = {{"100", "Continue"},
{"101", "Switching Protocols"},
{"200", "OK"},
{"201", "Created"},
{"202", "Accepted"},
{"203", "Non-Authoritative Information"},
{"204", "No Content"},
{"205", "Reset Content"},
{"206", "Partial Content"},
{"300", "Multiple Choices"},
{"301", "Moved Permanently"},
{"302", "Found"},
{"303", "See Other"},
{"304", "Not Modified"},
{"305", "Use Proxy"},
{"306", "(Unused)"},
{"307", "Temporary Redirect"},
{"400", "Bad Request"},
{"401", "Unauthorized"},
{"402", "Payment Required"},
{"403", "Forbidden"},
{"404", "Not Found"},
{"405", "Method Not Allowed"},
{"406", "Not Acceptable"},
{"407", "Proxy Authentication Required"},
{"408", "Request Timeout"},
{"409", "Conflict"},
{"410", "Gone"},
{"411", "Length Required"},
{"412", "Precondition Failed"},
{"413", "Request Entity Too Large"},
{"414", "Request-URI Too Long"},
{"415", "Unsupported Media Type"},
{"416", "Requested Range Not Satisfiable"},
{"417", "Expectation Failed"},
{"500", "Internal Server Error"},
{"501", "Not Implemented"},
{"502", "Bad Gateway"},
{"503", "Service Unavailable"},
{"504", "Gateway Timeout"},
{"505", "HTTP Version Not Supported"}};
private BufferedReader reader;
private String method, url;
private Hashtable headers, params;
private int[] ver;
public HttpParser(InputStream is) {
reader = new BufferedReader(new InputStreamReader(is));
method = "";
url = "";
headers = new Hashtable();
params = new Hashtable();
ver = new int[2];
}
public int parseRequest() throws IOException {
String initial, prms[], cmd[], temp[];
int ret, idx, i;
ret = 200; // default is OK now
initial = reader.readLine();
if (initial == null || initial.length() == 0) return 0;
if (Character.isWhitespace(initial.charAt(0))) {
// starting whitespace, return bad request
return 400;
}
cmd = initial.split("\\s");
if (cmd.length != 3) {
return 400;
}
if (cmd[2].indexOf("HTTP/") == 0 && cmd[2].indexOf('.') > 5) {
temp = cmd[2].substring(5).split("\\.");
try {
ver[0] = Integer.parseInt(temp[0]);
ver[1] = Integer.parseInt(temp[1]);
} catch (NumberFormatException nfe) {
ret = 400;
}
}
else ret = 400;
if (cmd[0].equals("GET") || cmd[0].equals("HEAD")) {
method = cmd[0];
idx = cmd[1].indexOf('?');
if (idx < 0) url = cmd[1];
else {
url = URLDecoder.decode(cmd[1].substring(0, idx), "ISO-8859-1");
prms = cmd[1].substring(idx+1).split("&");
params = new Hashtable();
for (i=0; i<prms.length; i++) {
temp = prms[i].split("=");
if (temp.length == 2) {
// we use ISO-8859-1 as temporary charset and then
// String.getBytes("ISO-8859-1") to get the data
params.put(URLDecoder.decode(temp[0], "ISO-8859-1"),
URLDecoder.decode(temp[1], "ISO-8859-1"));
}
else if(temp.length == 1 && prms[i].indexOf('=') == prms[i].length()-1) {
// handle empty string separatedly
params.put(URLDecoder.decode(temp[0], "ISO-8859-1"), "");
}
}
}
parseHeaders();
if (headers == null) ret = 400;
}
else if (cmd[0].equals("POST")) {
ret = 501; // not implemented
}
else if (ver[0] == 1 && ver[1] >= 1) {
if (cmd[0].equals("OPTIONS") ||
cmd[0].equals("PUT") ||
cmd[0].equals("DELETE") ||
cmd[0].equals("TRACE") ||
cmd[0].equals("CONNECT")) {
ret = 501; // not implemented
}
}
else {
// meh not understand, bad request
ret = 400;
}
if (ver[0] == 1 && ver[1] >= 1 && getHeader("Host") == null) {
ret = 400;
}
return ret;
}
private void parseHeaders() throws IOException {
String line;
int idx;
// that fscking rfc822 allows multiple lines, we don't care now
line = reader.readLine();
while (!line.equals("")) {
idx = line.indexOf(':');
if (idx < 0) {
headers = null;
break;
}
else {
headers.put(line.substring(0, idx).toLowerCase(), line.substring(idx+1).trim());
}
line = reader.readLine();
}
}
public String getMethod() {
return method;
}
public String getHeader(String key) {
if (headers != null)
return (String) headers.get(key.toLowerCase());
else return null;
}
public Hashtable getHeaders() {
return headers;
}
public String getRequestURL() {
return url;
}
public String getParam(String key) {
return (String) params.get(key);
}
public Hashtable getParams() {
return params;
}
public String getVersion() {
return ver[0] + "." + ver[1];
}
public int compareVersion(int major, int minor) {
if (major < ver[0]) return -1;
else if (major > ver[0]) return 1;
else if (minor < ver[1]) return -1;
else if (minor > ver[1]) return 1;
else return 0;
}
public static String getHttpReply(int codevalue) {
String key, ret;
int i;
ret = null;
key = "" + codevalue;
for (i=0; i<HttpReplies.length; i++) {
if (HttpReplies[i][0].equals(key)) {
ret = codevalue + " " + HttpReplies[i][1];
break;
}
}
return ret;
}
public static String getDateHeader() {
SimpleDateFormat format;
String ret;
format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss", Locale.US);
format.setTimeZone(TimeZone.getTimeZone("GMT"));
ret = "Date: " + format.format(new Date()) + " GMT";
return ret;
}
}
|