一个较丰满的servlet web server,由简化的conector、HttpProcessor、bootstrap 和简单servelt处理器构成(1代码清单)
代码结构:
该目录未能显示项目根下的webroot文件夹,此文件夹存放servlet程序员编译的servlet.class文件和静态资源。
- BootStrap

package sub.startup; import sub.connector.http.HttpConnector; public final class Bootstrap { public static void main(String[] args) {//之前是一个server,现在是有启动和连接器代理 HttpConnector connector = new HttpConnector(); connector.start(); } }
- HttpConnector

1 package sub.connector.http; 2 3 import java.io.IOException; 4 import java.net.InetAddress; 5 import java.net.ServerSocket; 6 import java.net.Socket; 7 8 public class HttpConnector implements Runnable {//开启了线程机制 9 10 boolean stopped;//默认false 11 private String scheme = "http"; 12 13 public String getScheme() { 14 return scheme; 15 } 16 17 public void run() { 18 ServerSocket serverSocket = null; 19 int port = 8080; 20 try { 21 serverSocket = new ServerSocket(port, 1, InetAddress.getByName("192.168.1.100"));//绑定自己的ip 22 } 23 catch (IOException e) { 24 e.printStackTrace(); 25 System.exit(1); 26 } 27 while (!stopped) { 28 // Accept the next incoming connection from the server socket 29 Socket socket = null; 30 try { 31 socket = serverSocket.accept(); 32 System.out.println("服务器接受到请求"); 33 } 34 catch (Exception e) { 35 continue; 36 } 37 // Hand this socket off to an HttpProcessor 38 HttpProcessor processor = new HttpProcessor(this); 39 processor.process(socket); 40 System.out.println("进入Http解析程序"); 41 } 42 } 43 44 public void start() { 45 Thread thread = new Thread(this); 46 thread.start(); 47 } 48 }
- HttpProcessor

1 package sub.connector.http; 2 3 import sub.ServletProcessor; 4 import sub.StaticResourceProcessor; 5 import java.net.Socket; 6 import java.io.OutputStream; 7 import java.io.IOException; 8 import javax.servlet.ServletException; 9 import javax.servlet.http.Cookie; 10 import org.apache.catalina.util.RequestUtil; 11 import org.apache.catalina.util.StringManager; 12 13 /* this class used to be called HttpServer 取代了原来的HttpServer类*/ 14 /** 15 * 原来的HttpServer除去等待请求的任务以外,就是创建res/req并“初始化”,req对象的创建,头部,行部的初始化和处理,req形同一个entity,但是请求体的解析在哪里? 16 * 并调用加载servlet的processor类(负责servlet的加载处理),使其动态加载servlet并传递res/req 17 * 如何获得请求体? 18 * */ 19 public class HttpProcessor { 20 21 public HttpProcessor(HttpConnector connector) { 22 this.connector = connector; 23 } 24 /** 25 * The HttpConnector with which this processor is associated. 26 */ 27 private HttpConnector connector = null; 28 private HttpRequest request; 29 private HttpRequestLine requestLine = new HttpRequestLine(); 30 private HttpResponse response; 31 32 protected String method = null; 33 protected String queryString = null; 34 35 /** 36 * The string manager for this package. 37 */ 38 protected StringManager sm = 39 StringManager.getManager("sub.connector.http");//读取标签文件中的信息,用来打印日志,指定包,供本包使用。 40 41 public void process(Socket socket) { //负责创建res/req 42 SocketInputStream input = null; 43 OutputStream output = null; 44 try { 45 input = new SocketInputStream(socket.getInputStream(), 2048); 46 output = socket.getOutputStream(); 47 48 // create HttpRequest object and parse 49 request = new HttpRequest(input); 50 51 // create HttpResponse object 52 response = new HttpResponse(output); 53 response.setRequest(request); //响应对象的诸多属性,为什么不需要初始化?除了响应体之外。 54 55 response.setHeader("Server", "Pyrmont Servlet Container"); 56 parseRequest(input, output); //解析请求行 57 parseHeaders(input); //解析请求头 58 59 //check if this is a request for a servlet or a static resource 60 //a request for a servlet begins with "/servlet/" 61 if (request.getRequestURI().startsWith("/servlet/")) { 62 ServletProcessor processor = new ServletProcessor(); 63 processor.process(request, response); 64 } 65 else { 66 StaticResourceProcessor processor = new StaticResourceProcessor(); 67 processor.process(request, response); 68 } 69 70 // Close the socket 71 socket.close(); 72 // no shutdown for this application 73 } 74 catch (Exception e) { 75 e.printStackTrace(); 76 } 77 } 78 79 /** 80 * 该方法类似于初始化或构造方法的延伸,根据目的是使属性得到值。 81 * This method is the simplified version of the similar method in 82 * org.apache.catalina.connector.http.HttpProcessor. 83 * However, this method only parses some "easy" headers, such as 84 * "cookie", "content-length", and "content-type", and ignore other headers. 85 * @param input The input stream connected to our socket 86 * 87 * @exception IOException if an input/output error occurs 88 * @exception ServletException if a parsing error occurs 89 */ 90 private void parseHeaders(SocketInputStream input) 91 throws IOException, ServletException {//旧版本中该输入流有现成的方法获取头部信息。从关系来看,request更类似一个entity类 92 while (true) { 93 HttpHeader header = new HttpHeader(); 94 95 // Read the next header 96 input.readHeader(header); 97 if (header.nameEnd == 0) { 98 if (header.valueEnd == 0) { 99 return; 100 } 101 else { 102 throw new ServletException 103 (sm.getString("httpProcessor.parseHeaders.colon")); 104 } 105 } 106 107 String name = new String(header.name, 0, header.nameEnd); 108 String value = new String(header.value, 0, header.valueEnd); 109 request.addHeader(name, value); 110 // do something for some headers, ignore others. 111 if (name.equals("cookie")) { 112 Cookie cookies[] = RequestUtil.parseCookieHeader(value);//从header中获得cookie 113 for (int i = 0; i < cookies.length; i++) { 114 if (cookies[i].getName().equals("jsessionid")) { 115 // Override anything requested in the URL 116 if (!request.isRequestedSessionIdFromCookie()) { 117 // Accept only the first session id cookie 118 request.setRequestedSessionId(cookies[i].getValue()); 119 request.setRequestedSessionCookie(true); 120 request.setRequestedSessionURL(false); 121 } 122 } 123 request.addCookie(cookies[i]); //request添加cookie对象,以上是cookie对象赋值。 124 } 125 } 126 else if (name.equals("content-length")) { 127 int n = -1; 128 try { 129 n = Integer.parseInt(value); 130 } 131 catch (Exception e) { 132 throw new ServletException(sm.getString("httpProcessor.parseHeaders.contentLength")); 133 } 134 request.setContentLength(n); //设置content-length 135 } 136 else if (name.equals("content-type")) { 137 request.setContentType(value); 138 } 139 } //end while 140 } 141 142 143 private void parseRequest(SocketInputStream input, OutputStream output) 144 throws IOException, ServletException {//解析请求行,input对象可以直接获取这些属性值。 145 146 // Parse the incoming request line 147 input.readRequestLine(requestLine); 148 String method = 149 new String(requestLine.method, 0, requestLine.methodEnd); 150 String uri = null; 151 String protocol = new String(requestLine.protocol, 0, requestLine.protocolEnd); 152 153 // Validate the incoming request line 154 if (method.length() < 1) { 155 throw new ServletException("Missing HTTP request method"); 156 } 157 else if (requestLine.uriEnd < 1) { 158 throw new ServletException("Missing HTTP request URI"); 159 } 160 // Parse any query parameters out of the request URI 161 int question = requestLine.indexOf("?"); 162 if (question >= 0) { 163 request.setQueryString(new String(requestLine.uri, question + 1, 164 requestLine.uriEnd - question - 1)); 165 uri = new String(requestLine.uri, 0, question); 166 } 167 else { 168 request.setQueryString(null); 169 uri = new String(requestLine.uri, 0, requestLine.uriEnd); 170 } 171 172 173 // Checking for an absolute URI (with the HTTP protocol) 174 if (!uri.startsWith("/")) { 175 int pos = uri.indexOf("://"); 176 // Parsing out protocol and host name 177 if (pos != -1) { 178 pos = uri.indexOf('/', pos + 3); 179 if (pos == -1) { 180 uri = ""; 181 } 182 else { 183 uri = uri.substring(pos); 184 } 185 } 186 187 } 188 189 // Parse any requested session ID out of the request URI 从请求URI中解析所请求的会话ID 190 String match = ";jsessionid="; 191 int semicolon = uri.indexOf(match); 192 if (semicolon >= 0) { 193 String rest = uri.substring(semicolon + match.length()); 194 int semicolon2 = rest.indexOf(';'); 195 if (semicolon2 >= 0) { 196 request.setRequestedSessionId(rest.substring(0, semicolon2)); 197 rest = rest.substring(semicolon2); 198 } 199 else { 200 request.setRequestedSessionId(rest); 201 rest = ""; 202 } 203 request.setRequestedSessionURL(true); 204 uri = uri.substring(0, semicolon) + rest; 205 } 206 else { 207 request.setRequestedSessionId(null); 208 request.setRequestedSessionURL(false); 209 } 210 211 // Normalize URI (using String operations at the moment) 规范化请求uri 212 String normalizedUri = normalize(uri); 213 214 // Set the corresponding request properties 设置相应的请求属性 215 ((HttpRequest) request).setMethod(method); 216 request.setProtocol(protocol); 217 if (normalizedUri != null) { 218 ((HttpRequest) request).setRequestURI(normalizedUri); 219 } 220 else { 221 ((HttpRequest) request).setRequestURI(uri); 222 } 223 224 if (normalizedUri == null) { 225 throw new ServletException("Invalid URI: " + uri + "'"); 226 } 227 } 228 229 /** 230 * Return a context-relative path, beginning with a "/", that represents 231 * the canonical version of the specified path after ".." and "." elements 232 * are resolved out. If the specified path attempts to go outside the 233 * boundaries of the current context (i.e. too many ".." path elements 234 * are present), return <code>null</code> instead. 235 * 236 * @param path Path to be normalized 237 */ 238 protected String normalize(String path) { 239 if (path == null) 240 return null; 241 // Create a place for the normalized path 242 String normalized = path; 243 244 // Normalize "/%7E" and "/%7e" at the beginning to "/~" 245 if (normalized.startsWith("/%7E") || normalized.startsWith("/%7e")) 246 normalized = "/~" + normalized.substring(4); 247 248 // Prevent encoding '%', '/', '.' and '\', which are special reserved 249 // characters 250 if ((normalized.indexOf("%25") >= 0) 251 || (normalized.indexOf("%2F") >= 0) 252 || (normalized.indexOf("%2E") >= 0) 253 || (normalized.indexOf("%5C") >= 0) 254 || (normalized.indexOf("%2f") >= 0) 255 || (normalized.indexOf("%2e") >= 0) 256 || (normalized.indexOf("%5c") >= 0)) { 257 return null; 258 } 259 260 if (normalized.equals("/.")) 261 return "/"; 262 263 // Normalize the slashes and add leading slash if necessary 264 if (normalized.indexOf('\\') >= 0) 265 normalized = normalized.replace('\\', '/'); 266 if (!normalized.startsWith("/")) 267 normalized = "/" + normalized; 268 269 // Resolve occurrences of "//" in the normalized path 270 while (true) { 271 int index = normalized.indexOf("//"); 272 if (index < 0) 273 break; 274 normalized = normalized.substring(0, index) + 275 normalized.substring(index + 1); 276 } 277 278 // Resolve occurrences of "/./" in the normalized path 279 while (true) { 280 int index = normalized.indexOf("/./"); 281 if (index < 0) 282 break; 283 normalized = normalized.substring(0, index) + 284 normalized.substring(index + 2); 285 } 286 287 // Resolve occurrences of "/../" in the normalized path 288 while (true) { 289 int index = normalized.indexOf("/../"); 290 if (index < 0) 291 break; 292 if (index == 0) 293 return (null); // Trying to go outside our context 294 int index2 = normalized.lastIndexOf('/', index - 1); 295 normalized = normalized.substring(0, index2) + 296 normalized.substring(index + 3); 297 } 298 299 // Declare occurrences of "/..." (three or more dots) to be invalid 300 // (on some Windows platforms this walks the directory tree!!!) 301 if (normalized.indexOf("/...") >= 0) 302 return (null); 303 304 // Return the normalized path that we have completed 305 return (normalized); 306 307 } 308 309 }
- HttpRequest

1 package sub.connector.http; 2 3 /** this class copies methods from org.apache.catalina.connector.HttpRequestBase 4 * and org.apache.catalina.connector.http.HttpRequestImpl. 5 * The HttpRequestImpl class employs a pool of HttpHeader objects for performance 6 * These two classes will be explained in Chapter 4. 7 */ 8 import sub.connector.RequestStream; 9 10 11 12 import javax.servlet.http.HttpServletRequest; 13 import javax.servlet.http.HttpServletResponse; 14 import javax.servlet.http.HttpSession; 15 import javax.servlet.http.HttpUpgradeHandler; 16 import javax.servlet.http.Part; 17 import javax.servlet.http.Cookie; 18 import javax.servlet.AsyncContext; 19 import javax.servlet.DispatcherType; 20 import javax.servlet.RequestDispatcher; 21 import javax.servlet.ServletContext; 22 import javax.servlet.ServletException; 23 import javax.servlet.ServletInputStream; 24 import javax.servlet.ServletRequest; 25 import javax.servlet.ServletResponse; 26 27 import java.security.Principal; 28 import java.io.InputStream; 29 import java.io.InputStreamReader; 30 import java.io.IOException; 31 import java.io.BufferedReader; 32 import java.io.UnsupportedEncodingException; 33 import java.net.InetAddress; 34 import java.net.Socket; 35 import java.text.ParseException; 36 import java.text.SimpleDateFormat; 37 import java.util.ArrayList; 38 import java.util.Collection; 39 import java.util.Date; 40 import java.util.Enumeration; 41 import java.util.HashMap; 42 import java.util.Locale; 43 import java.util.Map; 44 import org.apache.catalina.util.Enumerator; 45 import org.apache.catalina.util.ParameterMap; 46 import org.apache.catalina.util.RequestUtil; 47 /**request在servet程序员使用之前解析还是使用时解析更好? 48 * 如果是前者,就应该在servletProcessor中类似于初始化那样,全部解析,然后程序员可以直接get; 49 * 若后者,则需要在get中包含解析过程。 50 * */ 51 public class HttpRequest implements HttpServletRequest { 52 53 private String contentType; 54 private int contentLength; 55 private InetAddress inetAddress; 56 private InputStream input; 57 private String method; 58 private String protocol; 59 private String queryString; 60 private String requestURI; 61 private String serverName; 62 private int serverPort; 63 private Socket socket; 64 private boolean requestedSessionCookie; 65 private String requestedSessionId; 66 private boolean requestedSessionURL; 67 68 /** 69 * The request attributes for this request. 该当前请求的请求属性 70 */ 71 protected HashMap attributes = new HashMap(); 72 /** 73 * The authorization credentials sent with this Request. 当前请求的授权证书 74 */ 75 protected String authorization = null; 76 /** 77 * The context path for this request. 当前请求的上下文路径 78 */ 79 protected String contextPath = ""; 80 /** 81 * The set of cookies associated with this Request. 与请求关联的一组cookie(浏览器会自行发送cookie) 82 */ 83 protected ArrayList cookies = new ArrayList(); 84 /** 85 * An empty collection to use for returning empty Enumerations. Do not 86 * add any elements to this collection! 87 */ 88 protected static ArrayList empty = new ArrayList(); 89 /** 90 * The set of SimpleDateFormat formats to use in getDateHeader(). 91 */ 92 protected SimpleDateFormat formats[] = { 93 new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US), 94 new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US), 95 new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US) 96 }; 97 98 /** 99 * The HTTP headers associated with this Request, keyed by name. The 100 * values are ArrayLists of the corresponding header values. 用map保存header信息。 101 */ 102 protected HashMap headers = new HashMap(); 103 /** 104 * The parsed parameters for this request. This is populated only if 105 * parameter information is requested via one of the 106 * <code>getParameter()</code> family of method calls. The key is the 107 * parameter name, while the value is a String array of values for this 108 * parameter. 109 * <p> 110 * <strong>IMPLEMENTATION NOTE</strong> - Once the parameters for a 111 * particular request are parsed and stored here, they are not modified. 112 * Therefore, application level access to the parameters need not be 113 * synchronized. 114 */ 115 protected ParameterMap parameters = null; //hashmap的子类 116 117 /** 118 * Have the parameters for this request been parsed yet? 119 */ 120 protected boolean parsed = false; 121 protected String pathInfo = null; 122 123 /** 124 * The reader that has been returned by <code>getReader</code>, if any. 125 */ 126 protected BufferedReader reader = null; 127 128 /** 129 * The ServletInputStream that has been returned by 130 * <code>getInputStream()</code>, if any. 131 */ 132 protected ServletInputStream stream = null; 133 134 public HttpRequest(InputStream input) { 135 this.input = input; 136 } 137 138 public void addHeader(String name, String value) { //header包含所有的请求key-value 139 name = name.toLowerCase(); 140 synchronized (headers) { 141 ArrayList values = (ArrayList) headers.get(name); 142 if (values == null) { 143 values = new ArrayList(); 144 headers.put(name, values); 145 } 146 values.add(value); 147 } 148 } 149 150 /** 151 * Parse the parameters of this request, if it has not already occurred. 152 * If parameters are present in both the query string and the request 153 * content, they are merged. 一个“过程” 154 */ 155 protected void parseParameters() {//解析并把参数存进parameters中 156 if (parsed) 157 return; 158 ParameterMap results = parameters; //参数集合? 159 if (results == null) 160 results = new ParameterMap(); 161 results.setLocked(false); 162 String encoding = getCharacterEncoding(); 163 if (encoding == null) 164 encoding = "ISO-8859-1"; 165 166 // Parse any parameters specified in the query string 解析查询字符串中指定的任何参数 167 String queryString = getQueryString(); 168 try { 169 RequestUtil.parseParameters(results, queryString, encoding);//没有输入流,怎么就把请求参数解析出来的?? 170 } 171 catch (UnsupportedEncodingException e) { 172 ; 173 } 174 175 // Parse any parameters specified in the input stream 解析输入流中指定的任何参数 176 String contentType = getContentType(); 177 if (contentType == null) 178 contentType = ""; 179 int semicolon = contentType.indexOf(';'); 180 if (semicolon >= 0) { 181 contentType = contentType.substring(0, semicolon).trim(); 182 } 183 else { 184 contentType = contentType.trim(); 185 } 186 if ("POST".equals(getMethod()) && (getContentLength() > 0) 187 && "application/x-www-form-urlencoded".equals(contentType)) {//post请求方式下解析请求参数 188 try { 189 int max = getContentLength(); 190 int len = 0; 191 byte buf[] = new byte[getContentLength()]; 192 ServletInputStream is = getInputStream(); 193 while (len < max) { 194 int next = is.read(buf, len, max - len); 195 if (next < 0 ) { 196 break; 197 } 198 len += next; 199 } 200 is.close(); 201 if (len < max) { 202 throw new RuntimeException("Content length mismatch"); 203 } 204 RequestUtil.parseParameters(results, buf, encoding); 205 } 206 catch (UnsupportedEncodingException ue) { 207 ; 208 } 209 catch (IOException e) { 210 throw new RuntimeException("Content read fail"); 211 } 212 } 213 214 // Store the final results 215 results.setLocked(true); 216 parsed = true; 217 parameters = results; 218 } 219 220 public void addCookie(Cookie cookie) { 221 synchronized (cookies) { 222 cookies.add(cookie); 223 } 224 } 225 226 /** 227 * Create and return a ServletInputStream to read the content 228 * associated with this Request. The default implementation creates an 229 * instance of RequestStream associated with this request, but this can 230 * be overridden if necessary. 231 * 232 * @exception IOException if an input/output error occurs 233 */ 234 public ServletInputStream createInputStream() throws IOException { 235 return (new RequestStream(this)); 236 } 237 238 public InputStream getStream() { 239 return input; 240 } 241 public void setContentLength(int length) { 242 this.contentLength = length; 243 } 244 245 public void setContentType(String type) { 246 this.contentType = type; 247 } 248 249 public void setInet(InetAddress inetAddress) { 250 this.inetAddress = inetAddress; 251 } 252 253 public void setContextPath(String path) { 254 if (path == null) 255 this.contextPath = ""; 256 else 257 this.contextPath = path; 258 } 259 260 public void setMethod(String method) { 261 this.method = method; 262 } 263 264 public void setPathInfo(String path) { 265 this.pathInfo = path; 266 } 267 268 public void setProtocol(String protocol) { 269 this.protocol = protocol; 270 } 271 272 public void setQueryString(String queryString) { 273 this.queryString = queryString; 274 } 275 276 public void setRequestURI(String requestURI) { 277 this.requestURI = requestURI; 278 } 279 /** 280 * Set the name of the server (virtual host) to process this request. 281 * 282 * @param name The server name 283 */ 284 public void setServerName(String name) { 285 this.serverName = name; 286 } 287 /** 288 * Set the port number of the server to process this request. 289 * 290 * @param port The server port 291 */ 292 public void setServerPort(int port) { 293 this.serverPort = port; 294 } 295 296 public void setSocket(Socket socket) { 297 this.socket = socket; 298 } 299 300 /** 301 * Set a flag indicating whether or not the requested session ID for this 302 * request came in through a cookie. This is normally called by the 303 * HTTP Connector, when it parses the request headers. 304 * 305 * @param flag The new flag 306 */ 307 public void setRequestedSessionCookie(boolean flag) { 308 this.requestedSessionCookie = flag; 309 } 310 311 public void setRequestedSessionId(String requestedSessionId) { 312 this.requestedSessionId = requestedSessionId; 313 } 314 315 public void setRequestedSessionURL(boolean flag) { 316 requestedSessionURL = flag; 317 } 318 319 /* implementation of the HttpServletRequest*/ 320 public Object getAttribute(String name) { 321 synchronized (attributes) { 322 return (attributes.get(name)); 323 } 324 } 325 326 public Enumeration getAttributeNames() { 327 synchronized (attributes) { 328 return (new Enumerator(attributes.keySet())); 329 } 330 } 331 332 public String getAuthType() { 333 return null; 334 } 335 336 public String getCharacterEncoding() { 337 return null; 338 } 339 340 public int getContentLength() { 341 return contentLength ; 342 } 343 344 public String getContentType() { 345 return contentType; 346 } 347 348 public String getContextPath() { 349 return contextPath; 350 } 351 352 public Cookie[] getCookies() { 353 synchronized (cookies) { 354 if (cookies.size() < 1) 355 return (null); 356 Cookie results[] = new Cookie[cookies.size()]; 357 return ((Cookie[]) cookies.toArray(results)); 358 } 359 } 360 361 public long getDateHeader(String name) { 362 String value = getHeader(name); 363 if (value == null) 364 return (-1L); 365 366 // Work around a bug in SimpleDateFormat in pre-JDK1.2b4 367 // (Bug Parade bug #4106807) 368 value += " "; 369 370 // Attempt to convert the date header in a variety of formats 371 for (int i = 0; i < formats.length; i++) { 372 try { 373 Date date = formats[i].parse(value); 374 return (date.getTime()); 375 } 376 catch (ParseException e) { 377 ; 378 } 379 } 380 throw new IllegalArgumentException(value); 381 } 382 383 public String getHeader(String name) { 384 name = name.toLowerCase(); 385 synchronized (headers) { 386 ArrayList values = (ArrayList) headers.get(name); 387 if (values != null) 388 return ((String) values.get(0)); 389 else 390 return null; 391 } 392 } 393 394 public Enumeration getHeaderNames() { 395 synchronized (headers) { 396 return (new Enumerator(headers.keySet())); 397 } 398 } 399 400 public Enumeration getHeaders(String name) { 401 name = name.toLowerCase(); 402 synchronized (headers) { 403 ArrayList values = (ArrayList) headers.get(name); 404 if (values != null) 405 return (new Enumerator(values)); 406 else 407 return (new Enumerator(empty)); 408 } 409 } 410 411 public ServletInputStream getInputStream() throws IOException { 412 if (reader != null) 413 throw new IllegalStateException("getInputStream has been called"); 414 415 if (stream == null) 416 stream = createInputStream(); 417 return (stream); 418 } 419 420 public int getIntHeader(String name) { 421 String value = getHeader(name); 422 if (value == null) 423 return (-1); 424 else 425 return (Integer.parseInt(value)); 426 } 427 428 public Locale getLocale() { 429 return null; 430 } 431 432 public Enumeration getLocales() { 433 return null; 434 } 435 436 public String getMethod() { 437 return method; 438 } 439 440 public String getParameter(String name) {//在组件程序员获取参数时会包含解析过程! 441 parseParameters(); 442 String values[] = (String[]) parameters.get(name); 443 if (values != null) 444 return (values[0]); 445 else 446 return (null); 447 } 448 449 public Map getParameterMap() { 450 parseParameters(); 451 return (this.parameters); 452 } 453 454 public Enumeration getParameterNames() { 455 parseParameters(); 456 return (new Enumerator(parameters.keySet())); 457 } 458 459 public String[] getParameterValues(String name) { 460 parseParameters(); 461 String values[] = (String[]) parameters.get(name); 462 if (values != null) 463 return (values); 464 else 465 return null; 466 } 467 468 public String getPathInfo() { 469 return pathInfo; 470 } 471 472 public String getPathTranslated() { 473 return null; 474 } 475 476 public String getProtocol() { 477 return protocol; 478 } 479 480 public String getQueryString() { 481 return queryString; 482 } 483 484 public BufferedReader getReader() throws IOException { 485 if (stream != null) 486 throw new IllegalStateException("getInputStream has been called."); 487 if (reader == null) { 488 String encoding = getCharacterEncoding(); 489 if (encoding == null) 490 encoding = "ISO-8859-1"; 491 InputStreamReader isr = 492 new InputStreamReader(createInputStream(), encoding); 493 reader = new BufferedReader(isr); 494 } 495 return (reader); 496 } 497 498 public String getRealPath(String path) { 499 return null; 500 } 501 502 public String getRemoteAddr() { 503 return null; 504 } 505 506 public String getRemoteHost() { 507 return null; 508 } 509 510 public String getRemoteUser() { 511 return null; 512 } 513 514 public RequestDispatcher getRequestDispatcher(String path) { 515 return null; 516 } 517 518 public String getScheme() { 519 return null; 520 } 521 522 public String getServerName() { 523 return null; 524 } 525 526 public int getServerPort() { 527 return 0; 528 } 529 530 public String getRequestedSessionId() { 531 return null; 532 } 533 534 public String getRequestURI() { 535 return requestURI; 536 } 537 538 public StringBuffer getRequestURL() { 539 return null; 540 } 541 542 public HttpSession getSession() { 543 return null; 544 } 545 546 public HttpSession getSession(boolean create) { 547 return null; 548 } 549 550 public String getServletPath() { 551 return null; 552 } 553 554 public Principal getUserPrincipal() { 555 return null; 556 } 557 558 public boolean isRequestedSessionIdFromCookie() { 559 return false; 560 } 561 562 public boolean isRequestedSessionIdFromUrl() { 563 return isRequestedSessionIdFromURL(); 564 } 565 566 public boolean isRequestedSessionIdFromURL() { 567 return false; 568 } 569 570 public boolean isRequestedSessionIdValid() { 571 return false; 572 } 573 574 public boolean isSecure() { 575 return false; 576 } 577 578 public boolean isUserInRole(String role) { 579 return false; 580 } 581 582 public void removeAttribute(String attribute) { 583 } 584 585 public void setAttribute(String key, Object value) { 586 } 587 588 /** 589 * Set the authorization credentials sent with this request. 590 * 591 * @param authorization The new authorization credentials 592 */ 593 public void setAuthorization(String authorization) { 594 this.authorization = authorization; 595 } 596 597 public void setCharacterEncoding(String encoding) throws UnsupportedEncodingException { 598 } 599 600 @Override 601 public long getContentLengthLong() { 602 // TODO Auto-generated method stub 603 return 0; 604 } 605 606 @Override 607 public int getRemotePort() { 608 // TODO Auto-generated method stub 609 return 0; 610 } 611 612 @Override 613 public String getLocalName() { 614 // TODO Auto-generated method stub 615 return null; 616 } 617 618 @Override 619 public String getLocalAddr() { 620 // TODO Auto-generated method stub 621 return null; 622 } 623 624 @Override 625 public int getLocalPort() { 626 // TODO Auto-generated method stub 627 return 0; 628 } 629 630 @Override 631 public ServletContext getServletContext() { 632 // TODO Auto-generated method stub 633 return null; 634 } 635 636 @Override 637 public AsyncContext startAsync() throws IllegalStateException { 638 // TODO Auto-generated method stub 639 return null; 640 } 641 642 @Override 643 public AsyncContext startAsync(ServletRequest arg0, ServletResponse arg1) throws IllegalStateException { 644 // TODO Auto-generated method stub 645 return null; 646 } 647 648 @Override 649 public boolean isAsyncStarted() { 650 // TODO Auto-generated method stub 651 return false; 652 } 653 654 @Override 655 public boolean isAsyncSupported() { 656 // TODO Auto-generated method stub 657 return false; 658 } 659 660 @Override 661 public AsyncContext getAsyncContext() { 662 // TODO Auto-generated method stub 663 return null; 664 } 665 666 @Override 667 public DispatcherType getDispatcherType() { 668 // TODO Auto-generated method stub 669 return null; 670 } 671 672 @Override 673 public String changeSessionId() { 674 // TODO Auto-generated method stub 675 return null; 676 } 677 678 @Override 679 public boolean authenticate(HttpServletResponse arg0) throws IOException, ServletException { 680 // TODO Auto-generated method stub 681 return false; 682 } 683 684 @Override 685 public void login(String arg0, String arg1) throws ServletException { 686 // TODO Auto-generated method stub 687 688 } 689 690 @Override 691 public void logout() throws ServletException { 692 // TODO Auto-generated method stub 693 694 } 695 696 @Override 697 public Collection<Part> getParts() throws IOException, ServletException { 698 // TODO Auto-generated method stub 699 return null; 700 } 701 702 @Override 703 public Part getPart(String arg0) throws IOException, ServletException { 704 // TODO Auto-generated method stub 705 return null; 706 } 707 708 @Override 709 public <T extends HttpUpgradeHandler> T upgrade(Class<T> arg0) throws IOException, ServletException { 710 // TODO Auto-generated method stub 711 return null; 712 } 713 }
- HttpResponse

1 import sub.ServletProcessor; 2 import sub.StaticResourceProcessor; 3 import java.net.Socket; 4 import java.io.OutputStream; 5 import java.io.IOException; 6 import javax.servlet.ServletException; 7 import javax.servlet.http.Cookie; 8 import org.apache.catalina.util.RequestUtil; 9 import org.apache.catalina.util.StringManager; 10 11 /* this class used to be called HttpServer 取代了原来的HttpServer类*/ 12 /** 13 * 原来的HttpServer除去等待请求的任务以外,就是创建res/req并“初始化”,req对象的创建,头部,行部的初始化和处理,req形同一个entity,但是请求体的解析在哪里? 14 * 并调用加载servlet的processor类(负责servlet的加载处理),使其动态加载servlet并传递res/req 15 * 如何获得请求体? 16 * */ 17 public class HttpProcessor { 18 19 public HttpProcessor(HttpConnector connector) { 20 this.connector = connector; 21 } 22 /** 23 * The HttpConnector with which this processor is associated. 24 */ 25 private HttpConnector connector = null; 26 private HttpRequest request; 27 private HttpRequestLine requestLine = new HttpRequestLine(); 28 private HttpResponse response; 29 30 protected String method = null; 31 protected String queryString = null; 32 33 /** 34 * The string manager for this package. 35 */ 36 protected StringManager sm = 37 StringManager.getManager("sub.connector.http");//读取标签文件中的信息,用来打印日志,指定包,供本包使用。 38 39 public void process(Socket socket) { //负责创建res/req 40 SocketInputStream input = null; 41 OutputStream output = null; 42 try { 43 input = new SocketInputStream(socket.getInputStream(), 2048); 44 output = socket.getOutputStream(); 45 46 // create HttpRequest object and parse 47 request = new HttpRequest(input); 48 49 // create HttpResponse object 50 response = new HttpResponse(output); 51 response.setRequest(request); //响应对象的诸多属性,为什么不需要初始化?除了响应体之外。 52 53 response.setHeader("Server", "Pyrmont Servlet Container"); 54 parseRequest(input, output); //解析请求行 55 parseHeaders(input); //解析请求头 56 57 //check if this is a request for a servlet or a static resource 58 //a request for a servlet begins with "/servlet/" 59 if (request.getRequestURI().startsWith("/servlet/")) { 60 ServletProcessor processor = new ServletProcessor(); 61 processor.process(request, response); 62 } 63 else { 64 StaticResourceProcessor processor = new StaticResourceProcessor(); 65 processor.process(request, response); 66 } 67 68 // Close the socket 69 socket.close(); 70 // no shutdown for this application 71 } 72 catch (Exception e) { 73 e.printStackTrace(); 74 } 75 } 76 77 /** 78 * 该方法类似于初始化或构造方法的延伸,根据目的是使属性得到值。 79 * This method is the simplified version of the similar method in 80 * org.apache.catalina.connector.http.HttpProcessor. 81 * However, this method only parses some "easy" headers, such as 82 * "cookie", "content-length", and "content-type", and ignore other headers. 83 * @param input The input stream connected to our socket 84 * 85 * @exception IOException if an input/output error occurs 86 * @exception ServletException if a parsing error occurs 87 */ 88 private void parseHeaders(SocketInputStream input) 89 throws IOException, ServletException {//旧版本中该输入流有现成的方法获取头部信息。从关系来看,request更类似一个entity类 90 while (true) { 91 HttpHeader header = new HttpHeader(); 92 93 // Read the next header 94 input.readHeader(header); 95 if (header.nameEnd == 0) { 96 if (header.valueEnd == 0) { 97 return; 98 } 99 else { 100 throw new ServletException 101 (sm.getString("httpProcessor.parseHeaders.colon")); 102 } 103 } 104 105 String name = new String(header.name, 0, header.nameEnd); 106 String value = new String(header.value, 0, header.valueEnd); 107 request.addHeader(name, value); 108 // do something for some headers, ignore others. 109 if (name.equals("cookie")) { 110 Cookie cookies[] = RequestUtil.parseCookieHeader(value);//从header中获得cookie 111 for (int i = 0; i < cookies.length; i++) { 112 if (cookies[i].getName().equals("jsessionid")) { 113 // Override anything requested in the URL 114 if (!request.isRequestedSessionIdFromCookie()) { 115 // Accept only the first session id cookie 116 request.setRequestedSessionId(cookies[i].getValue()); 117 request.setRequestedSessionCookie(true); 118 request.setRequestedSessionURL(false); 119 } 120 } 121 request.addCookie(cookies[i]); //request添加cookie对象,以上是cookie对象赋值。 122 } 123 } 124 else if (name.equals("content-length")) { 125 int n = -1; 126 try { 127 n = Integer.parseInt(value); 128 } 129 catch (Exception e) { 130 throw new ServletException(sm.getString("httpProcessor.parseHeaders.contentLength")); 131 } 132 request.setContentLength(n); //设置content-length 133 } 134 else if (name.equals("content-type")) { 135 request.setContentType(value); 136 } 137 } //end while 138 } 139 140 141 private void parseRequest(SocketInputStream input, OutputStream output) 142 throws IOException, ServletException {//解析请求行,input对象可以直接获取这些属性值。 143 144 // Parse the incoming request line 145 input.readRequestLine(requestLine); 146 String method = 147 new String(requestLine.method, 0, requestLine.methodEnd); 148 String uri = null; 149 String protocol = new String(requestLine.protocol, 0, requestLine.protocolEnd); 150 151 // Validate the incoming request line 152 if (method.length() < 1) { 153 throw new ServletException("Missing HTTP request method"); 154 } 155 else if (requestLine.uriEnd < 1) { 156 throw new ServletException("Missing HTTP request URI"); 157 } 158 // Parse any query parameters out of the request URI 159 int question = requestLine.indexOf("?"); 160 if (question >= 0) { 161 request.setQueryString(new String(requestLine.uri, question + 1, 162 requestLine.uriEnd - question - 1)); 163 uri = new String(requestLine.uri, 0, question); 164 } 165 else { 166 request.setQueryString(null); 167 uri = new String(requestLine.uri, 0, requestLine.uriEnd); 168 } 169 170 171 // Checking for an absolute URI (with the HTTP protocol) 172 if (!uri.startsWith("/")) { 173 int pos = uri.indexOf("://"); 174 // Parsing out protocol and host name 175 if (pos != -1) { 176 pos = uri.indexOf('/', pos + 3); 177 if (pos == -1) { 178 uri = ""; 179 } 180 else { 181 uri = uri.substring(pos); 182 } 183 } 184 185 } 186 187 // Parse any requested session ID out of the request URI 从请求URI中解析所请求的会话ID 188 String match = ";jsessionid="; 189 int semicolon = uri.indexOf(match); 190 if (semicolon >= 0) { 191 String rest = uri.substring(semicolon + match.length()); 192 int semicolon2 = rest.indexOf(';'); 193 if (semicolon2 >= 0) { 194 request.setRequestedSessionId(rest.substring(0, semicolon2)); 195 rest = rest.substring(semicolon2); 196 } 197 else { 198 request.setRequestedSessionId(rest); 199 rest = ""; 200 } 201 request.setRequestedSessionURL(true); 202 uri = uri.substring(0, semicolon) + rest; 203 } 204 else { 205 request.setRequestedSessionId(null); 206 request.setRequestedSessionURL(false); 207 } 208 209 // Normalize URI (using String operations at the moment) 规范化请求uri 210 String normalizedUri = normalize(uri); 211 212 // Set the corresponding request properties 设置相应的请求属性 213 ((HttpRequest) request).setMethod(method); 214 request.setProtocol(protocol); 215 if (normalizedUri != null) { 216 ((HttpRequest) request).setRequestURI(normalizedUri); 217 } 218 else { 219 ((HttpRequest) request).setRequestURI(uri); 220 } 221 222 if (normalizedUri == null) { 223 throw new ServletException("Invalid URI: " + uri + "'"); 224 } 225 } 226 227 /** 228 * Return a context-relative path, beginning with a "/", that represents 229 * the canonical version of the specified path after ".." and "." elements 230 * are resolved out. If the specified path attempts to go outside the 231 * boundaries of the current context (i.e. too many ".." path elements 232 * are present), return <code>null</code> instead. 233 * 234 * @param path Path to be normalized 235 */ 236 protected String normalize(String path) { 237 if (path == null) 238 return null; 239 // Create a place for the normalized path 240 String normalized = path; 241 242 // Normalize "/%7E" and "/%7e" at the beginning to "/~" 243 if (normalized.startsWith("/%7E") || normalized.startsWith("/%7e")) 244 normalized = "/~" + normalized.substring(4); 245 246 // Prevent encoding '%', '/', '.' and '\', which are special reserved 247 // characters 248 if ((normalized.indexOf("%25") >= 0) 249 || (normalized.indexOf("%2F") >= 0) 250 || (normalized.indexOf("%2E") >= 0) 251 || (normalized.indexOf("%5C") >= 0) 252 || (normalized.indexOf("%2f") >= 0) 253 || (normalized.indexOf("%2e") >= 0) 254 || (normalized.indexOf("%5c") >= 0)) { 255 return null; 256 } 257 258 if (normalized.equals("/.")) 259 return "/"; 260 261 // Normalize the slashes and add leading slash if necessary 262 if (normalized.indexOf('\\') >= 0) 263 normalized = normalized.replace('\\', '/'); 264 if (!normalized.startsWith("/")) 265 normalized = "/" + normalized; 266 267 // Resolve occurrences of "//" in the normalized path 268 while (true) { 269 int index = normalized.indexOf("//"); 270 if (index < 0) 271 break; 272 normalized = normalized.substring(0, index) + 273 normalized.substring(index + 1); 274 } 275 276 // Resolve occurrences of "/./" in the normalized path 277 while (true) { 278 int index = normalized.indexOf("/./"); 279 if (index < 0) 280 break; 281 normalized = normalized.substring(0, index) + 282 normalized.substring(index + 2); 283 } 284 285 // Resolve occurrences of "/../" in the normalized path 286 while (true) { 287 int index = normalized.indexOf("/../"); 288 if (index < 0) 289 break; 290 if (index == 0) 291 return (null); // Trying to go outside our context 292 int index2 = normalized.lastIndexOf('/', index - 1); 293 normalized = normalized.substring(0, index2) + 294 normalized.substring(index + 3); 295 } 296 297 // Declare occurrences of "/..." (three or more dots) to be invalid 298 // (on some Windows platforms this walks the directory tree!!!) 299 if (normalized.indexOf("/...") >= 0) 300 return (null); 301 302 // Return the normalized path that we have completed 303 return (normalized); 304 305 } 306 307 }
- HttpReuqestFacaed

- HtppResponseFacaed

1 package sub.connector.http; 2 3 import java.io.IOException; 4 5 import java.io.PrintWriter; 6 import java.util.Collection; 7 import java.util.Locale; 8 import javax.servlet.ServletOutputStream; 9 import javax.servlet.http.Cookie; 10 import javax.servlet.http.HttpServletResponse; 11 12 public class HttpResponseFacade implements HttpServletResponse { 13 private HttpServletResponse response; 14 public HttpResponseFacade(HttpResponse response) { 15 this.response = response; 16 } 17 18 /** implementation of HttpServletResponse */ 19 public void addCookie(Cookie cookie) { 20 response.addCookie(cookie); 21 } 22 23 public void addDateHeader(String name, long value) { 24 response.addDateHeader(name, value); 25 } 26 27 public void addHeader(String name, String value) { 28 response.addHeader(name, value); 29 } 30 31 public void addIntHeader(String name, int value) { 32 response.addIntHeader(name, value); 33 } 34 35 public boolean containsHeader(String name) { 36 return response.containsHeader(name); 37 } 38 39 public String encodeRedirectURL(String url) { 40 return response.encodeRedirectURL(url); 41 } 42 43 public String encodeRedirectUrl(String url) { 44 return response.encodeRedirectUrl(url); 45 } 46 47 public String encodeUrl(String url) { 48 return response.encodeUrl(url); 49 } 50 51 public String encodeURL(String url) { 52 return response.encodeURL(url); 53 } 54 55 public void flushBuffer() throws IOException { 56 response.flushBuffer(); 57 } 58 59 public int getBufferSize() { 60 return response.getBufferSize(); 61 } 62 63 public String getCharacterEncoding() { 64 return response.getCharacterEncoding(); 65 } 66 67 public Locale getLocale() { 68 return response.getLocale(); 69 } 70 71 public ServletOutputStream getOutputStream() throws IOException { 72 return response.getOutputStream(); 73 } 74 75 public PrintWriter getWriter() throws IOException { 76 return response.getWriter(); 77 } 78 79 public boolean isCommitted() { 80 return response.isCommitted(); 81 } 82 83 public void reset() { 84 response.reset(); 85 } 86 87 public void resetBuffer() { 88 response.resetBuffer(); 89 } 90 91 public void sendError(int sc) throws IOException { 92 response.sendError(sc); 93 } 94 95 public void sendError(int sc, String message) throws IOException { 96 response.sendError(sc, message); 97 } 98 99 public void sendRedirect(String location) throws IOException { 100 response.sendRedirect(location); 101 } 102 103 public void setBufferSize(int size) { 104 response.setBufferSize(size); 105 } 106 107 public void setContentLength(int length) { 108 response.setContentLength(length); 109 } 110 111 public void setContentType(String type) { 112 response.setContentType(type); 113 } 114 115 public void setDateHeader(String name, long value) { 116 response.setDateHeader(name, value); 117 } 118 119 public void setHeader(String name, String value) { 120 response.setHeader(name, value); 121 } 122 123 public void setIntHeader(String name, int value) { 124 response.setIntHeader(name, value); 125 } 126 127 public void setLocale(Locale locale) { 128 response.setLocale(locale); 129 } 130 131 public void setStatus(int sc) { 132 response.setStatus(sc); 133 } 134 135 public void setStatus(int sc, String message) { 136 response.setStatus(sc, message); 137 } 138 139 @Override 140 public String getContentType() { 141 // TODO Auto-generated method stub 142 return null; 143 } 144 145 @Override 146 public void setCharacterEncoding(String arg0) { 147 // TODO Auto-generated method stub 148 149 } 150 151 @Override 152 public void setContentLengthLong(long arg0) { 153 // TODO Auto-generated method stub 154 155 } 156 157 @Override 158 public int getStatus() { 159 // TODO Auto-generated method stub 160 return 0; 161 } 162 163 @Override 164 public String getHeader(String arg0) { 165 // TODO Auto-generated method stub 166 return null; 167 } 168 169 @Override 170 public Collection<String> getHeaders(String arg0) { 171 // TODO Auto-generated method stub 172 return null; 173 } 174 175 @Override 176 public Collection<String> getHeaderNames() { 177 // TODO Auto-generated method stub 178 return null; 179 } 180 }
- ScoketInputStream

1 package sub.connector.http; 2 3 import java.io.IOException; 4 5 6 import java.io.InputStream; 7 import java.io.EOFException; 8 import org.apache.catalina.util.StringManager; 9 10 /** 11 * Extends InputStream to be more efficient reading lines during HTTP 12 * header processing. 13 * 14 * @author <a href="mailto:remm@apache.org">Remy Maucherat</a> 15 * @deprecated 16 */ 17 public class SocketInputStream extends InputStream { 18 19 20 // -------------------------------------------------------------- Constants 21 22 23 /** 24 * CR. 25 */ 26 private static final byte CR = (byte) '\r'; 27 28 29 /** 30 * LF. 31 */ 32 private static final byte LF = (byte) '\n'; 33 34 35 /** 36 * SP. 37 */ 38 private static final byte SP = (byte) ' '; 39 40 41 /** 42 * HT. 43 */ 44 private static final byte HT = (byte) '\t'; 45 46 47 /** 48 * COLON. 49 */ 50 private static final byte COLON = (byte) ':'; 51 52 53 /** 54 * Lower case offset. 55 */ 56 private static final int LC_OFFSET = 'A' - 'a'; 57 58 59 /** 60 * Internal buffer. 61 */ 62 protected byte buf[]; 63 64 65 /** 66 * Last valid byte. 67 */ 68 protected int count; 69 70 71 /** 72 * Position in the buffer. 73 */ 74 protected int pos; 75 76 77 /** 78 * Underlying input stream. 79 */ 80 protected InputStream is; 81 82 83 // ----------------------------------------------------------- Constructors 84 85 86 /** 87 * Construct a servlet input stream associated with the specified socket 88 * input. 89 * 90 * @param is socket input stream 91 * @param bufferSize size of the internal buffer 92 */ 93 public SocketInputStream(InputStream is, int bufferSize) { 94 95 this.is = is; 96 buf = new byte[bufferSize]; 97 98 } 99 100 101 // -------------------------------------------------------------- Variables 102 103 104 /** 105 * The string manager for this package. 106 */ 107 protected static StringManager sm = 108 StringManager.getManager(Constants.Package); 109 110 111 // ----------------------------------------------------- Instance Variables 112 113 114 // --------------------------------------------------------- Public Methods 115 116 117 /** 118 * Read the request line, and copies it to the given buffer. This 119 * function is meant to be used during the HTTP request header parsing. 120 * Do NOT attempt to read the request body using it. 121 * 122 * @param requestLine Request line object 123 * @throws IOException If an exception occurs during the underlying socket 124 * read operations, or if the given buffer is not big enough to accomodate 125 * the whole line. 126 */ 127 public void readRequestLine(HttpRequestLine requestLine) 128 throws IOException { 129 130 // Recycling check 131 if (requestLine.methodEnd != 0) 132 requestLine.recycle(); 133 134 // Checking for a blank line 135 int chr = 0; 136 do { // Skipping CR or LF 137 try { 138 chr = read(); 139 } catch (IOException e) { 140 chr = -1; 141 } 142 } while ((chr == CR) || (chr == LF)); 143 if (chr == -1) 144 throw new EOFException 145 (sm.getString("requestStream.readline.error")); 146 pos--; 147 148 // Reading the method name 149 150 int maxRead = requestLine.method.length; 151 int readStart = pos; 152 int readCount = 0; 153 154 boolean space = false; 155 156 while (!space) { 157 // if the buffer is full, extend it 158 if (readCount >= maxRead) { 159 if ((2 * maxRead) <= HttpRequestLine.MAX_METHOD_SIZE) { 160 char[] newBuffer = new char[2 * maxRead]; 161 System.arraycopy(requestLine.method, 0, newBuffer, 0, 162 maxRead); 163 requestLine.method = newBuffer; 164 maxRead = requestLine.method.length; 165 } else { 166 throw new IOException 167 (sm.getString("requestStream.readline.toolong")); 168 } 169 } 170 // We're at the end of the internal buffer 171 if (pos >= count) { 172 int val = read(); 173 if (val == -1) { 174 throw new IOException 175 (sm.getString("requestStream.readline.error")); 176 } 177 pos = 0; 178 readStart = 0; 179 } 180 if (buf[pos] == SP) { 181 space = true; 182 } 183 requestLine.method[readCount] = (char) buf[pos]; 184 readCount++; 185 pos++; 186 } 187 188 requestLine.methodEnd = readCount - 1; 189 190 // Reading URI 191 192 maxRead = requestLine.uri.length; 193 readStart = pos; 194 readCount = 0; 195 196 space = false; 197 198 boolean eol = false; 199 200 while (!space) { 201 // if the buffer is full, extend it 202 if (readCount >= maxRead) { 203 if ((2 * maxRead) <= HttpRequestLine.MAX_URI_SIZE) { 204 char[] newBuffer = new char[2 * maxRead]; 205 System.arraycopy(requestLine.uri, 0, newBuffer, 0, 206 maxRead); 207 requestLine.uri = newBuffer; 208 maxRead = requestLine.uri.length; 209 } else { 210 throw new IOException 211 (sm.getString("requestStream.readline.toolong")); 212 } 213 } 214 // We're at the end of the internal buffer 215 if (pos >= count) { 216 int val = read(); 217 if (val == -1) 218 throw new IOException 219 (sm.getString("requestStream.readline.error")); 220 pos = 0; 221 readStart = 0; 222 } 223 if (buf[pos] == SP) { 224 space = true; 225 } else if ((buf[pos] == CR) || (buf[pos] == LF)) { 226 // HTTP/0.9 style request 227 eol = true; 228 space = true; 229 } 230 requestLine.uri[readCount] = (char) buf[pos]; 231 readCount++; 232 pos++; 233 } 234 235 requestLine.uriEnd = readCount - 1; 236 237 // Reading protocol 238 239 maxRead = requestLine.protocol.length; 240 readStart = pos; 241 readCount = 0; 242 243 while (!eol) { 244 // if the buffer is full, extend it 245 if (readCount >= maxRead) { 246 if ((2 * maxRead) <= HttpRequestLine.MAX_PROTOCOL_SIZE) { 247 char[] newBuffer = new char[2 * maxRead]; 248 System.arraycopy(requestLine.protocol, 0, newBuffer, 0, 249 maxRead); 250 requestLine.protocol = newBuffer; 251 maxRead = requestLine.protocol.length; 252 } else { 253 throw new IOException 254 (sm.getString("requestStream.readline.toolong")); 255 } 256 } 257 // We're at the end of the internal buffer 258 if (pos >= count) { 259 // Copying part (or all) of the internal buffer to the line 260 // buffer 261 int val = read(); 262 if (val == -1) 263 throw new IOException 264 (sm.getString("requestStream.readline.error")); 265 pos = 0; 266 readStart = 0; 267 } 268 if (buf[pos] == CR) { 269 // Skip CR. 270 } else if (buf[pos] == LF) { 271 eol = true; 272 } else { 273 requestLine.protocol[readCount] = (char) buf[pos]; 274 readCount++; 275 } 276 pos++; 277 } 278 279 requestLine.protocolEnd = readCount; 280 281 } 282 283 284 /** 285 * Read a header, and copies it to the given buffer. This 286 * function is meant to be used during the HTTP request header parsing. 287 * Do NOT attempt to read the request body using it. 288 * 289 * @param requestLine Request line object 290 * @throws IOException If an exception occurs during the underlying socket 291 * read operations, or if the given buffer is not big enough to accomodate 292 * the whole line. 293 */ 294 public void readHeader(HttpHeader header) 295 throws IOException { 296 297 // Recycling check 298 if (header.nameEnd != 0) 299 header.recycle(); 300 301 // Checking for a blank line 302 int chr = read(); 303 if ((chr == CR) || (chr == LF)) { // Skipping CR 304 if (chr == CR) 305 read(); // Skipping LF 306 header.nameEnd = 0; 307 header.valueEnd = 0; 308 return; 309 } else { 310 pos--; 311 } 312 313 // Reading the header name 314 315 int maxRead = header.name.length; 316 int readStart = pos; 317 int readCount = 0; 318 319 boolean colon = false; 320 321 while (!colon) { 322 // if the buffer is full, extend it 323 if (readCount >= maxRead) { 324 if ((2 * maxRead) <= HttpHeader.MAX_NAME_SIZE) { 325 char[] newBuffer = new char[2 * maxRead]; 326 System.arraycopy(header.name, 0, newBuffer, 0, maxRead); 327 header.name = newBuffer; 328 maxRead = header.name.length; 329 } else { 330 throw new IOException 331 (sm.getString("requestStream.readline.toolong")); 332 } 333 } 334 // We're at the end of the internal buffer 335 if (pos >= count) { 336 int val = read(); 337 if (val == -1) { 338 throw new IOException 339 (sm.getString("requestStream.readline.error")); 340 } 341 pos = 0; 342 readStart = 0; 343 } 344 if (buf[pos] == COLON) { 345 colon = true; 346 } 347 char val = (char) buf[pos]; 348 if ((val >= 'A') && (val <= 'Z')) { 349 val = (char) (val - LC_OFFSET); 350 } 351 header.name[readCount] = val; 352 readCount++; 353 pos++; 354 } 355 356 header.nameEnd = readCount - 1; 357 358 // Reading the header value (which can be spanned over multiple lines) 359 360 maxRead = header.value.length; 361 readStart = pos; 362 readCount = 0; 363 364 int crPos = -2; 365 366 boolean eol = false; 367 boolean validLine = true; 368 369 while (validLine) { 370 371 boolean space = true; 372 373 // Skipping spaces 374 // Note : Only leading white spaces are removed. Trailing white 375 // spaces are not. 376 while (space) { 377 // We're at the end of the internal buffer 378 if (pos >= count) { 379 // Copying part (or all) of the internal buffer to the line 380 // buffer 381 int val = read(); 382 if (val == -1) 383 throw new IOException 384 (sm.getString("requestStream.readline.error")); 385 pos = 0; 386 readStart = 0; 387 } 388 if ((buf[pos] == SP) || (buf[pos] == HT)) { 389 pos++; 390 } else { 391 space = false; 392 } 393 } 394 395 while (!eol) { 396 // if the buffer is full, extend it 397 if (readCount >= maxRead) { 398 if ((2 * maxRead) <= HttpHeader.MAX_VALUE_SIZE) { 399 char[] newBuffer = new char[2 * maxRead]; 400 System.arraycopy(header.value, 0, newBuffer, 0, 401 maxRead); 402 header.value = newBuffer; 403 maxRead = header.value.length; 404 } else { 405 throw new IOException 406 (sm.getString("requestStream.readline.toolong")); 407 } 408 } 409 // We're at the end of the internal buffer 410 if (pos >= count) { 411 // Copying part (or all) of the internal buffer to the line 412 // buffer 413 int val = read(); 414 if (val == -1) 415 throw new IOException 416 (sm.getString("requestStream.readline.error")); 417 pos = 0; 418 readStart = 0; 419 } 420 if (buf[pos] == CR) { 421 } else if (buf[pos] == LF) { 422 eol = true; 423 } else { 424 // FIXME : Check if binary conversion is working fine 425 int ch = buf[pos] & 0xff; 426 header.value[readCount] = (char) ch; 427 readCount++; 428 } 429 pos++; 430 } 431 432 int nextChr = read(); 433 434 if ((nextChr != SP) && (nextChr != HT)) { 435 pos--; 436 validLine = false; 437 } else { 438 eol = false; 439 // if the buffer is full, extend it 440 if (readCount >= maxRead) { 441 if ((2 * maxRead) <= HttpHeader.MAX_VALUE_SIZE) { 442 char[] newBuffer = new char[2 * maxRead]; 443 System.arraycopy(header.value, 0, newBuffer, 0, 444 maxRead); 445 header.value = newBuffer; 446 maxRead = header.value.length; 447 } else { 448 throw new IOException 449 (sm.getString("requestStream.readline.toolong")); 450 } 451 } 452 header.value[readCount] = ' '; 453 readCount++; 454 } 455 456 } 457 458 header.valueEnd = readCount; 459 460 } 461 462 463 /** 464 * Read byte. 465 */ 466 public int read() 467 throws IOException { 468 if (pos >= count) { 469 fill(); 470 if (pos >= count) 471 return -1; 472 } 473 return buf[pos++] & 0xff; 474 } 475 476 477 /** 478 * 479 */ 480 /* 481 public int read(byte b[], int off, int len) 482 throws IOException { 483 484 } 485 */ 486 487 488 /** 489 * 490 */ 491 /* 492 public long skip(long n) 493 throws IOException { 494 495 } 496 */ 497 498 499 /** 500 * Returns the number of bytes that can be read from this input 501 * stream without blocking. 502 */ 503 public int available() 504 throws IOException { 505 return (count - pos) + is.available(); 506 } 507 508 509 /** 510 * Close the input stream. 511 */ 512 public void close() 513 throws IOException { 514 if (is == null) 515 return; 516 is.close(); 517 is = null; 518 buf = null; 519 } 520 521 522 // ------------------------------------------------------ Protected Methods 523 524 525 /** 526 * Fill the internal buffer using data from the undelying input stream. 527 */ 528 protected void fill() 529 throws IOException { 530 pos = 0; 531 count = 0; 532 int nRead = is.read(buf, 0, buf.length); 533 if (nRead > 0) { 534 count = nRead; 535 } 536 } 537 538 539 }
- HttpRequestLine

1 package sub.connector.http; 2 /** 3 * HTTP request line enum type. 4 * 5 * @author Remy Maucherat 6 * @version $Revision: 1.6 $ $Date: 2002/03/18 07:15:40 $ 7 * @deprecated 8 */ 9 final class HttpRequestLine { 10 11 12 // -------------------------------------------------------------- Constants 13 14 15 public static final int INITIAL_METHOD_SIZE = 8; 16 public static final int INITIAL_URI_SIZE = 64; 17 public static final int INITIAL_PROTOCOL_SIZE = 8; 18 public static final int MAX_METHOD_SIZE = 1024; 19 public static final int MAX_URI_SIZE = 32768; 20 public static final int MAX_PROTOCOL_SIZE = 1024; 21 22 23 // ----------------------------------------------------------- Constructors 24 25 26 public HttpRequestLine() { 27 28 this(new char[INITIAL_METHOD_SIZE], 0, new char[INITIAL_URI_SIZE], 0, 29 new char[INITIAL_PROTOCOL_SIZE], 0); 30 31 } 32 33 34 public HttpRequestLine(char[] method, int methodEnd, 35 char[] uri, int uriEnd, 36 char[] protocol, int protocolEnd) { 37 38 this.method = method; 39 this.methodEnd = methodEnd; 40 this.uri = uri; 41 this.uriEnd = uriEnd; 42 this.protocol = protocol; 43 this.protocolEnd = protocolEnd; 44 45 } 46 47 48 // ----------------------------------------------------- Instance Variables 49 50 51 public char[] method; 52 public int methodEnd; 53 public char[] uri; 54 public int uriEnd; 55 public char[] protocol; 56 public int protocolEnd; 57 58 59 // ------------------------------------------------------------- Properties 60 61 62 // --------------------------------------------------------- Public Methods 63 64 65 /** 66 * Release all object references, and initialize instance variables, in 67 * preparation for reuse of this object. 68 */ 69 public void recycle() { 70 71 methodEnd = 0; 72 uriEnd = 0; 73 protocolEnd = 0; 74 75 } 76 77 78 /** 79 * Test if the uri includes the given char array. 80 */ 81 public int indexOf(char[] buf) { 82 return indexOf(buf, buf.length); 83 } 84 85 86 /** 87 * Test if the value of the header includes the given char array. 88 */ 89 public int indexOf(char[] buf, int end) { 90 char firstChar = buf[0]; 91 int pos = 0; 92 while (pos < uriEnd) { 93 pos = indexOf(firstChar, pos); 94 if (pos == -1) 95 return -1; 96 if ((uriEnd - pos) < end) 97 return -1; 98 for (int i = 0; i < end; i++) { 99 if (uri[i + pos] != buf[i]) 100 break; 101 if (i == (end-1)) 102 return pos; 103 } 104 pos++; 105 } 106 return -1; 107 } 108 109 110 /** 111 * Test if the value of the header includes the given string. 112 */ 113 public int indexOf(String str) { 114 return indexOf(str.toCharArray(), str.length()); 115 } 116 117 118 /** 119 * Returns the index of a character in the value. 120 */ 121 public int indexOf(char c, int start) { 122 for (int i=start; i<uriEnd; i++) { 123 if (uri[i] == c) 124 return i; 125 } 126 return -1; 127 } 128 129 130 // --------------------------------------------------------- Object Methods 131 132 133 public int hashCode() { 134 // FIXME 135 return 0; 136 } 137 138 139 public boolean equals(Object obj) { 140 return false; 141 } 142 143 144 }
- RequestStream

1 package sub.connector; 2 3 import sub.connector.http.Constants; 4 5 6 7 8 import sub.connector.http.HttpRequest; 9 import java.io.InputStream; 10 import java.io.IOException; 11 12 import javax.servlet.ReadListener; 13 import javax.servlet.ServletInputStream; 14 import org.apache.catalina.util.StringManager; 15 16 17 /** 18 * Convenience implementation of <b>ServletInputStream</b> that works with 19 * the standard implementations of <b>Request</b>. If the content length has 20 * been set on our associated Request, this implementation will enforce 21 * not reading more than that many bytes on the underlying stream. 22 * 23 * @author Craig R. McClanahan 24 * @version $Revision: 1.6 $ $Date: 2002/03/18 07:15:39 $ 25 * @deprecated 26 */ 27 28 public class RequestStream 29 extends ServletInputStream { 30 31 32 // ----------------------------------------------------------- Constructors 33 34 35 /** 36 * Construct a servlet input stream associated with the specified Request. 37 * 38 * @param request The associated request 39 */ 40 public RequestStream(HttpRequest request) { 41 42 super(); 43 closed = false; 44 count = 0; 45 length = request.getContentLength(); 46 stream = request.getStream(); 47 48 } 49 50 51 // ----------------------------------------------------- Instance Variables 52 53 54 /** 55 * Has this stream been closed? 56 */ 57 protected boolean closed = false; 58 59 60 /** 61 * The number of bytes which have already been returned by this stream. 62 */ 63 protected int count = 0; 64 65 66 /** 67 * The content length past which we will not read, or -1 if there is 68 * no defined content length. 69 */ 70 protected int length = -1; 71 72 73 /** 74 * The localized strings for this package. 75 */ 76 protected static StringManager sm = 77 StringManager.getManager(Constants.Package); 78 79 80 /** 81 * The underlying input stream from which we should read data. 82 */ 83 protected InputStream stream = null; 84 85 86 // --------------------------------------------------------- Public Methods 87 88 89 /** 90 * Close this input stream. No physical level I-O is performed, but 91 * any further attempt to read from this stream will throw an IOException. 92 * If a content length has been set but not all of the bytes have yet been 93 * consumed, the remaining bytes will be swallowed. 94 */ 95 public void close() throws IOException { 96 97 if (closed) 98 throw new IOException(sm.getString("requestStream.close.closed")); 99 100 if (length > 0) { 101 while (count < length) { 102 int b = read(); 103 if (b < 0) 104 break; 105 } 106 } 107 108 closed = true; 109 110 } 111 112 113 114 /** 115 * Read and return a single byte from this input stream, or -1 if end of 116 * file has been encountered. 117 * 118 * @exception IOException if an input/output error occurs 119 */ 120 public int read() throws IOException { 121 122 // Has this stream been closed? 123 if (closed) 124 throw new IOException(sm.getString("requestStream.read.closed")); 125 126 // Have we read the specified content length already? 127 if ((length >= 0) && (count >= length)) 128 return (-1); // End of file indicator 129 130 // Read and count the next byte, then return it 131 int b = stream.read(); 132 if (b >= 0) 133 count++; 134 return (b); 135 136 } 137 138 139 /** 140 * Read some number of bytes from the input stream, and store them 141 * into the buffer array b. The number of bytes actually read is 142 * returned as an integer. This method blocks until input data is 143 * available, end of file is detected, or an exception is thrown. 144 * 145 * @param b The buffer into which the data is read 146 * 147 * @exception IOException if an input/output error occurs 148 */ 149 public int read(byte b[]) throws IOException { 150 151 return (read(b, 0, b.length)); 152 153 } 154 155 156 /** 157 * Read up to <code>len</code> bytes of data from the input stream 158 * into an array of bytes. An attempt is made to read as many as 159 * <code>len</code> bytes, but a smaller number may be read, 160 * possibly zero. The number of bytes actually read is returned as 161 * an integer. This method blocks until input data is available, 162 * end of file is detected, or an exception is thrown. 163 * 164 * @param b The buffer into which the data is read 165 * @param off The start offset into array <code>b</code> at which 166 * the data is written 167 * @param len The maximum number of bytes to read 168 * 169 * @exception IOException if an input/output error occurs 170 */ 171 public int read(byte b[], int off, int len) throws IOException { 172 173 int toRead = len; 174 if (length > 0) { 175 if (count >= length) 176 return (-1); 177 if ((count + len) > length) 178 toRead = length - count; 179 } 180 int actuallyRead = super.read(b, off, toRead); 181 return (actuallyRead); 182 183 } 184 185 186 187 @Override 188 public boolean isFinished() { 189 // TODO Auto-generated method stub 190 return false; 191 } 192 193 194 195 @Override 196 public boolean isReady() { 197 // TODO Auto-generated method stub 198 return false; 199 } 200 201 202 203 @Override 204 public void setReadListener(ReadListener arg0) { 205 // TODO Auto-generated method stub 206 207 } 208 209 210 }
- ResponseStream
代码清单
- ResponseWriter

1 package sub.connector; 2 3 import java.io.OutputStreamWriter; 4 import java.io.PrintWriter; 5 6 /** 7 * A subclass of PrintWriter that automatically flushes each time 8 * a print() or println() method is called. 9 */ 10 11 public class ResponseWriter extends PrintWriter { 12 13 public ResponseWriter(OutputStreamWriter writer) { 14 super(writer); 15 } 16 17 public void print(boolean b) { 18 super.print(b); 19 super.flush(); 20 } 21 22 public void print(char c) { 23 super.print(c); 24 super.flush(); 25 } 26 27 public void print(char ca[]) { 28 super.print(ca); 29 super.flush(); 30 } 31 32 public void print(double d) { 33 super.print(d); 34 super.flush(); 35 } 36 37 public void print(float f) { 38 super.print(f); 39 super.flush(); 40 } 41 42 public void print(int i) { 43 super.print(i); 44 super.flush(); 45 } 46 47 public void print(long l) { 48 super.print(l); 49 super.flush(); 50 } 51 52 public void print(Object o) { 53 super.print(o); 54 super.flush(); 55 } 56 57 public void print(String s) { 58 super.print(s); 59 super.flush(); 60 } 61 62 public void println() { 63 super.println(); 64 super.flush(); 65 } 66 67 public void println(boolean b) { 68 super.println(b); 69 super.flush(); 70 } 71 72 public void println(char c) { 73 super.println(c); 74 super.flush(); 75 } 76 77 public void println(char ca[]) { 78 super.println(ca); 79 super.flush(); 80 } 81 82 public void println(double d) { 83 super.println(d); 84 super.flush(); 85 } 86 87 public void println(float f) { 88 super.println(f); 89 super.flush(); 90 } 91 92 public void println(int i) { 93 super.println(i); 94 super.flush(); 95 } 96 97 public void println(long l) { 98 super.println(l); 99 super.flush(); 100 } 101 102 public void println(Object o) { 103 super.println(o); 104 super.flush(); 105 } 106 107 public void println(String s) { 108 super.println(s); 109 super.flush(); 110 } 111 112 public void write(char c) { 113 super.write(c); 114 super.flush(); 115 } 116 117 public void write(char ca[]) { 118 super.write(ca); 119 super.flush(); 120 } 121 122 public void write(char ca[], int off, int len) { 123 super.write(ca, off, len); 124 super.flush(); 125 } 126 127 public void write(String s) { 128 super.write(s); 129 super.flush(); 130 } 131 132 public void write(String s, int off, int len) { 133 super.write(s, off, len); 134 super.flush(); 135 } 136 }
- ServletProcessor

1 package sub; 2 import sub.connector.http.Constants; 3 import sub.connector.http.HttpRequest; 4 import sub.connector.http.HttpResponse; 5 import sub.connector.http.HttpRequestFacade; 6 import sub.connector.http.HttpResponseFacade; 7 8 import java.io.File; 9 import java.io.IOException; 10 import java.net.URL; 11 import java.net.URLClassLoader; 12 import java.net.URLStreamHandler; 13 import javax.servlet.Servlet; 14 /** 15 * servlet处理器负责动态加载servlet组件,并管理servlet的生命周期,传递res、req给其。 16 * */ 17 public class ServletProcessor{ 18 19 public void process(HttpRequest request, HttpResponse response) { 20 21 String uri = request.getRequestURI(); 22 String servletName = uri.substring(uri.lastIndexOf("/") + 1); 23 URLClassLoader loader = null; 24 try { 25 // create a URLClassLoader 26 URL[] urls = new URL[1]; 27 URLStreamHandler streamHandler = null; 28 File classPath = new File(Constants.WEB_ROOT); 29 String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString() ; 30 urls[0] = new URL(null, repository, streamHandler); 31 loader = new URLClassLoader(urls); 32 } 33 catch (IOException e) { 34 System.out.println(e.toString() ); 35 } 36 Class myClass = null; 37 try { 38 myClass = loader.loadClass(servletName); 39 } 40 catch (ClassNotFoundException e) { 41 System.out.println(e.toString()); 42 } 43 44 Servlet servlet = null; 45 46 try { 47 servlet = (Servlet) myClass.newInstance(); 48 HttpRequestFacade requestFacade = new HttpRequestFacade(request); 49 HttpResponseFacade responseFacade = new HttpResponseFacade(response); 50 servlet.service(requestFacade, responseFacade); 51 ((HttpResponse) response).finishResponse(); 52 } 53 catch (Exception e) { 54 System.out.println(e.toString()); 55 } 56 catch (Throwable e) { 57 System.out.println(e.toString()); 58 } 59 } 60 }
- StaticResourceProcessor

1 package sub; 2 import sub.connector.http.HttpRequest; 3 import sub.connector.http.HttpResponse; 4 import java.io.IOException; 5 6 public class StaticResourceProcessor { 7 8 public void process(HttpRequest request, HttpResponse response) { 9 try { 10 response.sendStaticResource(); 11 } 12 catch (IOException e) { 13 e.printStackTrace(); 14 } 15 } 16 17 }