Java tutorial
package jhttpp2; /* Written and copyright 2001-2003 Benjamin Kohl. * Distributed under the GNU General Public License; see the README file. * This code comes with NO WARRANTY. */ import java.io.IOException; import java.io.InputStream; import java.io.BufferedInputStream; import java.net.InetAddress; import java.net.URL; import java.net.UnknownHostException; import java.util.SortedMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * File: Jhttpp2BufferedFilterStream.java * * @author Benjamin Kohl */ public class Jhttpp2ClientInputStream extends BufferedInputStream { private static Log log = LogFactory.getLog(Jhttpp2ClientInputStream.class); private String buf; private int lread = 0; /** * The length of the header (with body, if one) */ private int header_length = 0; /** * The length of the (optional) body of the actual request */ private int content_len = 0; /** * This is set to true with requests with bodies, like "POST" */ private boolean body = false; private Jhttpp2Server server; private Jhttpp2HTTPSession connection; private InetAddress remote_host; private String remote_host_name; private boolean ssl = false; private String errordescription; private int statuscode; public String url; public String method; public int remote_port = 0; public int post_data_len = 0; public int getHeaderLength() { return header_length; } public InetAddress getRemoteHost() { return remote_host; } public String getRemoteHostName() { return remote_host_name; } public Jhttpp2ClientInputStream(Jhttpp2Server server, Jhttpp2HTTPSession connection, InputStream a) { super(a); this.server = server; this.connection = connection; } /** * Handler for the actual HTTP request * * @exception IOException */ public int read(byte[] a) throws IOException { statuscode = Jhttpp2HTTPSession.SC_OK; if (ssl) return super.read(a); boolean cookies_enabled = server.enableCookiesByDefault(); String rq = ""; header_length = 0; post_data_len = 0; content_len = 0; boolean start_line = true; buf = getLine(); // reads the first line while (lread > 2) { if (start_line) { start_line = false; int methodID = server.getHttpMethod(buf); switch (methodID) { case -1: statuscode = Jhttpp2HTTPSession.SC_NOT_SUPPORTED; break; case 2: ssl = true; default: InetAddress host = parseRequest(buf, methodID); if (statuscode != Jhttpp2HTTPSession.SC_OK) break; // error occured, go on with the next line if (!server.use_proxy && !ssl) { /* creates a new request without the hostname */ buf = method + " " + url + " " + server.getHttpVersion() + "\r\n"; lread = buf.length(); } if ((server.use_proxy && connection.notConnected()) || !host.equals(remote_host)) { if (server.debug) server.writeLog("read_f: STATE_CONNECT_TO_NEW_HOST"); statuscode = Jhttpp2HTTPSession.SC_CONNECTING_TO_HOST; remote_host = host; } /* * ------------------------- url blocking (only "GET" * method) ------------------------- */ if (Jhttpp2Server.block_urls && methodID == 0 && statuscode != Jhttpp2HTTPSession.SC_FILE_REQUEST) { log.debug("Searching match... for " + this.remote_host_name + url); Jhttpp2URLMatch match = server.findMatch(this.remote_host_name + url); if (match != null) { log.debug("Match found!"); cookies_enabled = match.getCookiesEnabled(); if (match.getActionIndex() == -1) break; OnURLAction action = server.getURLActions().get(match.getActionIndex()); if (action.onAccesssDeny()) { statuscode = Jhttpp2HTTPSession.SC_URL_BLOCKED; if (action.onAccessDenyWithCustomText()) errordescription = action.getCustomErrorText(); } else if (action.onAccessRedirect()) { statuscode = Jhttpp2HTTPSession.SC_MOVED_PERMANENTLY; errordescription = action.newLocation(); } } // end if match!=null) } // end if (server.block... } // end switch } // end if(startline) else { /*----------------------------------------------- * Content-Length parsing *-----------------------------------------------*/ if (server.startsWith(buf.toUpperCase(), "CONTENT-LENGTH")) { String clen = buf.substring(16); if (clen.indexOf("\r") != -1) clen = clen.substring(0, clen.indexOf("\r")); else if (clen.indexOf("\n") != -1) clen = clen.substring(0, clen.indexOf("\n")); try { content_len = Integer.parseInt(clen); } catch (NumberFormatException e) { statuscode = Jhttpp2HTTPSession.SC_CLIENT_ERROR; } log.debug("read_f: content_len: " + content_len); if (!ssl) body = true; // Note: in HTTP/1.1 any method can have a // body, not only "POST" } else if (server.startsWith(buf, "Proxy-Connection:")) { if (!server.use_proxy) buf = null; else { buf = "Proxy-Connection: Keep-Alive\r\n"; lread = buf.length(); } } /* * else if (server.startsWith(buf,"Connection:")) { if * (!server.use_proxy) { buf="Connection: Keep-Alive\r\n"; //use * always keep-alive lread=buf.length(); } else buf=null; } */ /*----------------------------------------------- * cookie crunch section *-----------------------------------------------*/ else if (server.startsWith(buf, "Cookie:")) { if (!cookies_enabled) buf = null; } /*------------------------------------------------ * Http-Header filtering section *------------------------------------------------*/ else if (server.filter_http) { if (server.startsWith(buf, "Referer:")) {// removes // "Referer" buf = null; } else if (server.startsWith(buf, "User-Agent")) // changes // User-Agent { buf = "User-Agent: " + server.getUserAgent() + "\r\n"; lread = buf.length(); } } } if (buf != null) { rq += buf; if (server.debug) server.writeLog(buf); header_length += lread; } buf = getLine(); } rq += buf; // adds last line (should be an empty line) to the header // String header_length += lread; if (header_length == 0) { if (server.debug) server.writeLog("header_length=0, setting status to SC_CONNECTION_CLOSED (buggy request)"); statuscode = Jhttpp2HTTPSession.SC_CONNECTION_CLOSED; } for (int i = 0; i < header_length; i++) a[i] = (byte) rq.charAt(i); if (body) {// read the body, if "Content-Length" given post_data_len = 0; while (post_data_len < content_len) { a[header_length + post_data_len] = (byte) read(); // writes data // into the // array post_data_len++; } header_length += content_len; // add the body-length to the // header-length body = false; } return (statuscode == Jhttpp2HTTPSession.SC_OK) ? header_length : -1; // return // -1 // with // an // error } /** * reads a line * * @exception IOException */ public String getLine() throws IOException { int l = 0; String line = ""; lread = 0; while (l != '\n') { l = read(); if (l != -1) { line += (char) l; lread++; } else break; } return line; } /** * Parser for the first (!) line from the HTTP request<BR> * Sets up the URL, method and remote hostname. * * @return an InetAddress for the hostname, null on errors with a * statuscode!=SC_OK */ public InetAddress parseRequest(String a, int method_index) { log.debug(a); String f; int pos; url = ""; if (ssl) { f = a.substring(8); } else { method = a.substring(0, a.indexOf(" ")); // first word in the line pos = a.indexOf(":"); // locate first : if (pos == -1) { // occours with "GET / HTTP/1.1" url = a.substring(a.indexOf(" ") + 1, a.lastIndexOf(" ")); if (method_index == 0) { // method_index==0 --> GET if (url.indexOf(server.WEB_CONFIG_FILE) != -1) statuscode = Jhttpp2HTTPSession.SC_CONFIG_RQ; else statuscode = Jhttpp2HTTPSession.SC_FILE_REQUEST; } else { if (method_index == 1 && url.indexOf(server.WEB_CONFIG_FILE) != -1) { // allow // "POST" // for // admin // log // in statuscode = Jhttpp2HTTPSession.SC_CONFIG_RQ; } else { statuscode = Jhttpp2HTTPSession.SC_INTERNAL_SERVER_ERROR; errordescription = "This WWW proxy supports only the \"GET\" method while acting as webserver."; } } return null; } f = a.substring(pos + 3); // removes "http://" } pos = f.indexOf(" "); // locate space, should be the space before // "HTTP/1.1" if (pos == -1) { // buggy request statuscode = Jhttpp2HTTPSession.SC_CLIENT_ERROR; errordescription = "Your browser sent an invalid request: \"" + a + "\""; return null; } f = f.substring(0, pos); // removes all after space // if the url contains a space... it's not our mistake...(url's must // never contain a space character) pos = f.indexOf("/"); // locate the first slash if (pos != -1) { url = f.substring(pos); // saves path without hostname f = f.substring(0, pos); // reduce string to the hostname } else url = "/"; // occurs with this request: // "GET http://localhost HTTP/1.1" pos = f.indexOf(":"); // check for the portnumber if (pos != -1) { String l_port = f.substring(pos + 1); l_port = l_port.indexOf(" ") != -1 ? l_port.substring(0, l_port.indexOf(" ")) : l_port; int i_port = 80; try { i_port = Integer.parseInt(l_port); } catch (NumberFormatException e_get_host) { server.writeLog("get_Host :" + e_get_host + " !!!!"); } f = f.substring(0, pos); remote_port = i_port; } else remote_port = 80; remote_host_name = f; SortedMap<String, URL> map = server.getHostRedirects(); for (String redirectHost : map.keySet()) { if (redirectHost.equals(remote_host_name)) { URL u = map.get(redirectHost); f = u.getHost(); if (u.getPort() != -1) { remote_port = u.getPort(); } log.debug("Redirecting host " + redirectHost + " to " + f + " port " + remote_port); } } InetAddress address = null; if (server.log_access) server.logAccess(connection.getLocalSocket().getInetAddress().getHostAddress() + " " + method + " " + getFullURL()); try { address = InetAddress.getByName(f); if (remote_port == server.port && address.equals(InetAddress.getLocalHost())) { if (url.indexOf(server.WEB_CONFIG_FILE) != -1 && (method_index == 0 || method_index == 1)) statuscode = Jhttpp2HTTPSession.SC_CONFIG_RQ; else if (method_index > 0) { statuscode = Jhttpp2HTTPSession.SC_INTERNAL_SERVER_ERROR; errordescription = "This WWW proxy supports only the \"GET\" method while acting as webserver."; } else statuscode = Jhttpp2HTTPSession.SC_FILE_REQUEST; } } catch (UnknownHostException e_u_host) { if (!server.use_proxy) statuscode = Jhttpp2HTTPSession.SC_HOST_NOT_FOUND; } return address; } /** * @return boolean whether the actual connection was established with the * CONNECT method. * @since 0.2.21 */ public boolean isTunnel() { return ssl; } /** * @return the full qualified URL of the actual request. * @since 0.4.0 */ public String getFullURL() { return "http" + (ssl ? "s" : "") + "://" + getRemoteHostName() + (remote_port != 80 ? (":" + remote_port) : "") + url; } /** * @return status-code for the actual request * @since 0.3.5 */ public int getStatusCode() { return statuscode; } /** * @return the (optional) error-description for this request */ public String getErrorDescription() { return errordescription; } }