private IntegerHolder parse16BitInteger(ByteBuffer buf, AjpParseState state) { if (!buf.hasRemaining()) { return new IntegerHolder(-1, false); } int number = state.currentIntegerPart; if (number == -1) { number = (buf.get() & 0xFF); } if (buf.hasRemaining()) { final byte b = buf.get(); int result = ((0xFF & number) << 8) + (b & 0xFF); state.currentIntegerPart = -1; return new IntegerHolder(result, true); } else { state.currentIntegerPart = number; return new IntegerHolder(-1, false); } }
private StringHolder parseString(ByteBuffer buf, AjpParseState state, boolean header) { if (!buf.hasRemaining()) { return new StringHolder(null, false); } int stringLength = state.stringLength; if (stringLength == -1) { int number = buf.get() & 0xFF; if (buf.hasRemaining()) { final byte b = buf.get(); stringLength = ((0xFF & number) << 8) + (b & 0xFF); } else { state.stringLength = number | STRING_LENGTH_MASK; return new StringHolder(null, false); } } else if ((stringLength & STRING_LENGTH_MASK) != 0) { int number = stringLength & ~STRING_LENGTH_MASK; stringLength = ((0xFF & number) << 8) + (buf.get() & 0xFF); } if (header && (stringLength & 0xFF00) != 0) { state.stringLength = -1; return new StringHolder(HTTP_HEADERS[stringLength & 0xFF]); } if (stringLength == 0xFFFF) { // OxFFFF means null state.stringLength = -1; return new StringHolder(null, true); } StringBuilder builder = state.currentString; if (builder == null) { builder = new StringBuilder(); state.currentString = builder; } int length = builder.length(); while (length < stringLength) { if (!buf.hasRemaining()) { state.stringLength = stringLength; return new StringHolder(null, false); } builder.append((char) buf.get()); ++length; } if (buf.hasRemaining()) { buf.get(); // null terminator state.currentString = null; state.stringLength = -1; return new StringHolder(builder.toString(), true); } else { return new StringHolder(null, false); } }
public void parse( final ByteBuffer buf, final AjpParseState state, final HttpServerExchange exchange) { if (!buf.hasRemaining()) { return; } switch (state.state) { case AjpParseState.BEGIN: { IntegerHolder result = parse16BitInteger(buf, state); if (!result.readComplete) { return; } else { if (result.value != 0x1234) { throw new IllegalStateException("Wrong magic number"); } } } case AjpParseState.READING_DATA_SIZE: { IntegerHolder result = parse16BitInteger(buf, state); if (!result.readComplete) { state.state = AjpParseState.READING_DATA_SIZE; return; } else { state.dataSize = result.value; } } case AjpParseState.READING_PREFIX_CODE: { if (!buf.hasRemaining()) { state.state = AjpParseState.READING_PREFIX_CODE; return; } else { final byte prefix = buf.get(); if (prefix != 2) { throw new IllegalArgumentException( "We do not support prefix codes other than 2 yet. Received: " + prefix); } } } case AjpParseState.READING_METHOD: { if (!buf.hasRemaining()) { state.state = AjpParseState.READING_METHOD; return; } else { int method = buf.get(); if (method > 0 && method < 28) { exchange.setRequestMethod(HTTP_METHODS[method]); } else { throw new IllegalArgumentException("Unknown method type " + method); } } } case AjpParseState.READING_PROTOCOL: { StringHolder result = parseString(buf, state, false); if (result.readComplete) { // TODO: more efficient way of doing this exchange.setProtocol(HttpString.tryFromString(result.value)); } else { state.state = AjpParseState.READING_PROTOCOL; return; } } case AjpParseState.READING_REQUEST_URI: { StringHolder result = parseString(buf, state, false); if (result.readComplete) { String res = result.value; exchange.setRequestPath(res); exchange.setRelativePath(res); } else { state.state = AjpParseState.READING_REQUEST_URI; return; } } case AjpParseState.READING_REMOTE_ADDR: { StringHolder result = parseString(buf, state, false); if (result.readComplete) { // exchange.setRequestURI(result.value); } else { state.state = AjpParseState.READING_REMOTE_ADDR; return; } } case AjpParseState.READING_REMOTE_HOST: { StringHolder result = parseString(buf, state, false); if (result.readComplete) { // exchange.setRequestURI(result.value); } else { state.state = AjpParseState.READING_REMOTE_HOST; return; } } case AjpParseState.READING_SERVER_NAME: { StringHolder result = parseString(buf, state, false); if (result.readComplete) { // exchange.setRequestURI(result.value); } else { state.state = AjpParseState.READING_SERVER_NAME; return; } } case AjpParseState.READING_SERVER_PORT: { IntegerHolder result = parse16BitInteger(buf, state); if (result.readComplete) { // exchange.setRequestURI(result.value); } else { state.state = AjpParseState.READING_SERVER_PORT; return; } } case AjpParseState.READING_IS_SSL: { if (!buf.hasRemaining()) { state.state = AjpParseState.READING_IS_SSL; return; } else { final byte isSsl = buf.get(); } } case AjpParseState.READING_NUM_HEADERS: { IntegerHolder result = parse16BitInteger(buf, state); if (!result.readComplete) { state.state = AjpParseState.READING_NUM_HEADERS; return; } else { state.numHeaders = result.value; } } case AjpParseState.READING_HEADERS: { int readHeaders = exchange.getRequestHeaders().getHeaderNames().size(); while (readHeaders < state.numHeaders) { if (state.currentHeader == null) { StringHolder result = parseString(buf, state, true); if (!result.readComplete) { state.state = AjpParseState.READING_HEADERS; return; } if (result.header != null) { state.currentHeader = result.header; } else { state.currentHeader = HttpString.tryFromString(result.value); } } StringHolder result = parseString(buf, state, false); if (!result.readComplete) { state.state = AjpParseState.READING_HEADERS; return; } exchange.getRequestHeaders().add(state.currentHeader, result.value); state.currentHeader = null; ++readHeaders; } } case AjpParseState.READING_ATTRIBUTES: { for (; ; ) { if (state.currentAttribute == null && state.currentIntegerPart == -1) { if (!buf.hasRemaining()) { state.state = AjpParseState.READING_ATTRIBUTES; return; } int val = (0xFF & buf.get()); if (val == 0xFF) { state.state = AjpParseState.DONE; return; } else if (val == 0x0A) { // we need to read the name. We overload currentIntegerPart to avoid adding another // state field state.currentIntegerPart = 1; } else { state.currentAttribute = ATTRIBUTES[val]; } } if (state.currentIntegerPart == 1) { StringHolder result = parseString(buf, state, false); if (!result.readComplete) { state.state = AjpParseState.READING_ATTRIBUTES; return; } state.currentAttribute = result.value; state.currentIntegerPart = -1; } StringHolder result = parseString(buf, state, false); if (!result.readComplete) { state.state = AjpParseState.READING_ATTRIBUTES; return; } // query string. if (state.currentAttribute.equals(ATTRIBUTES[5])) { String res = result.value; exchange.setQueryString(res); int stringStart = 0; String attrName = null; for (int i = 0; i < res.length(); ++i) { char c = res.charAt(i); if (c == '=' && attrName == null) { attrName = res.substring(stringStart, i); stringStart = i + 1; } else if (c == '&') { if (attrName != null) { exchange.addQueryParam(attrName, res.substring(stringStart, i)); } else { exchange.addQueryParam(res.substring(stringStart, i), ""); } stringStart = i + 1; attrName = null; } } if (attrName != null) { exchange.addQueryParam(attrName, res.substring(stringStart, res.length())); } else if (res.length() != stringStart) { exchange.addQueryParam(res.substring(stringStart, res.length()), ""); } } // TODO: do something with the attributes state.currentAttribute = null; } } } state.state = AjpParseState.DONE; }