Network Protocol Java

/**
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          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      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;
  }
}