首页 > 技术文章 > InputStream的封装类

wuxinliulei 2015-11-15 22:22 原文

package ex03.pyrmont.connector.http;

import java.io.IOException;
import java.io.InputStream;
import java.io.EOFException;
import org.apache.catalina.util.StringManager;

/**
 * 继承于InputStream,可以在处理HTTP请求头的时候更有效率
 */
public class SocketInputStream extends InputStream {


    // ---------------------------------------------------------解析字符串时的常量


    /**
     * CR. 回车
     */
    private static final byte CR = (byte) '\r';


    /**
     * LF.换行
     */
    private static final byte LF = (byte) '\n';


    /**
     * SP.空格
     */
    private static final byte SP = (byte) ' ';


    /**
     * HT. Tab
     */
    private static final byte HT = (byte) '\t';


    /**
     * COLON. 冒号
     */
    private static final byte COLON = (byte) ':';


    /**
     * Lower case offset. 小写字符转大写的偏移量
     */
    private static final int LC_OFFSET = 'A' - 'a';


    /**
     * 内部缓存.
     */
    protected byte buf[];


    /**
     * 最大字节数.
     */
    protected int count;


    /**
     * Position in the buffer.
     */
    protected int pos;


    /**
     * Underlying input stream.里层的输入流
     */
    protected InputStream is;


    // ----------------------------------------------------------- Constructors


    /**
     * Construct a servlet input stream associated with the specified socket
     * input.
     *
     * @param is socket input stream
     * @param bufferSize size of the internal buffer
     */
    public SocketInputStream(InputStream is, int bufferSize) {

        this.is = is;
        buf = new byte[bufferSize];

    }


    // -------------------------------------------------------------- Variables


    /**
     * The string manager for this package.
     */
    protected static StringManager sm =
        StringManager.getManager(Constants.Package);


    // ----------------------------------------------------- Instance Variables


    // --------------------------------------------------------- Public Methods


    /**
     * Read the request line, and copies it to the given buffer. This
     * function is meant to be used during the HTTP request header parsing.
     * Do NOT attempt to read the request body using it.
     *
     * @param requestLine Request line object
     * @throws IOException If an exception occurs during the underlying socket
     * read operations, or if the given buffer is not big enough to accomodate
     * the whole line.
     */
    public void readRequestLine(HttpRequestLine requestLine)
        throws IOException {

        // Recycling check
        if (requestLine.methodEnd != 0)
            requestLine.recycle();

        // Checking for a blank line
        int chr = 0;
        do { // Skipping CR or LF
            try {
                chr = read();
            } catch (IOException e) {
                chr = -1;
            }
        } while ((chr == CR) || (chr == LF));
        if (chr == -1)
            throw new EOFException
                (sm.getString("requestStream.readline.error"));
        pos--;

        // Reading the method name

        int maxRead = requestLine.method.length;
        int readStart = pos;
        int readCount = 0;

        boolean space = false;

        while (!space) {
            // if the buffer is full, extend it
            if (readCount >= maxRead) {
                if ((2 * maxRead) <= HttpRequestLine.MAX_METHOD_SIZE) {
                    char[] newBuffer = new char[2 * maxRead];
                    System.arraycopy(requestLine.method, 0, newBuffer, 0,
                                     maxRead);
                    requestLine.method = newBuffer;
                    maxRead = requestLine.method.length;
                } else {
                    throw new IOException
                        (sm.getString("requestStream.readline.toolong"));
                }
            }
            // We're at the end of the internal buffer
            if (pos >= count) {
                int val = read();
                if (val == -1) {
                    throw new IOException
                        (sm.getString("requestStream.readline.error"));
                }
                pos = 0;
                readStart = 0;
            }
            if (buf[pos] == SP) {
                space = true;
            }
            requestLine.method[readCount] = (char) buf[pos];
            readCount++;
            pos++;
        }

        requestLine.methodEnd = readCount - 1;

        // Reading URI

        maxRead = requestLine.uri.length;
        readStart = pos;
        readCount = 0;

        space = false;

        boolean eol = false;

        while (!space) {
            // if the buffer is full, extend it
            if (readCount >= maxRead) {
                if ((2 * maxRead) <= HttpRequestLine.MAX_URI_SIZE) {
                    char[] newBuffer = new char[2 * maxRead];
                    System.arraycopy(requestLine.uri, 0, newBuffer, 0,
                                     maxRead);
                    requestLine.uri = newBuffer;
                    maxRead = requestLine.uri.length;
                } else {
                    throw new IOException
                        (sm.getString("requestStream.readline.toolong"));
                }
            }
            // We're at the end of the internal buffer
            if (pos >= count) {
                int val = read();
                if (val == -1)
                    throw new IOException
                        (sm.getString("requestStream.readline.error"));
                pos = 0;
                readStart = 0;
            }
            if (buf[pos] == SP) {
                space = true;
            } else if ((buf[pos] == CR) || (buf[pos] == LF)) {
                // HTTP/0.9 style request
                eol = true;
                space = true;
            }
            requestLine.uri[readCount] = (char) buf[pos];
            readCount++;
            pos++;
        }

        requestLine.uriEnd = readCount - 1;

        // Reading protocol

        maxRead = requestLine.protocol.length;
        readStart = pos;
        readCount = 0;

        while (!eol) {
            // if the buffer is full, extend it
            if (readCount >= maxRead) {
                if ((2 * maxRead) <= HttpRequestLine.MAX_PROTOCOL_SIZE) {
                    char[] newBuffer = new char[2 * maxRead];
                    System.arraycopy(requestLine.protocol, 0, newBuffer, 0,
                                     maxRead);
                    requestLine.protocol = newBuffer;
                    maxRead = requestLine.protocol.length;
                } else {
                    throw new IOException
                        (sm.getString("requestStream.readline.toolong"));
                }
            }
            // We're at the end of the internal buffer
            if (pos >= count) {
                // Copying part (or all) of the internal buffer to the line
                // buffer
                int val = read();
                if (val == -1)
                    throw new IOException
                        (sm.getString("requestStream.readline.error"));
                pos = 0;
                readStart = 0;
            }
            if (buf[pos] == CR) {
                // Skip CR.
            } else if (buf[pos] == LF) {
                eol = true;
            } else {
                requestLine.protocol[readCount] = (char) buf[pos];
                readCount++;
            }
            pos++;
        }

        requestLine.protocolEnd = readCount;

    }


