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

  

InputStream的封装类的更多相关文章

  1. 未关闭InputStream 引起的血案

    下面的方法是从aws s3 读取文件对象下载到本地 public int downloadFile(HttpServletResponse httpResponse, String storePath ...

  2. c#生成静态html文件,封装类

    由于这段时间比较轻松,于是想到很多的企业网站,新闻网站需要将页面静态化,于是写了个封装类来实现静态文件的生成,思路比较简单,但未完善,网友可根据自己的思路将此类扩展,运用了简单工厂模式(本来刚开始看设 ...

  3. apache.commons.io.IOUtils: 一个很方便的IO工具库(比如InputStream转String)

    转换InputStream到String, 比如 //引入apache的io包 import org.apache.commons.io.IOUtils; ... ...String str = IO ...

  4. Android InputStream接收 字符串乱码 问题

    各个国家和地区所制定的不同 ANSI 编码标准中,都只规定了各自语言所需的“字符”.比如:汉字标准(GB2312)中没有规定韩国语字符怎样存储.这些 ANSI 编码标准所规定的内容包含两层含义:1. ...

  5. InputStream、InputStreamReader和Reader的关系

    InputStream:得到的是字节输入流,InputStream.read("filename")之后,得到字节流 Reader:读取的是字符流 InputStreamReade ...

  6. 自动创建WIN32下多级子目录的C++封装类

            这是 WIN32 自动创建多级子目录的 C++ 封装类,用法简单.         封装没有采用类的静态函数方式,而是在构造函数里面直接完成工作.没什么具体的原因,只是当时做成这样了, ...

  7. StackExchange.Redis 访问封装类

    最近需要在C#中使用Redis,在Redis的官网找到了ServiceStack.Redis,最后在测试的时候发现这是个坑,4.0已上已经收费,后面只好找到3系列的最终版本,最后测试发现还是有BUG或 ...

  8. StackExchange.Redis通用封装类分享(转)

    阅读目录 ConnectionMultiplexer 封装 RedisHelper 通用操作类封 String类型的封装 List类型的封装 Hash类型的封装 SortedSet 类型的封装 key ...

  9. Reader与InputStream两个类中的read()的区别

    InputStream类的read()方法是从流里面取出一个字节,他的函数原型是 int read(); ,Reader类的read()方法则是从流里面取出一个字符(一个char),他的函数原型也是  ...

随机推荐

  1. CreateEvent的使用方法

     CreateEvent的使用方法收藏 新一篇: PreCreateWindow的作用和用法 | 旧一篇: VC中_T()的作用 function StorePage(){d=document;t=d ...

  2. 仿path菜单button的实现

    path刚出来时.其菜单button也算是让大多数人感到了惊艳,如今看来事实上是非常easy的就是动画的结合. watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQ ...

  3. [rxjs] Shares a single subscription -- publish()

    If have an observable and you subscribe it twice, those tow subscritions have no connection. console ...

  4. LINUX 文件系统JBD ----深入理解Fsync

    http://www.cnblogs.com/hustcat/p/3283955.html http://www.cnblogs.com/zengkefu/p/5639200.html http:// ...

  5. FileZilla命令行实现文件上传以及CreateProcess实现静默调用

    应用需求:         用户在选择渲染作业时面临两种情况:一是选择用户远程存储上的文件:二是选择本地文件系统中的文件进行渲染.由于渲染任务是在远程主机上进行的,实际进行渲染时源文件也是在ftp目录 ...

  6. iOS UIKit:CollectionView之布局(2)

    Collection view使用UICollectionViewFlowLayout对象来管理section中的cell,该对象是一种流布局方式,即在collection view中的section ...

  7. Grant-Permission.ps1

    Grant-Permission.ps1 Download the EXE version of SetACL 3.0.6 for 32-bit and 64-bit Windows. Put set ...

  8. Nginx性能统计模块http_stub_status_module使用

    1.进入nginx源码目录,重新配置编译参数 ./configure --prefix=/usr/local/nginx/ --with-http_stub_status_module 2.重新编译安 ...

  9. 文件上传利器SWFUpload使用指南

    这里就不再介绍什么是SWFUpload啦,简单为大家写一个简单关于SWFUpload的Demo. 1.把SWFUpload 相关的文件引用进来 2.创建upload.aspx页面(页面名称可自定义), ...

  10. 通过C#去调用C++编写的DLL

    这个问题缠了我2个小时才弄出来,其实很简单.当对方提供一个dll给你使用时,你需要去了解这个dll 是由什么语言写的,怎么编译的,看它的编译类型.这样即使在没有头绪时,你可以先尝使用一些比较热门的编译 ...