/** * Parses a header value. This is called from the generated bytecode. * * @param buffer The buffer * @param remaining The number of bytes remaining * @param state The current state * @param builder The exchange builder * @return The number of bytes remaining */ @SuppressWarnings("unused") final int handleHeaderValue( ByteBuffer buffer, int remaining, ParseState state, HttpExchangeBuilder builder) { StringBuilder stringBuilder = state.stringBuilder; if (stringBuilder == null) { stringBuilder = new StringBuilder(); } int parseState = state.parseState; while (remaining > 0) { final byte next = buffer.get(); --remaining; switch (parseState) { case NORMAL: { if (next == '\r') { parseState = BEGIN_LINE_END; } else if (next == '\n') { parseState = LINE_END; } else if (next == ' ' || next == '\t') { parseState = WHITESPACE; } else { stringBuilder.append((char) next); } break; } case WHITESPACE: { if (next == '\r') { parseState = BEGIN_LINE_END; } else if (next == '\n') { parseState = LINE_END; } else if (next == ' ' || next == '\t') { } else { if (stringBuilder.length() > 0) { stringBuilder.append(' '); } stringBuilder.append((char) next); parseState = NORMAL; } break; } case LINE_END: case BEGIN_LINE_END: { if (next == '\n' && parseState == BEGIN_LINE_END) { parseState = LINE_END; } else if (next == '\t' || next == ' ') { // this is a continuation parseState = WHITESPACE; } else { // we have a header String nextStandardHeader = state.nextHeader; builder.headers.put(nextStandardHeader, stringBuilder.toString()); state.nextHeader = null; state.leftOver = next; state.stringBuilder = null; if (next == '\r') { parseState = AWAIT_DATA_END; } else { state.state = ParseState.HEADER; state.parseState = 0; return remaining; } } break; } case AWAIT_DATA_END: { state.state = ParseState.PARSE_COMPLETE; return remaining; } } } // we only write to the state if we did not finish parsing state.parseState = parseState; state.stringBuilder = stringBuilder; return remaining; }
/** * Parses a path value. This is called from the generated bytecode. * * @param buffer The buffer * @param remaining The number of bytes remaining * @param state The current state * @param builder The exchange builder * @return The number of bytes remaining */ @SuppressWarnings("unused") final int handlePath( ByteBuffer buffer, int remaining, ParseState state, HttpExchangeBuilder builder) { StringBuilder stringBuilder = state.stringBuilder; int parseState = state.parseState; int canonicalPathStart = state.pos; int queryParamPos = state.queryParamPos; String nextQueryParam = state.nextHeader; if (stringBuilder == null) { state.stringBuilder = stringBuilder = new StringBuilder(); } while (remaining > 0) { final char next = (char) buffer.get(); --remaining; if (next == ' ' || next == '\t') { if (stringBuilder.length() != 0) { final String path = stringBuilder.toString(); builder.fullPath = path; if (parseState < HOST_DONE) { builder.relativePath = path; } else { builder.relativePath = path.substring(canonicalPathStart); } if (parseState == QUERY_PARAM_NAME) { builder.addQueryParam(stringBuilder.substring(queryParamPos), ""); } else if (parseState == QUERY_PARAM_VALUE) { builder.addQueryParam(nextQueryParam, stringBuilder.substring(queryParamPos)); } state.state = ParseState.VERSION; state.stringBuilder = null; state.parseState = 0; state.pos = 0; state.nextHeader = null; state.queryParamPos = 0; return remaining; } } else { if (next == ':' && parseState == START) { parseState = FIRST_COLON; } else if (next == '/' && parseState == FIRST_COLON) { parseState = FIRST_SLASH; } else if (next == '/' && parseState == FIRST_SLASH) { parseState = SECOND_SLASH; } else if (next == '/' && parseState == SECOND_SLASH) { parseState = HOST_DONE; canonicalPathStart = stringBuilder.length(); } else if (parseState == FIRST_COLON || parseState == FIRST_SLASH) { parseState = START; } else if (next == '?' && (parseState == START || parseState == HOST_DONE)) { parseState = QUERY_PARAM_NAME; queryParamPos = stringBuilder.length() + 1; } else if (next == '=' && parseState == QUERY_PARAM_NAME) { parseState = QUERY_PARAM_VALUE; nextQueryParam = stringBuilder.substring(queryParamPos); queryParamPos = stringBuilder.length() + 1; } else if (next == '&' && parseState == QUERY_PARAM_NAME) { parseState = QUERY_PARAM_NAME; builder.addQueryParam(stringBuilder.substring(queryParamPos), ""); nextQueryParam = null; queryParamPos = stringBuilder.length() + 1; } else if (next == '&' && parseState == QUERY_PARAM_VALUE) { parseState = QUERY_PARAM_NAME; builder.addQueryParam(nextQueryParam, stringBuilder.substring(queryParamPos)); nextQueryParam = null; queryParamPos = stringBuilder.length() + 1; } stringBuilder.append(next); } } state.stringBuilder = stringBuilder; state.parseState = parseState; state.pos = canonicalPathStart; state.nextHeader = nextQueryParam; state.queryParamPos = queryParamPos; return remaining; }