    /**
     * Read a header, and copies it to the given buffer. This
     * function is meant to be used during the HTTP request header parsing.
     * Do NOT attempt to read the request body using it.
     *
     * @param requestLine Request line object
     * @throws IOException If an exception occurs during the underlying socket
     * read operations, or if the given buffer is not big enough to accomodate
     * the whole line.
     */
    public void readHeader(HttpHeader header)
        throws IOException {

        // Recycling check
        if (header.nameEnd != 0)
            header.recycle();

        // Checking for a blank line
        int chr = read();
        if ((chr == CR) || (chr == LF)) { // Skipping CR
            if (chr == CR)
                read(); // Skipping LF
            header.nameEnd = 0;
            header.valueEnd = 0;
            return;
        } else {
            pos--;
        }

        // Reading the header name

        int maxRead = header.name.length;
        int readStart = pos;
        int readCount = 0;

        boolean colon = false;

        while (!colon) {
            // if the buffer is full, extend it
            if (readCount >= maxRead) {
                if ((2 * maxRead) <= HttpHeader.MAX_NAME_SIZE) {
                    char[] newBuffer = new char[2 * maxRead];
                    System.arraycopy(header.name, 0, newBuffer, 0, maxRead);
                    header.name = newBuffer;
                    maxRead = header.name.length;
                } else {
                    throw new IOException
                        (sm.getString("requestStream.readline.toolong"));
                }
            }
            // We're at the end of the internal buffer
            if (pos >= count) {
                int val = read();
                if (val == -1) {
                    throw new IOException
                        (sm.getString("requestStream.readline.error"));
                }
                pos = 0;
                readStart = 0;
            }
            if (buf[pos] == COLON) {
                colon = true;
            }
            char val = (char) buf[pos];
            if ((val >= 'A') && (val <= 'Z')) {
                val = (char) (val - LC_OFFSET);
            }
            header.name[readCount] = val;
            readCount++;
            pos++;
        }

        header.nameEnd = readCount - 1;

        // Reading the header value (which can be spanned over multiple lines)

        maxRead = header.value.length;
        readStart = pos;
        readCount = 0;

        int crPos = -2;

        boolean eol = false;
        boolean validLine = true;

        while (validLine) {

            boolean space = true;

            // Skipping spaces
            // Note : Only leading white spaces are removed. Trailing white
            // spaces are not.
            while (space) {
                // We're at the end of the internal buffer
                if (pos >= count) {
                    // Copying part (or all) of the internal buffer to the line
                    // buffer
                    int val = read();
                    if (val == -1)
                        throw new IOException
                            (sm.getString("requestStream.readline.error"));
                    pos = 0;
                    readStart = 0;
                }
                if ((buf[pos] == SP) || (buf[pos] == HT)) {
                    pos++;
                } else {
                    space = false;
                }
            }

            while (!eol) {
                // if the buffer is full, extend it
                if (readCount >= maxRead) {
                    if ((2 * maxRead) <= HttpHeader.MAX_VALUE_SIZE) {
                        char[] newBuffer = new char[2 * maxRead];
                        System.arraycopy(header.value, 0, newBuffer, 0,
                                         maxRead);
                        header.value = newBuffer;
                        maxRead = header.value.length;
                    } else {
                        throw new IOException
                            (sm.getString("requestStream.readline.toolong"));
                    }
                }
                // We're at the end of the internal buffer
                if (pos >= count) {
                    // Copying part (or all) of the internal buffer to the line
                    // buffer
                    int val = read();
                    if (val == -1)
                        throw new IOException
                            (sm.getString("requestStream.readline.error"));
                    pos = 0;
                    readStart = 0;
                }
                if (buf[pos] == CR) {
                } else if (buf[pos] == LF) {
                    eol = true;
                } else {
                    // FIXME : Check if binary conversion is working fine
                    int ch = buf[pos] & 0xff;
                    header.value[readCount] = (char) ch;
                    readCount++;
                }
                pos++;
            }

            int nextChr = read();

            if ((nextChr != SP) && (nextChr != HT)) {
                pos--;
                validLine = false;
            } else {
                eol = false;
                // if the buffer is full, extend it
                if (readCount >= maxRead) {
                    if ((2 * maxRead) <= HttpHeader.MAX_VALUE_SIZE) {
                        char[] newBuffer = new char[2 * maxRead];
                        System.arraycopy(header.value, 0, newBuffer, 0,
                                         maxRead);
                        header.value = newBuffer;
                        maxRead = header.value.length;
                    } else {
                        throw new IOException
                            (sm.getString("requestStream.readline.toolong"));
                    }
                }
                header.value[readCount] = ' ';
                readCount++;
            }

        }

        header.valueEnd = readCount;

    }


