一.运行机制
1. 上一篇中我们简单的实现了服务器的运行机制,但是,分工可以进一步的细化,上一篇中HTTPServer起到两个作用:1. 连接,2. 处理请求;这里我们将其拆分成两个模块:1.连接器,2.处理器
2. 上一篇中,对请求的获取和解析都是在Request中完成的,这里将其拆分成两个模块:
1.获取工具2.解析工具
3. 另外将独立出处理错误消息的模块,用于处理程序产生的错误信息。
4. 增加一个启动模块,作为程序的入口。
这样连接器就成为一个独立的模块,这样就大大减轻请求和响应程序的负载,从而提高程序的效率,提高程序的模块化程度;连接器所完成的三个重要功能:1.连接处理 2解析 3产生Request和Response对象
二.实战代码
该应用程序所包含的模块:
1.Model模块:将HTTP请求分别抽象成三个类:1.HTTPRequestLine(请求行)2.HTTPHeader(请求头)3.HttpRequestParameters(请求实体)
2.inter模块:Servlet实现统一的标准:1.Servlet接口 2.ServeltRequest接口 3.ServletResponse接口
3.Util模块:工具类模块:1.Contants工具类 2.Parse工具类 3.StringManager工具类 4.SocketInputStream工具类
4.Handeler模块:1.RequestFacade2.ResponseFacade类 3.ServletProcessor4.StaticRescourseProcessor
1. HttpConnetor
package Connector;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
/**
* 连接器
* @author JayKing
*
*/
public class HttpConnector implements Runnable {
boolean stopped=false;
private String scheme = "http";
public String getScheme() {
return scheme;
}
@Override
public void run() {
ServerSocket serversocket = null;
int port = 8080;
try {
serversocket = new ServerSocket(port, 100, InetAddress.getByName("127.0.0.1"));
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
while (!stopped) {
Socket socket = null;
try {
socket = serversocket.accept();
} catch (IOException e) {
continue;
}
HttpProcessor processor = new HttpProcessor(this);//频繁创建对象 通过连接池来解决
processor.process(socket);
}
}
public void start() {
Thread thread = new Thread(this);
thread.start();
}
}
2. HttpProcessor
package Connector;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import Handler.ServletProcessor;
import Handler.StaticResourceProcessor;
import Util.Parse;
import Util.SocketInputStream;
/**
* 处理器
* @author JayKing
*
*/
public class HttpProcessor {
private HttpConnector httpConnector;
private HttpRequest request;
private HttpResponse response;
public HttpProcessor(HttpConnector httpConnector) {
this.httpConnector = httpConnector;
}
/**
* 接受请求 实现分流
*
* @param socket
*/
public void process(Socket socket) {
SocketInputStream input = null;
OutputStream output = null;
try {
input = new SocketInputStream(socket.getInputStream(), 2048);
output = socket.getOutputStream();
request = new HttpRequest(input);
response = new HttpResponse(output);
response.setRequest(request);
response.setHeader("Server", "Pyrmont Servlet container");
Parse.parseRequestLine(request, input, output);
Parse.parseHeaders(request, input);
if (request.getRequestURI().startsWith("/servlet/")) {
ServletProcessor processor = new ServletProcessor();
processor.process(request, response);
} else {
StaticResourceProcessor processor = new StaticResourceProcessor();
processor.process(request, response);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
3. HttpResponse
package Connector;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import Inter.ServletResponse;
/**
* 响应
* @author JayKing
*
*/
public class HttpResponse implements ServletResponse {
protected HttpRequest request;
protected String contentType;
protected HashMap<String, ArrayList<String>> headers = new HashMap<String, ArrayList<String>>();
protected boolean committed = false;
private int contentLength = -1;
public OutputStream output;
public HttpResponse(OutputStream output) {
this.output = output;
}
public void setRequest(HttpRequest request) {
this.request = request;
}
public void setHeader(String name, String value) {
if (isCommitted())
return;
ArrayList<String> values = new ArrayList<String>();
values.add(value);
synchronized (headers) {
headers.put(name, values);
}
String match = name.toLowerCase();
if (match.equals("content-length")) {
try {
contentLength = Integer.parseInt(value);
} catch (NumberFormatException e) {
e.printStackTrace();
}
if (contentLength >= 0)
setContentLength(contentLength);
} else if (match.equals("content-type")) {
setContentType(value);
}
}
private void setContentType(String value) {
if (isCommitted())
return;
this.contentType = value;
}
private void setContentLength(int length) {
if (isCommitted())
return;
this.contentLength = length;
}
public boolean isCommitted() {
return (committed);
}
}
4. HttpRequest
package Connector;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import Inter.ServletRequest;
import Model.Cookie;
import Model.HttpRequestParameters;
import Util.SocketInputStream;
/**
* 请求
* @author JayKing
*
*/
public class HttpRequest implements ServletRequest {
private InputStream input;
private String requestURI;
private String method;
private String protocol;
protected ArrayList<Cookie> cookies = new ArrayList<Cookie>();
public HashMap<String, ArrayList<String>> headers = new HashMap<String, ArrayList<String>>();
public boolean parsed;
public HttpRequestParameters parameters;
public boolean isRequestedSessionIdFromCookie() {
return false;
}
public void setRequestedSessionCookie(boolean b) {
}
public void setRequestedSessionURL(boolean b) {
}
public void setRequestedSessionId(String password) {
}
public void setContentLength(int n) {
}
public void setContentType(String value) {
}
public void setQueryString(String string) {
}
public String getMethod() {
return method;
}
public String getProtocol() {
return protocol;
}
public HttpRequest(SocketInputStream input) {
this.input = input;
}
public String getRequestURI() {
return requestURI;
}
public InputStream getInput() {
return input;
}
public void setInput(InputStream input) {
this.input = input;
}
public void setMethod(String method) {
this.method = method;
}
public void setProtocol(String protocol) {
this.protocol = protocol;
}
public void setRequestURI(String normalizedUri) {
this.requestURI = normalizedUri;
}
public void addCookie(Cookie cookie) {
synchronized (cookies) {
cookies.add(cookie);
}
}
public void addHeader(String name, String value) {
name = name.toLowerCase();
synchronized (headers) {
ArrayList<String> values = (ArrayList<String>) headers.get(name);
if (values == null) {
values = new ArrayList<String>();
headers.put(name, values);
}
values.add(value);
}
}
public String getCharacterEncoding() {
return null;
}
public String getQueryString() {
return null;
}
public String getContentType() {
return null;
}
public int getContentLength() {
return 0;
}
}
5. RequestFacade
package Handler;
import Connector.HttpRequest;
import Inter.ServletRequest;
import Inter.ServletResponse;
public class RequestFacade implements ServletRequest {
private ServletRequest resquest;
public RequestFacade(HttpRequest request) {
this.resquest = resquest;
}
}
6. ResponseFacade
package Handler;
import Connector.HttpResponse;
import Inter.ServletResponse;
public class ResponseFacade implements ServletResponse{
private ServletResponse response;
public ResponseFacade(HttpResponse response) {
this.response = response;
}
}
7. ServletProcessor
package Handler;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandler;
import java.util.HashMap;
import Connector.HttpRequest;
import Connector.HttpResponse;
import Inter.Servlet;
import Inter.ServletRequest;
import Inter.ServletResponse;
import Util.Contants;
public class ServletProcessor {
public void process(HttpRequest request, HttpResponse response) {
String uri = request.getRequestURI();
String ServletName = uri.substring(uri.lastIndexOf("/") + 1);
ClassLoader classloader = null;
Class myClass = null;
String repository = null;
URLClassLoader loader = null;
URL[] urls = new URL[1];
URLStreamHandler streamhandler = null;
File classPath = new File(Contants.WEB_ROOT);
try {
repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString();
urls[0] = new URL(null, repository, streamhandler);
loader = new URLClassLoader(urls);
myClass = loader.loadClass(ServletName);
} catch (MalformedURLException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Servlet servlet = null;
RequestFacade requestFacade = new RequestFacade(request);
ResponseFacade responseFacade = new ResponseFacade(response);
try {
servlet = (Servlet) myClass.newInstance();
servlet.service((ServletRequest) requestFacade, (ServletResponse) responseFacade);
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
8. StaticRescourceProcessor
package Handler;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import Connector.HttpRequest;
import Connector.HttpResponse;
import Util.Contants;
public class StaticResourceProcessor {
private static final int BUFFER_SIZE = 1024;
public void process(HttpRequest request, HttpResponse response) throws IOException {
byte[] bytes = new byte[BUFFER_SIZE];
FileInputStream fis = null;
try {
File file = new File(Contants.WEB_ROOT, request.getRequestURI());
if (file.exists()) {
fis = new FileInputStream(file);
int ch = fis.read(bytes, 0, BUFFER_SIZE);
while (ch != -1) {
response.output.write(bytes, 0, ch);
ch = fis.read(bytes, 0, BUFFER_SIZE);
}
}
} catch (FileNotFoundException e) {
response.output.write(Contants.errorMessage.getBytes());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (fis != null)
fis.close();
}
}
}
9. Servlet
package Inter;
public interface Servlet {
public void init();
public void service(ServletRequest servletrequest,ServletResponse servletresposne);
public void destory();
}
10. ServletRequest
package Inter;
public interface ServletRequest {
}
11. ServletResponse
package Inter;
public interface ServletResponse {
}
12. Cookie
package Model;
/**
* Cookie菜单
* @author JayKing
*
*/
public class Cookie {
public String name;
public String password;
public Cookie() {
}
public Cookie(String username, String password) {
this.name = username;
this.password = password;
}
public String getName() {
return name;
}
public void setName(String username) {
this.name = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
13. HttpHeader
package Model;
/**
* 请求头
*
* @author JayKing
*
*/
public class HttpHeader {
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;
public char[] name;
public int nameEnd;
public char[] value;
public int valueEnd;
protected int hashCode = 0;
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 void recycle() {
nameEnd = 0;
valueEnd = 0;
hashCode = 0;
}
}
14. HttpREquestLine
package Model;
/**
* 请求方法
*
* @author JayKing
*
*/
public class HttpRequestLine {
public static final int MAX_PROTOCOL_SIZE = 1024;
public static final int MAX_METHOD_SIZE = 1024;
public static final int MAX_URI_SIZE = 32768;
private static final int INITIAL_METHOD_SIZE = 1024;
private static final int INITIAL_URI_SIZE = 64;
private static final int INITIAL_PROTOCOL_SIZE = 8;
public char[] method;
public int methodEnd;
public char[] uri;
public int uriEnd;
public char[] protocol;
public int protocolEnd;
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;
}
public void recycle() {
methodEnd = 0;
uriEnd = 0;
protocolEnd = 0;
}
public int indexOf(char[] buf) {
return indexOf(buf, buf.length);
}
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;
}
public int indexOf(char c, int start) {
for (int i = start; i < uriEnd; i++) {
if (uri[i] == c)
return i;
}
return -1;
}
public int indexOf(String str) {
return indexOf(str.toCharArray(), str.length());
}
public char[] getMethod() {
return method;
}
public void setMethod(char[] method) {
this.method = method;
}
public int getMethodEnd() {
return methodEnd;
}
public void setMethodEnd(int methodEnd) {
this.methodEnd = methodEnd;
}
public char[] getUri() {
return uri;
}
public void setUri(char[] uri) {
this.uri = uri;
}
public int getUriEnd() {
return uriEnd;
}
public void setUriEnd(int uriEnd) {
this.uriEnd = uriEnd;
}
public char[] getProtocol() {
return protocol;
}
public void setProtocol(char[] protocol) {
this.protocol = protocol;
}
public int getProtocolEnd() {
return protocolEnd;
}
public void setProtocolEnd(int protocolEnd) {
this.protocolEnd = protocolEnd;
}
}
15. HttpRequestParameters
package Model;
import java.util.HashMap;
public class HttpRequestParameters extends HashMap {
private boolean locked = false;
public HttpRequestParameters() {
}
public void setLocked(boolean locked) {
this.locked = locked;
}
}
16. BootStarp
package startup;
import Connector.HttpConnector;
public class Bootstrap {
public static void main(String[] args) {
HttpConnector connector = new HttpConnector();
connector.start();
}
}
17. Contants
package Util;
import java.io.File;
/**
* 常量类
* @author JayKing
*
*/
public class Contants {
public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "webroot";
public static final String Package = "JayKing.Connector";
public static final String Config = System.getProperty("user.dir") + File.separator + "config";
public static final String errorMessage = "HTTP/1.1 404 File Not Found\r\n" + "Content-Type: text/html\r\n"
+ "Content-Length: 23\r\n" + "\r\n" + "<h1>File Not Found</h1>";
public static final int DEFAULT_CONNECTION_TIMEOUT = 60000;
public static final int PROCESSOR_IDLE = 0;
public static final int PROCESSOR_ACTIVE = 1;
}
18. Parse
package Util;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import Connector.HttpRequest;
import Model.Cookie;
import Model.HttpHeader;
import Model.HttpRequestLine;
import Model.HttpRequestParameters;
/**
* 解析类
*
* @author JayKing
*
*/
public class Parse {
private static HttpRequestLine requestLine = new HttpRequestLine();
private static HttpHeader httpheader = new HttpHeader();
private static HttpRequestParameters results = new HttpRequestParameters();
protected static StringManager sm = StringManager.getManager("JayKing.connector");
/**
* 解析请求头
*
* @param input
* @throws IOException
*/
public static void parseHeaders(HttpRequest request, SocketInputStream input) throws IOException {
while (true) {
input.readHeader(httpheader);
if (httpheader.nameEnd == 0) {
if (httpheader.valueEnd == 0) {
return;
} else {
System.out.println(sm.getString("httpProcessor.parseHeaders.colon"));
}
}
String name = new String(httpheader.name, 0, httpheader.nameEnd);
String value = new String(httpheader.value, 0, httpheader.valueEnd);
request.addHeader(name, value);
if (name.equals("cookie")) {
Cookie cookies[] = parseCookie(value);
for (int i = 0; i < cookies.length; i++) {
if (cookies[i].getName().equals("jsessionid")) {
if (!request.isRequestedSessionIdFromCookie()) {
request.setRequestedSessionId(cookies[i].getPassword());
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) {
System.out.println(sm.getString("httpProcessor.parseHeaders.contentLength"));
}
request.setContentLength(n);
} else if (name.equals("content-type")) {
request.setContentType(value);
}
}
}
/**
* 解析Cookie
*
* @param value
* @return
*/
private static Cookie[] parseCookie(String value) {
return null;
}
/**
* 解析请求行
*
* @param input
* @param output
* @throws IOException
*/
public static void parseRequestLine(HttpRequest request, SocketInputStream input, OutputStream output)
throws IOException {
input.readRequestLine(requestLine);
String method = new String(requestLine.method, 0, requestLine.methodEnd);
String uri = null;
String protocol = new String(requestLine.protocol, 0, requestLine.protocolEnd);
if (method.length() < 1) {
System.out.println("Missing HTTP request method");
} else if (requestLine.uriEnd < 1) {
System.out.println("Missing HTTP 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);
}
if (!uri.startsWith("/")) {
int pos = uri.indexOf("://");
if (pos != -1) {
pos = uri.indexOf('/', pos + 3);
if (pos == -1) {
uri = "";
} else {
uri = uri.substring(pos);
}
}
}
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);
}
String normalizedUri = normalize(uri);
((HttpRequest) request).setMethod(method);
request.setProtocol(protocol);
if (normalizedUri != null) {
((HttpRequest) request).setRequestURI(normalizedUri);
} else {
((HttpRequest) request).setRequestURI(uri);
}
if (normalizedUri == null) {
System.out.println("Invalid URI: " + uri + "'");
}
}
/**
* 解析参数
*
* @param request
* @throws UnsupportedEncodingException
*/
protected static void parseParameters(HttpRequest request) throws UnsupportedEncodingException {
if (request.parsed)
return;
results.setLocked(false);
String encoding = request.getCharacterEncoding();
if (encoding == null)
encoding = "ISO-8859-1";
String queryString = request.getQueryString();
parseParameters(results, queryString, encoding);
String contentType = request.getContentType();
if (contentType == null)
contentType = "";
int semicolon = contentType.indexOf(':');
if (semicolon >= 0) {
contentType = contentType.substring(0, semicolon).trim();
} else {
contentType = contentType.trim();
}
if ("POST".equals(request.getMethod()) && (request.getContentLength() > 0)
&& "application/x-www-form-urlencoded".equals(contentType)) {
try {
int max = request.getContentLength();
int len = 0;
byte buf[] = new byte[request.getContentLength()];
InputStream is = request.getInput();
while (len < max) {
int next = is.read(buf, len, max - len);
if (next < 0) {
break;
}
len += next;
}
is.close();
if (len < max) {
throw new RuntimeException("Content length mismatch");
}
parseParameters(results, buf, encoding);
} catch (UnsupportedEncodingException ue) {
ue.printStackTrace();
} catch (IOException e) {
throw new RuntimeException("Content read fail");
}
}
results.setLocked(true);
request.parsed = true;
request.parameters = results;
}
private static void parseParameters(HttpRequestParameters results, byte[] data, String encoding) throws UnsupportedEncodingException {
if (data != null && data.length > 0) {
int pos = 0;
int ix = 0;
int ox = 0;
String key = null;
String value = null;
while (ix < data.length) {
byte c = data[ix++];
switch ((char) c) {
case '&':
value = new String(data, 0, ox, encoding);
if (key != null) {
putMapEntry(results, key, value);
key = null;
}
ox = 0;
break;
case '=':
key = new String(data, 0, ox, encoding);
ox = 0;
break;
case '+':
data[ox++] = (byte) ' ';
break;
case '%':
data[ox++] = (byte) ((convertHexDigit(data[ix++]) << 4) + convertHexDigit(data[ix++]));
break;
default:
data[ox++] = c;
}
}
if (key != null) {
value = new String(data, 0, ox, encoding);
putMapEntry(results, key, value);
}
}
}
private static byte convertHexDigit(byte b) {
if ((b >= '0') && (b <= '9'))
return (byte) (b - '0');
if ((b >= 'a') && (b <= 'f'))
return (byte) (b - 'a' + 10);
if ((b >= 'A') && (b <= 'F'))
return (byte) (b - 'A' + 10);
return 0;
}
private static void parseParameters(HttpRequestParameters results, String data, String encoding) throws UnsupportedEncodingException {
if ((data != null) && (data.length() > 0)) {
int len = data.length();
byte[] bytes = new byte[len];
data.getBytes(0, len, bytes, 0);
parseParameters(results, bytes, encoding);
}
}
private static void putMapEntry(Map map, String name, String value) {
String[] newValues = null;
String[] oldValues = (String[]) map.get(name);
if (oldValues == null) {
newValues = new String[1];
newValues[0] = value;
} else {
newValues = new String[oldValues.length + 1];
System.arraycopy(oldValues, 0, newValues, 0, oldValues.length);
newValues[oldValues.length] = value;
}
map.put(name, newValues);
}
/**
* 标准化
*
* @param path
* @return
*/
private static String normalize(String path) {
if (path == null)
return null;
String normalized = path;
if (normalized.startsWith("/%7E") || normalized.startsWith("/%7e"))
normalized = "/~" + normalized.substring(4);
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 "/";
if (normalized.indexOf('\\') >= 0)
normalized = normalized.replace('\\', '/');
if (!normalized.startsWith("/"))
normalized = "/" + normalized;
while (true) {
int index = normalized.indexOf("//");
if (index < 0)
break;
normalized = normalized.substring(0, index) + normalized.substring(index + 1);
}
while (true) {
int index = normalized.indexOf("/./");
if (index < 0)
break;
normalized = normalized.substring(0, index) + normalized.substring(index + 2);
}
while (true) {
int index = normalized.indexOf("/../");
if (index < 0)
break;
if (index == 0)
return (null);
int index2 = normalized.lastIndexOf('/', index - 1);
normalized = normalized.substring(0, index2) + normalized.substring(index + 3);
}
if (normalized.indexOf("/...") >= 0)
return (null);
return (normalized);
}
}
19. SocketInputStream
package Util;
import java.io.IOException;
import java.io.InputStream;
import Model.HttpHeader;
import Model.HttpRequestLine;
/**
* 读取类
*
* @author JayKing
*
*/
public class SocketInputStream extends InputStream {
private static final byte CR = (byte) '\r';// 首部
private static final byte LF = (byte) '\n';// 换行 \r\n回到首部换行
private static final byte SP = (byte) ' ';
private static final byte HT = (byte) '\t';
private static final byte COLON = (byte) ':';
private static final int LC_OFFSET = 'A' - 'a';
protected byte buf[];// 字节数组
protected int count = 0;// buf的长度
protected int pos;// buf的指针
protected InputStream is;
protected static StringManager sm = StringManager.getManager(Contants.Package);
public SocketInputStream(InputStream is, int bufferSize) {
this.is = is;
buf = new byte[bufferSize];
}
/**
* 读取请求头
*
* @param header
* @throws IOException
*/
public void readHeader(HttpHeader header) throws IOException {
if (header.nameEnd != 0)
header.recycle();
int chr = read();
if ((chr == CR) || (chr == LF)) {
if (chr == CR)
read();
header.nameEnd = 0;
header.valueEnd = 0;
return;
} else {
pos--;
}
int maxRead = header.name.length;
int readStart = pos;
int readCount = 0;
boolean colon = false;
while (!colon) {
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 {
System.out.println(sm.getString("requestStream.readline.toolong"));
}
}
if (pos >= count) {
int val = read();
if (val == -1) {
System.out.println(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;
maxRead = header.value.length;
readStart = pos;
readCount = 0;
int crPos = -2;
boolean eol = false;
boolean validLine = true;
while (validLine) {
boolean space = true;
while (space) {
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) || (buf[pos] == HT)) {
pos++;
} else {
space = false;
}
}
while (!eol) {
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 {
System.out.println(sm.getString("requestStream.readline.toolong"));
}
}
if (pos >= count) {
int val = read();
if (val == -1)
System.out.println(sm.getString("requestStream.readline.error"));
pos = 0;
readStart = 0;
}
if (buf[pos] == CR) {
} else if (buf[pos] == LF) {
eol = true;
} else {
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 (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 {
System.out.println(sm.getString("requestStream.readline.toolong"));
}
}
header.value[readCount] = ' ';
readCount++;
}
}
header.valueEnd = readCount;
}
/**
* 读取请求行
*
* @param requestLine
* @throws IOException
*/
public void readRequestLine(HttpRequestLine requestLine) throws IOException {
if (requestLine.methodEnd != 0)
requestLine.recycle();
int chr = 0;
do {
try {
chr = read();
} catch (Exception e) {
chr = -1;
System.out.println(sm.getString("requestStream.readline.error"));
}
} while ((chr == CR) && (chr == LF));
pos--;
int maxRead = requestLine.method.length;
int readStart = pos;
int readCount = 0;
boolean space = false;
while (!space) {
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 {
System.out.println(sm.getString("requestStream.readline.toolong"));
}
}
if (pos >= count) {
int val = read();
if (val == -1) {
System.out.println(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;
maxRead = requestLine.uri.length;
readStart = pos;
readCount = 0;
space = false;
boolean eol = false;
while (!space) {
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 {
System.out.println(sm.getString("requestStream.readline.toolong"));
}
}
if (pos >= count) {
int val = read();
if (val == -1)
System.out.println(sm.getString("requestStream.readline.error"));
pos = 0;
readStart = 0;
}
if (buf[pos] == SP) {
space = true;
} else if ((buf[pos] == CR) || (buf[pos] == LF)) {
eol = true;
space = true;
}
requestLine.uri[readCount] = (char) buf[pos];
readCount++;
pos++;
}
requestLine.uriEnd = readCount - 1;
maxRead = requestLine.protocol.length;
readStart = pos;
readCount = 0;
while (!eol) {
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 {
System.out.println(sm.getString("requestStream.readline.toolong"));
}
}
if (pos >= count) {
int val = read();
if (val == -1)
System.out.println(sm.getString("requestStream.readline.error"));
pos = 0;
readStart = 0;
}
if (buf[pos] == CR) {
} else if (buf[pos] == LF) {
eol = true;
} else {
requestLine.protocol[readCount] = (char) buf[pos];
readCount++;
}
pos++;
}
requestLine.protocolEnd = readCount;
}
/**
* 读取一个buf数组,并做判断 必须进行重写
*/
public int read() throws IOException {
if (pos >= count) {
fill();
if (pos >= count)
return -1;
}
return buf[pos++] & 0xff;// byte类型转换成int类型保持二进制数一致性
}
/**
* 读取一个buf数组
*
* @throws IOException
*/
public void fill() throws IOException {
pos = 0;
count = 0;
int nRead = is.read(buf);
if (nRead > 0) {
count = nRead;
}
}
public int available() throws IOException {
return (count - pos) + is.available();
}
public void close() throws IOException {
if (is == null)
return;
is.close();
is = null;
buf = null;
}
}
20. StringManager
package Util;
/**
* 字符串获取类
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Hashtable;
import java.util.Properties;
public class StringManager {
private String packagename;
private static Hashtable managers = new Hashtable();
private StringManager(String packagename) {
this.packagename = packagename;
}
public synchronized static StringManager getManager(String packagename) {
StringManager mgr = (StringManager) managers.get(packagename);
if (mgr == null) {
mgr = new StringManager(packagename);
}
return mgr;
}
public String getString(String string) throws IOException {
Properties p = new Properties();
InputStream in = new FileInputStream(Contants.Config + File.separator + "LocalStrings.properties");
p.load(in);
return p.getProperty(string);
}
}
三.运行程序
静态资源:打开浏览器在地址栏中输入URL:Http://localhost:8080/index.html
Servlet资源:打开浏览器在地址栏中输入URL:Http://localhost:8080/Servlet/MyServlet