当前位置: 代码迷 >> 综合 >> 《How Tomcat Works》学习(四)——连接器(二)——解析http头部参数
  详细解决方案

《How Tomcat Works》学习(四)——连接器(二)——解析http头部参数

热度:89   发布时间:2024-01-09 01:54:22.0

前言

上文已经对路径及请求参数进行了解析,本文会对头部的参数,如cookie、content-length、content-type进行解析

 

程序

HttpRequest类增加以下代码:

public class HttpRequest implements HttpServletRequest {//......private int contentLength;private String contentType;protected ArrayList<Cookie> cookies =  new ArrayList<Cookie>();//......public void parseHeader() throws ServletException {int i = 0;byte[] buffer = new byte[2048];try {while (true) {input.read(buffer, i, 1);if (buffer[i] == '\r') {i++;input.read(buffer, i, 1);if (buffer[i] == '\n') {i++;input.read(buffer, i, 1);if (buffer[i] == '\r') {i++;input.read(buffer, i, 1);if (buffer[i] == '\n') {break;}}}}i++;}String header = new String(buffer);while (true) {int index = header.indexOf("\r\n");if (index > 0) {String line = header.substring(0, index);header = header.substring(index + 2);int index1 = line.indexOf(":");if (index1 > 0) {String key = line.substring(0, index1);String value = line.substring(index1 + 1).trim();if ("cookie".equals(key.toLowerCase())) {Cookie cookieArray[] = RequestUtil.parseCookieHeader(value);synchronized (cookies) {for (Cookie cookie : cookieArray) {cookies.add(cookie);}}} else if ("content-length".equals(key.toLowerCase())) {int n = -1;try {n = Integer.parseInt(value);} catch (Exception e) {throw new ServletException("httpProcessor.parseHeaders.contentLength");}this.setContentLength(n);} else if("content-type".equals(key.toLowerCase())) {this.setContentType(value);}}} else {break;}}} catch (IOException e) {e.printStackTrace();i = -1;}}public void setContentLength(int length) {this.contentLength = length;}@Overridepublic int getContentLength() {return contentLength;}public void setContentType(String contentType) {this.contentType = contentType;}@Overridepublic String getContentType() {return contentType;}@Overridepublic Cookie[] getCookies() {synchronized (cookies) {if (cookies.size() < 1)return (null);Cookie results[] = new Cookie[cookies.size()];return ((Cookie[]) cookies.toArray(results));}}//......}

第5-7行为本次要解析的http头部参数。11-33行代码写得比较憋足,主要是表示当遇到两个"\r\n"后,http头部内容结束。37-40行按行截取内容。41-44行根据“:”冒号分割key和value值。45-51行当key值为“cookie”时,通过RequestUtil.parseCookieHeader函数解析cookie并添加到HttpRequest的cookies数组中。在RequestUtil我们添加如下代码:

public class RequestUtil {//......public static Cookie[] parseCookieHeader(String header) {if ((header == null) || (header.length() < 1))return (new Cookie[0]);ArrayList cookies = new ArrayList();while (header.length() > 0) {int semicolon = header.indexOf(';');if (semicolon < 0)semicolon = header.length();if (semicolon == 0)break;String token = header.substring(0, semicolon);if (semicolon < header.length())header = header.substring(semicolon + 1);elseheader = "";try {int equals = token.indexOf('=');if (equals > 0) {String name = token.substring(0, equals).trim();String value = token.substring(equals + 1).trim();cookies.add(new Cookie(name, value));}} catch (Throwable e) {;}}return ((Cookie[]) cookies.toArray(new Cookie[cookies.size()]));}
}

多条cookie根据“;”分号进行分割,单条cookie根据“=”等号进行name和value的分割。

最后我们通过之前的ModernServlet.java获取cookies看看:

public class ModernServlet extends HttpServlet {public void init(ServletConfig config) {System.out.println("ModernServlet -- init");}public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html");PrintWriter out = response.getWriter();out.print("HTTP/1.1 200 OK\r\n\r\n");out.println("<html>");out.println("<head>");out.println("<title>Modern Servlet</title>");out.println("</head>");out.println("<body>");out.println("<br><h2>Method</h2");out.println("<br>" + request.getMethod());out.println("<br><h2>Query String</h2");out.println("<br>" + request.getQueryString());out.println("<br><h2>Request URI</h2");out.println("<br>" + request.getRequestURI());out.println("<br><h2>Request Protocol</h2");out.println("<br>" + request.getProtocol());out.println("<br><h2>Cookies</h2>");Cookie[] cookies = request.getCookies();for(Cookie cookie : cookies) {out.println("<br>" + cookie.getName() + " : " + cookie.getValue());}out.println("</body>");out.println("</html>");}
}

之后启动程序,在chrome浏览器中按f12弹出开发者工具,然后在如下地方添加访问用cookie:

之后访问对应servlet,http://localhost:8080/servlet/ModernServlet?username=jack&password=123456,得到

成功获取cookies。content-length和content-type获取方式比较简单,就不列举了。

 

小结

通过两篇文章,简单描述了连接器解析http头部的过程。实际tomcat的处理更为复杂,代码封装也更好。希望通过本文抛砖引玉的方式,可以引导读者更深入学习tomcat的连接器源码。

  相关解决方案