    /**
     * Read byte.
     */
    public int read()
        throws IOException {
        if (pos >= count) {
            fill();
            if (pos >= count)
                return -1;
        }
        return buf[pos++] & 0xff;
    }


    /**
     *
     */
    /*
    public int read(byte b[], int off, int len)
        throws IOException {

    }
    */


    /**
     *
     */
    /*
    public long skip(long n)
        throws IOException {

    }
    */


    /**
     * Returns the number of bytes that can be read from this input
     * stream without blocking.
     */
    public int available()
        throws IOException {
        return (count - pos) + is.available();
    }


    /**
     * Close the input stream.
     */
    public void close()
        throws IOException {
        if (is == null)
            return;
        is.close();
        is = null;
        buf = null;
    }


    // ------------------------------------------------------ Protected Methods


    /**
     * Fill the internal buffer using data from the undelying input stream.
     */
    protected void fill()
        throws IOException {
        pos = 0;
        count = 0;
        int nRead = is.read(buf, 0, buf.length);
        if (nRead > 0) {
            count = nRead;
        }
    }


}

 

下面是连接器HttpConnector的run方法

public void run()
	{
		ServerSocket serverSocket = null;
		int port = 8080;
		try
		{
			serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));
		} catch (IOException e)
		{
			e.printStackTrace();
			System.exit(1);
		}
		while (!stopped)
		{
			// Accept the next incoming connection from the server socket
			Socket socket = null;
			try
			{
				socket = serverSocket.accept();
			} catch (Exception e)
			{
				continue;
			}
			// Hand this socket off to an HttpProcessor
			HttpProcessor processor = new HttpProcessor(this);
			processor.process(socket);
		}
	}

下面是HttpProcessor类的process方法    与第二章的架构不同的是,创建Request和Response以及解析工作都放到了HttpProcessor当中,而不是在HttpServer当中,在这个模式当中仅仅向HttpProcessor当中传入Socket对象,输入流的处理防盗了HttpProcessor当中

 

