Java tutorial
/** Copyright (C) 2004 Juho Vh-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; } }