HttpParser.java Source code

Java tutorial

Introduction

Here is the source code for HttpParser.java

Source

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