package org.jboss.pitbull.internal.nio.http; import org.jboss.pitbull.OrderedHeaders; import java.nio.ByteBuffer; /** * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @version $Revision: 1 $ */ public abstract class HttpMessageDecoder { //space ' ' protected static final byte SP = 32; //tab ' ' protected static final byte HT = 9; /** * Carriage return */ protected static final byte CR = 13; /** * Equals '=' */ protected static final byte EQUALS = 61; /** * Line feed character */ protected static final byte LF = 10; /** * carriage return line feed */ protected static final byte[] CRLF = new byte[]{CR, LF}; /** * Colon ':' */ protected static final byte COLON = 58; /** * Semicolon ';' */ protected static final byte SEMICOLON = 59; /** * comma ',' */ protected static final byte COMMA = 44; protected static final byte DOUBLE_QUOTE = '"'; protected StringBuilder currentString = new StringBuilder(64); protected String currentHeaderName; protected String currentHeaderValue; protected States currentState = States.SKIP_CONTROL_CHARS; protected interface State { boolean process(HttpMessageDecoder decoder, ByteBuffer buffer); } protected enum States implements State { SKIP_CONTROL_CHARS { @Override public boolean process(HttpMessageDecoder decoder, ByteBuffer buffer) { return decoder.skipControlChars(buffer); } }, READ_INITIAL { @Override public boolean process(HttpMessageDecoder decoder, ByteBuffer buffer) { return decoder.readInitial(buffer); } }, READ_HEADERS { @Override public boolean process(HttpMessageDecoder decoder, ByteBuffer buffer) { return decoder.readHeader(buffer); } }, DONE { @Override public boolean process(HttpMessageDecoder decoder, ByteBuffer buffer) { return false; } } } /** * @param buffer must be flipped */ public boolean process(ByteBuffer buffer) { if (currentState == States.DONE) return true; while (currentState.process(this, buffer)) ; if (currentState == States.DONE) return true; return false; } protected abstract OrderedHeaders getHeaders(); protected boolean readHeader(ByteBuffer buffer) { for (; ; ) { String line = readLine(buffer); if (line == null) return false; if (line.length() == 0) { if (currentHeaderName != null && currentHeaderValue != null) { getHeaders().addHeader(currentHeaderName, currentHeaderValue); } currentState = States.DONE; return false; } else { char first = line.charAt(0); if (currentHeaderName != null && (first == ' ' || first == '\t')) { currentHeaderValue += ' ' + line.trim(); } else { if (currentHeaderName != null) { getHeaders().addHeader(currentHeaderName, currentHeaderValue); currentHeaderName = null; currentHeaderValue = null; } String[] split = splitHeader(line); currentHeaderName = split[0]; currentHeaderValue = split[1]; } } } } protected abstract boolean readInitial(ByteBuffer buffer); protected String readLine(ByteBuffer buffer) { String line = null; while (buffer.hasRemaining()) { byte b = buffer.get(); if (b == LF) { // strip out \r if (currentString.length() > 0 && currentString.charAt(currentString.length() - 1) == '\r') currentString.setLength(currentString.length() - 1); line = currentString.toString(); currentString = new StringBuilder(); break; } else { currentString.append((char) b); } } return line; } protected boolean skipControlChars(ByteBuffer buffer) { while (buffer.hasRemaining()) { char c = (char) buffer.get(); if (!Character.isISOControl(c) && !Character.isWhitespace(c)) { buffer.position(buffer.position() - 1); currentState = States.READ_INITIAL; return true; } } return false; } protected String[] splitHeader(String sb) { final int length = sb.length(); int nameStart; int nameEnd; int colonEnd; int valueStart; int valueEnd; nameStart = findNonWhitespace(sb, 0); for (nameEnd = nameStart; nameEnd < length; nameEnd++) { char ch = sb.charAt(nameEnd); if (ch == ':' || Character.isWhitespace(ch)) { break; } } for (colonEnd = nameEnd; colonEnd < length; colonEnd++) { if (sb.charAt(colonEnd) == ':') { colonEnd++; break; } } valueStart = findNonWhitespace(sb, colonEnd); if (valueStart == length) { return new String[]{ sb.substring(nameStart, nameEnd), "" }; } valueEnd = findEndOfString(sb); return new String[]{ sb.substring(nameStart, nameEnd), sb.substring(valueStart, valueEnd) }; } protected int findNonWhitespace(String sb, int offset) { int result; for (result = offset; result < sb.length(); result++) { if (!Character.isWhitespace(sb.charAt(result))) { break; } } return result; } protected int findWhitespace(String sb, int offset) { int result; for (result = offset; result < sb.length(); result++) { if (Character.isWhitespace(sb.charAt(result))) { break; } } return result; } protected int findEndOfString(String sb) { int result; for (result = sb.length(); result > 0; result--) { if (!Character.isWhitespace(sb.charAt(result - 1))) { break; } } return result; } }