public void process(Socket socket)
	{
          SocketInputStream input = null; OutputStream output = null; try {
              //创建SocketInputStream对象 input = new SocketInputStream(socket.getInputStream(), 2048); output = socket.getOutputStream(); // create HttpRequest object and parse request = new HttpRequest(input); // create HttpResponse object response = new HttpResponse(output); response.setRequest(request); response.setHeader("Server", "Pyrmont Servlet Container"); parseRequest(input, output); parseHeaders(input); // check if this is a request for a servlet or a static resource // a request for a servlet begins with "/servlet/" if (request.getRequestURI().startsWith("/servlet/")) { ServletProcessor processor = new ServletProcessor(); processor.process(request, response); } else { StaticResourceProcessor processor = new StaticResourceProcessor(); processor.process(request, response); } // Close the socket socket.close(); // no shutdown for this application } catch (Exception e) { e.printStackTrace(); } }

  

 

Constants.java

package ex03.pyrmont.connector.http;

import java.io.File;

public final class Constants
{
	public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "webroot";
	public static final String Package = "ex03.pyrmont.connector.http";
	public static final int DEFAULT_CONNECTION_TIMEOUT = 60000;
	public static final int PROCESSOR_IDLE = 0;
	public static final int PROCESSOR_ACTIVE = 1;
}

 

package org.apache.catalina.util;

import java.net.URLClassLoader;
import java.text.MessageFormat;
import java.util.Hashtable;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class StringManager
{
  private ResourceBundle bundle;
  private static Log log = LogFactory.getLog(StringManager.class);

  private static Hashtable managers = new Hashtable();

  private StringManager(String packageName)
  {
    String bundleName = packageName + ".LocalStrings";
    try {
      this.bundle = ResourceBundle.getBundle(bundleName);
      return;
    }
    catch (MissingResourceException ex) {
      ClassLoader cl = Thread.currentThread().getContextClassLoader();
      if (cl != null)
        try {
          this.bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault(), cl);
          return;
        }
        catch (MissingResourceException ex2) {
        }
      if (cl == null) {
        cl = getClass().getClassLoader();
      }
      if (log.isDebugEnabled()) {
        log.debug("Can't find resource " + bundleName + " " + cl);
      }
      if (((cl instanceof URLClassLoader)) && 
        (log.isDebugEnabled()))
        log.debug(((URLClassLoader)cl).getURLs());
    }
  }

  public String getString(String key)
  {
    return MessageFormat.format(getStringInternal(key), (Object[])null);
  }

  protected String getStringInternal(String key)
  {
    if (key == null) {
      String msg = "key is null";

      throw new NullPointerException(msg);
    }

    String str = null;

    if (this.bundle == null)
      return key;
    try {
      str = this.bundle.getString(key);
    } catch (MissingResourceException mre) {
      str = "Cannot find message associated with key '" + key + "'";
    }

    return str;
  }

  public String getString(String key, Object[] args)
  {
    String iString = null;
    String value = getStringInternal(key);
    try
    {
      Object[] nonNullArgs = args;
      for (int i = 0; i < args.length; i++) {
        if (args[i] == null) {
          if (nonNullArgs == args) nonNullArgs = (Object[])args.clone();
          nonNullArgs[i] = "null";
        }
      }

      iString = MessageFormat.format(value, nonNullArgs);
    } catch (IllegalArgumentException iae) {
      StringBuffer buf = new StringBuffer();
      buf.append(value);
      for (int i = 0; i < args.length; i++) {
        buf.append(" arg[" + i + "]=" + args[i]);
      }
      iString = buf.toString();
    }
    return iString;
  }

  public String getString(String key, Object arg)
  {
    Object[] args = { arg };
    return getString(key, args);
  }

  public String getString(String key, Object arg1, Object arg2)
  {
    Object[] args = { arg1, arg2 };
    return getString(key, args);
  }

  public String getString(String key, Object arg1, Object arg2, Object arg3)
  {
    Object[] args = { arg1, arg2, arg3 };
    return getString(key, args);
  }

  public String getString(String key, Object arg1, Object arg2, Object arg3, Object arg4)
  {
    Object[] args = { arg1, arg2, arg3, arg4 };
    return getString(key, args);
  }

  public static synchronized StringManager getManager(String packageName)
  {
    StringManager mgr = (StringManager)managers.get(packageName);

    if (mgr == null) {
      mgr = new StringManager(packageName);
      managers.put(packageName, mgr);
    }
    return mgr;
  }
}

  

里面用到了Tomcat5中提供的StringManager类

(貌似在Tomcat7当中没有这个类了,或者更改了包的位置,目前不得而知)

作用:像Tomcat这样的大型程序必须小心的仔细处理错误消息。在Tomcat当中,错误消息对于系统管理员和Servlet程序员来说都是非常有用的。

例如:系统管理员可以很容易的根据Tomcat的错误日志消息定位到异常发生的位置。而对于servlet程序员来说,在抛出的每个javax.servlet.ServletException异常中,Tomcat都会发送一条特姝的错误消息。

这样,程序员就可以知道servlet程序到底哪里出错了

 

Tomcat处理错误消息的方法是将错误消息存储在一个properties文件中,便于读取和编辑,但是Tomcat中有几百个类。

若是将所有类使用的错误消息都存储在一个大的properties属性文件当中,

 

 

使用到的工具类HttpRequestLine类  

 

package ex03.pyrmont.connector.http;

/**
 * HTTP request line enum type.
 * 
 * @author Remy Maucherat
 * @version $Revision: 1.6 $ $Date: 2002/03/18 07:15:40 $
 * @deprecated
 */

final class HttpRequestLine
{

	// -------------------------------------------------------------- Constants

	public static final int INITIAL_METHOD_SIZE = 8;
	public static final int INITIAL_URI_SIZE = 64;
	public static final int INITIAL_PROTOCOL_SIZE = 8;
	public static final int MAX_METHOD_SIZE = 1024;
	public static final int MAX_URI_SIZE = 32768;
	public static final int MAX_PROTOCOL_SIZE = 1024;

	// ----------------------------------------------------------- Constructors

	public HttpRequestLine()
	{

		this(new char[INITIAL_METHOD_SIZE], 0, new char[INITIAL_URI_SIZE], 0, new char[INITIAL_PROTOCOL_SIZE], 0);

	}

	public HttpRequestLine(char[] method, int methodEnd, char[] uri, int uriEnd, char[] protocol, int protocolEnd)
	{

		this.method = method;
		this.methodEnd = methodEnd;
		this.uri = uri;
		this.uriEnd = uriEnd;
		this.protocol = protocol;
		this.protocolEnd = protocolEnd;

	}

	// ----------------------------------------------------- Instance Variables

	public char[] method;
	public int methodEnd;
	public char[] uri;
	public int uriEnd;
	public char[] protocol;
	public int protocolEnd;

	// ------------------------------------------------------------- Properties

	// --------------------------------------------------------- Public Methods

	/**
	 * Release all object references, and initialize instance variables, in
	 * preparation for reuse of this object.
	 */
	public void recycle()
	{

		methodEnd = 0;
		uriEnd = 0;
		protocolEnd = 0;

	}

	/**
	 * Test if the uri includes the given char array.
	 */
	public int indexOf(char[] buf)
	{
		return indexOf(buf, buf.length);
	}

	/**
	 * Test if the value of the header includes the given char array.
	 */
	public int indexOf(char[] buf, int end)
	{
		char firstChar = buf[0];
		int pos = 0;
		while (pos < uriEnd)
		{
			pos = indexOf(firstChar, pos);
			if (pos == -1)
				return -1;
			if ((uriEnd - pos) < end)
				return -1;
			for (int i = 0; i < end; i++)
			{
				if (uri[i + pos] != buf[i])
					break;
				if (i == (end - 1))
					return pos;
			}
			pos++;
		}
		return -1;
	}

	/**
	 * Test if the value of the header includes the given string.
	 */
	public int indexOf(String str)
	{
		return indexOf(str.toCharArray(), str.length());
	}

	/**
	 * Returns the index of a character in the value.
	 */
	public int indexOf(char c, int start)
	{
		for (int i = start; i < uriEnd; i++)
		{
			if (uri[i] == c)
				return i;
		}
		return -1;
	}

	// --------------------------------------------------------- Object Methods

	public int hashCode()
	{
		// FIXME
		return 0;
	}

	public boolean equals(Object obj)
	{
		return false;
	}

}

 

 

 

//HttpProcessor.java  对SocketInputStream类的使用   这里还是没有使用多线程,估计要到第4章才会介绍使用多线程吧,此时每次只能处理一个请求,其余请求只能排队。

 

package ex03.pyrmont.connector.http;

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;

import org.apache.catalina.util.RequestUtil;
import org.apache.catalina.util.StringManager;

import ex03.pyrmont.ServletProcessor;
import ex03.pyrmont.StaticResourceProcessor;

/* this class used to be called HttpServer */
public class HttpProcessor
{
        //将HttpConnector传递进来进行回调或者说绑定
	public HttpProcessor(HttpConnector connector)
	{
		this.connector = connector;
	}

	/**
	 * The HttpConnector with which this processor is associated.
	 */
	private HttpConnector connector = null;
	private HttpRequest request;
	private HttpRequestLine requestLine = new HttpRequestLine();
	private HttpResponse response;

	protected String method = null;
	protected String queryString = null;

	/**
	 * The string manager for this package.
	 */
	protected StringManager sm = StringManager.getManager("ex03.pyrmont.connector.http");

	public void process(Socket socket)
	{
		SocketInputStream input = null;
		OutputStream output = null;
		try
		{
//获得输入流 input = new SocketInputStream(socket.getInputStream(), 2048); //获得输出流
output = socket.getOutputStream(); // create HttpRequest object and parse request = new HttpRequest(input); // create HttpResponse object response = new HttpResponse(output); response.setRequest(request); //为响应报文设置响应头Server 表明Server的名字 比如百度的就是bws baidu web server response.setHeader("Server", "Pyrmont Servlet Container"); parseRequest(input, output); parseHeaders(input); // check if this is a request for a servlet or a static resource // a request for a servlet begins with "/servlet/" if (request.getRequestURI().startsWith("/servlet/")) { ServletProcessor processor = new ServletProcessor(); processor.process(request, response); } else { StaticResourceProcessor processor = new StaticResourceProcessor(); processor.process(request, response); } // Close the socket socket.close(); // no shutdown for this application } catch (Exception e) { e.printStackTrace(); } } /** * This method is the simplified version of the similar method in * org.apache.catalina.connector.http.HttpProcessor. However, this method * only parses some "easy" headers, such as "cookie", "content-length", and * "content-type", and ignore other headers. * * @param input * The input stream connected to our socket * * @exception IOException * if an input/output error occurs * @exception ServletException * if a parsing error occurs */ private void parseHeaders(SocketInputStream input) throws IOException, ServletException { while (true) { HttpHeader header = new HttpHeader(); ; // Read the next header 调用SocketInputStream当中的方法初始化HttpHeader() input.readHeader(header); if (header.nameEnd == 0) { if (header.valueEnd == 0) { return; } else { throw new ServletException(sm.getString("httpProcessor.parseHeaders.colon")); } } String name = new String(header.name, 0, header.nameEnd); String value = new String(header.value, 0, header.valueEnd); request.addHeader(name, value); // do something for some headers, ignore others. if (name.equals("cookie")) { Cookie cookies[] = RequestUtil.parseCookieHeader(value); for (int i = 0; i < cookies.length; i++) { if (cookies[i].getName().equals("jsessionid")) { // Override anything requested in the URL if (!request.isRequestedSessionIdFromCookie()) { // Accept only the first session id cookie request.setRequestedSessionId(cookies[i].getValue()); request.setRequestedSessionCookie(true); request.setRequestedSessionURL(false); } } request.addCookie(cookies[i]); } } else if (name.equals("content-length")) { int n = -1; try { n = Integer.parseInt(value); } catch (Exception e) { throw new ServletException(sm.getString("httpProcessor.parseHeaders.contentLength")); } request.setContentLength(n); } else if (name.equals("content-type")) { request.setContentType(value); } } // end while } private void parseRequest(SocketInputStream input, OutputStream output) throws IOException, ServletException { // Parse the incoming request line input.readRequestLine(requestLine); String method = new String(requestLine.method, 0, requestLine.methodEnd); String uri = null; String protocol = new String(requestLine.protocol, 0, requestLine.protocolEnd); // Validate the incoming request line if (method.length() < 1) { throw new ServletException("Missing HTTP request method"); } else if (requestLine.uriEnd < 1) { throw new ServletException("Missing HTTP request URI"); } // Parse any query parameters out of the request URI int question = requestLine.indexOf("?"); if (question >= 0) { request.setQueryString(new String(requestLine.uri, question + 1, requestLine.uriEnd - question - 1)); uri = new String(requestLine.uri, 0, question); } else { request.setQueryString(null); uri = new String(requestLine.uri, 0, requestLine.uriEnd); } // Checking for an absolute URI (with the HTTP protocol) if (!uri.startsWith("/")) { int pos = uri.indexOf("://"); // Parsing out protocol and host name if (pos != -1) { pos = uri.indexOf('/', pos + 3); if (pos == -1) { uri = ""; } else { uri = uri.substring(pos); } } } // Parse any requested session ID out of the request URI String match = ";jsessionid="; int semicolon = uri.indexOf(match); if (semicolon >= 0) { String rest = uri.substring(semicolon + match.length()); int semicolon2 = rest.indexOf(';'); if (semicolon2 >= 0) { request.setRequestedSessionId(rest.substring(0, semicolon2)); rest = rest.substring(semicolon2); } else { request.setRequestedSessionId(rest); rest = ""; } request.setRequestedSessionURL(true); uri = uri.substring(0, semicolon) + rest; } else { request.setRequestedSessionId(null); request.setRequestedSessionURL(false); } // Normalize URI (using String operations at the moment) String normalizedUri = normalize(uri); // Set the corresponding request properties ((HttpRequest) request).setMethod(method); request.setProtocol(protocol); if (normalizedUri != null) { ((HttpRequest) request).setRequestURI(normalizedUri); } else { ((HttpRequest) request).setRequestURI(uri); } if (normalizedUri == null) { throw new ServletException("Invalid URI: " + uri + "'"); } } /** * Return a context-relative path, beginning with a "/", that represents the * canonical version of the specified path after ".." and "." elements are * resolved out. If the specified path attempts to go outside the boundaries * of the current context (i.e. too many ".." path elements are present), * return <code>null</code> instead. * * @param path * Path to be normalized */ protected String normalize(String path) { if (path == null) return null; // Create a place for the normalized path String normalized = path; // Normalize "/%7E" and "/%7e" at the beginning to "/~" if (normalized.startsWith("/%7E") || normalized.startsWith("/%7e")) normalized = "/~" + normalized.substring(4); // Prevent encoding '%', '/', '.' and '\', which are special reserved // characters if ((normalized.indexOf("%25") >= 0) || (normalized.indexOf("%2F") >= 0) || (normalized.indexOf("%2E") >= 0) || (normalized.indexOf("%5C") >= 0) || (normalized.indexOf("%2f") >= 0) || (normalized.indexOf("%2e") >= 0) || (normalized.indexOf("%5c") >= 0)) { return null; } if (normalized.equals("/.")) return "/"; // Normalize the slashes and add leading slash if necessary if (normalized.indexOf('\\') >= 0) normalized = normalized.replace('\\', '/'); if (!normalized.startsWith("/")) normalized = "/" + normalized; // Resolve occurrences of "//" in the normalized path while (true) { int index = normalized.indexOf("//"); if (index < 0) break; normalized = normalized.substring(0, index) + normalized.substring(index + 1); } // Resolve occurrences of "/./" in the normalized path while (true) { int index = normalized.indexOf("/./"); if (index < 0) break; normalized = normalized.substring(0, index) + normalized.substring(index + 2); } // Resolve occurrences of "/../" in the normalized path while (true) { int index = normalized.indexOf("/../"); if (index < 0) break; if (index == 0) return (null); // Trying to go outside our context int index2 = normalized.lastIndexOf('/', index - 1); normalized = normalized.substring(0, index2) + normalized.substring(index + 3); } // Declare occurrences of "/..." (three or more dots) to be invalid // (on some Windows platforms this walks the directory tree!!!) if (normalized.indexOf("/...") >= 0) return (null); // Return the normalized path that we have completed return (normalized); } }

  

 

//在HttpProcessor当中parseRequest的时候初始化HttpHeader对象

package ex03.pyrmont.connector.http;

/**
 * HTTP header enum type.
 * 
 * @author Remy Maucherat
 * @version $Revision: 1.4 $ $Date: 2002/03/18 07:15:40 $
 * @deprecated
 */

final class HttpHeader
{

	// -------------------------------------------------------------- Constants

	public static final int INITIAL_NAME_SIZE = 32;
	public static final int INITIAL_VALUE_SIZE = 64;
	public static final int MAX_NAME_SIZE = 128;
	public static final int MAX_VALUE_SIZE = 4096;

	// ----------------------------------------------------------- Constructors

	public HttpHeader()
	{

		this(new char[INITIAL_NAME_SIZE], 0, new char[INITIAL_VALUE_SIZE], 0);

	}

	public HttpHeader(char[] name, int nameEnd, char[] value, int valueEnd)
	{

		this.name = name;
		this.nameEnd = nameEnd;
		this.value = value;
		this.valueEnd = valueEnd;

	}

	public HttpHeader(String name, String value)
	{

		this.name = name.toLowerCase().toCharArray();
		this.nameEnd = name.length();
		this.value = value.toCharArray();
		this.valueEnd = value.length();

	}

	// ----------------------------------------------------- Instance Variables

	public char[] name;
	public int nameEnd;
	public char[] value;
	public int valueEnd;
	protected int hashCode = 0;

	// ------------------------------------------------------------- Properties

	// --------------------------------------------------------- Public Methods

	/**
	 * Release all object references, and initialize instance variables, in
	 * preparation for reuse of this object.
	 */
	public void recycle()
	{

		nameEnd = 0;
		valueEnd = 0;
		hashCode = 0;

	}

	/**
	 * Test if the name of the header is equal to the given char array. All the
	 * characters must already be lower case.
	 */
	public boolean equals(char[] buf)
	{
		return equals(buf, buf.length);
	}

	/**
	 * Test if the name of the header is equal to the given char array. All the
	 * characters must already be lower case.
	 */
	public boolean equals(char[] buf, int end)
	{
		if (end != nameEnd)
			return false;
		for (int i = 0; i < end; i++)
		{
			if (buf[i] != name[i])
				return false;
		}
		return true;
	}

	/**
	 * Test if the name of the header is equal to the given string. The String
	 * given must be made of lower case characters.
	 */
	public boolean equals(String str)
	{
		return equals(str.toCharArray(), str.length());
	}

	/**
	 * Test if the value of the header is equal to the given char array.
	 */
	public boolean valueEquals(char[] buf)
	{
		return valueEquals(buf, buf.length);
	}

	/**
	 * Test if the value of the header is equal to the given char array.
	 */
	public boolean valueEquals(char[] buf, int end)
	{
		if (end != valueEnd)
			return false;
		for (int i = 0; i < end; i++)
		{
			if (buf[i] != value[i])
				return false;
		}
		return true;
	}

	/**
	 * Test if the value of the header is equal to the given string.
	 */
	public boolean valueEquals(String str)
	{
		return valueEquals(str.toCharArray(), str.length());
	}

	/**
	 * Test if the value of the header includes the given char array.
	 */
	public boolean valueIncludes(char[] buf)
	{
		return valueIncludes(buf, buf.length);
	}

	/**
	 * Test if the value of the header includes the given char array.
	 */
	public boolean valueIncludes(char[] buf, int end)
	{
		char firstChar = buf[0];
		int pos = 0;
		while (pos < valueEnd)
		{
			pos = valueIndexOf(firstChar, pos);
			if (pos == -1)
				return false;
			if ((valueEnd - pos) < end)
				return false;
			for (int i = 0; i < end; i++)
			{
				if (value[i + pos] != buf[i])
					break;
				if (i == (end - 1))
					return true;
			}
			pos++;
		}
		return false;
	}

	/**
	 * Test if the value of the header includes the given string.
	 */
	public boolean valueIncludes(String str)
	{
		return valueIncludes(str.toCharArray(), str.length());
	}

	/**
	 * Returns the index of a character in the value.
	 */
	public int valueIndexOf(char c, int start)
	{
		for (int i = start; i < valueEnd; i++)
		{
			if (value[i] == c)
				return i;
		}
		return -1;
	}

	/**
	 * Test if the name of the header is equal to the given header. All the
	 * characters in the name must already be lower case.
	 */
	public boolean equals(HttpHeader header)
	{
		return (equals(header.name, header.nameEnd));
	}

	/**
	 * Test if the name and value of the header is equal to the given header.
	 * All the characters in the name must already be lower case.
	 */
	public boolean headerEquals(HttpHeader header)
	{
		return (equals(header.name, header.nameEnd)) && (valueEquals(header.value, header.valueEnd));
	}

	// --------------------------------------------------------- Object Methods

	/**
	 * Return hash code. The hash code of the HttpHeader object is the same as
	 * returned by new String(name, 0, nameEnd).hashCode().
	 */
	public int hashCode()
	{
		int h = hashCode;
		if (h == 0)
		{
			int off = 0;
			char val[] = name;
			int len = nameEnd;
			for (int i = 0; i < len; i++)
				h = 31 * h + val[off++];
			hashCode = h;
		}
		return h;
	}

	public boolean equals(Object obj)
	{
		if (obj instanceof String)
		{
			return equals(((String) obj).toLowerCase());
		} else if (obj instanceof HttpHeader)
		{
			return equals((HttpHeader) obj);
		}
		return false;
	}

}

  

推荐阅读