Coder 爱翻译 How Tomcat Works 第三章 第三部分
Parsing Headers
一个HttpHeader类代表了一个HTTP的头部信息。这个类将在第四章讲解。现在,我们了解以下内容就足够:
?你可以通过使用它的无参构造函数来创建一个HttpHeader实例。
?一旦你有一个HttpHeader实例,你可以把它传递给SocketInputStream的readHeader方法。如果有头部信息可读的话,readHeader方法将相应地填充好HttpHeader对象。如果没有头部信息可读,HttpHeader实例的nameEnd和valueEnd字段都将为0。
?获取头部信息的名字和值,使用下面的方法:
String name = new String (header.name, 0, header.nameEnd);
String value = new String(header.value, 0, header.valueEnd);
parseHeader方法包含一个while循环持续从SocketInputStream读取头部信息,直到读取完所有的头部信息。这个循环在创建一个HttpHeader实例,并把它传递给SocketInputStream类的readHeader后开始执行:
HttpHeader header = new HttpHeader();
// Read the next header
input.readHeader(header);
然后,你可以测试在输入流中是否有下一个头部信息可读。使用HttpHeader实例的nameEnd和valueEnd字段:
if (header.nameEnd == 0) {
if (header.valueEnd == 0) {
return;
} else {
throw new ServletException (sm.getString("httpProcessor.parseHeaders.colon"));
}
}
如果有下一个头部信息,这个头部信息的name和value可以被获取:
String name = new String(header.name, 0, header.nameEnd);
String value = new String(header.value, 0, header.valueEnd);
一旦你得到了头部name和value。你调用addHeader方法把它添加到HttpRequest对象中的头部信息HashMap中。
request.addHeader(name, value);
一些头部信息也需要设置一些属性。例如:当servlet调用javax.servlet.ServletRequest的getContentLength方法,content-length头部信息的值被返回,cookie头部信息包含cookies被添加到cookie集合中。下面是处理过程:
if (name.equals("cookie")) { ... // process cookies here } else if (name.equals("content-length")) { int n = -1; try { n = Integer.parseInt (value); } catch (Exception e) { throw new ServletException(sm.getString( "httpProcessor.parseHeaders.contentLength")); } request.setContentLength(n); }else if (name.equals("content-type")) { request.setContentType(value); }Listing 3.5: The org.apache.catalina.util.RequestUtil class's parseCookieHeader method public static Cookie[] parseCookieHeader(String header) { if ((header == null) || (header.length 0 < 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); else header = ""; 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 ()])); }Listing 3.6: The org.apache.Catalina.util.ParameterMap class. package org.apache.catalina.util; import java.util.HashMap; import java.util.Map; public final class ParameterMap extends HashMap { public ParameterMap() { super (); } public ParameterMap(int initialCapacity) { super(initialCapacity); } public ParameterMap(int initialCapacity, float loadFactor) { super(initialCapacity, loadFactor); } public ParameterMap(Map map) { super(map); } private boolean locked = false; public boolean isLocked() { return (this.locked); } public void setLocked(boolean locked) { this.locked = locked; } private static final StringManager sm = StringManager.getManager("org.apache.catalina.util"); public void clear() { if (locked) throw new IllegalStateException (sm.getString("parameterMap.locked")); super.clear(); } public Object put(Object key, Object value) { if (locked) throw new IllegalStateException (sm.getString("parameterMap.locked")); return (super.put(key, value)); } public void putAll(Map map) { if (locked) throw new IllegalStateException (sm.getString("parameterMap.locked")); super.putAll(map); } public Object remove(Object key) { if (locked) throw new IllegalStateException (sm.getString("parameterMap.locked")); return (super.remove(key)); }} // Parse any parameters specified in the input stream String contentType = 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(getMethod()) && (getContentLength() > 0) && "application/x-www-form-urlencoded".equals(contentType)) { try { int max = getContentLength();int len = 0; byte buf[] = new byte[getContentLength()]; ServletInputStream is = getInputStream(); 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"); } RequestUtil.parseParameters(results, buf, encoding); } catch (UnsupportedEncodingException ue) { ; } catch (IOException e) { throw new RuntimeException("Content read fail"); } }