use of io.undertow.util.HeaderValues in project undertow by undertow-io.
the class HpackEncoder method encode.
/**
* Encodes the headers into a buffer.
*
* @param headers
* @param target
*/
public State encode(HeaderMap headers, ByteBuffer target) {
if (overflowData != null) {
for (int i = overflowPos; i < overflowLength; ++i) {
if (!target.hasRemaining()) {
overflowPos = i;
return State.OVERFLOW;
}
target.put(overflowData[i]);
}
overflowData = null;
}
long it = headersIterator;
if (headersIterator == -1) {
handleTableSizeChange(target);
//new headers map
it = headers.fastIterate();
currentHeaders = headers;
} else {
if (headers != currentHeaders) {
throw new IllegalStateException();
}
}
while (it != -1) {
HeaderValues values = headers.fiCurrent(it);
boolean skip = false;
if (firstPass) {
if (values.getHeaderName().byteAt(0) != ':') {
skip = true;
}
} else {
if (values.getHeaderName().byteAt(0) == ':') {
skip = true;
}
}
if (SKIP.contains(values.getHeaderName())) {
//ignore connection specific headers
skip = true;
}
if (!skip) {
for (int i = 0; i < values.size(); ++i) {
HttpString headerName = values.getHeaderName();
//we use 11 to make sure we have enough room for the variable length itegers
int required = 11 + headerName.length();
String val = values.get(i);
for (int v = 0; v < val.length(); ++v) {
char c = val.charAt(v);
if (c == '\r' || c == '\n') {
val = val.replace('\r', ' ').replace('\n', ' ');
break;
}
}
TableEntry tableEntry = findInTable(headerName, val);
required += (1 + val.length());
boolean overflowing = false;
ByteBuffer current = target;
if (current.remaining() < required) {
overflowing = true;
current = ByteBuffer.wrap(overflowData = new byte[required]);
overflowPos = 0;
}
//only index if it will fit
boolean canIndex = hpackHeaderFunction.shouldUseIndexing(headerName, val) && (headerName.length() + val.length() + 32) < maxTableSize;
if (tableEntry == null && canIndex) {
//add the entry to the dynamic table
current.put((byte) (1 << 6));
writeHuffmanEncodableName(current, headerName);
writeHuffmanEncodableValue(current, headerName, val);
addToDynamicTable(headerName, val);
} else if (tableEntry == null) {
//literal never indexed
current.put((byte) (1 << 4));
writeHuffmanEncodableName(current, headerName);
writeHuffmanEncodableValue(current, headerName, val);
} else {
//so we know something is already in the table
if (val.equals(tableEntry.value)) {
//the whole thing is in the table
current.put((byte) (1 << 7));
encodeInteger(current, tableEntry.getPosition(), 7);
} else {
if (canIndex) {
//add the entry to the dynamic table
current.put((byte) (1 << 6));
encodeInteger(current, tableEntry.getPosition(), 6);
writeHuffmanEncodableValue(current, headerName, val);
addToDynamicTable(headerName, val);
} else {
current.put((byte) (1 << 4));
encodeInteger(current, tableEntry.getPosition(), 4);
writeHuffmanEncodableValue(current, headerName, val);
}
}
}
if (overflowing) {
it = headers.fiNext(it);
this.headersIterator = it;
this.overflowLength = current.position();
return State.OVERFLOW;
}
}
}
it = headers.fiNext(it);
if (it == -1 && firstPass) {
firstPass = false;
it = headers.fastIterate();
}
}
headersIterator = -1;
firstPass = true;
return State.COMPLETE;
}
use of io.undertow.util.HeaderValues in project undertow by undertow-io.
the class Http2ReceiveListener method handleInitialRequest.
/**
* Handles the initial request when the exchange was started by a HTTP ugprade.
*
*
* @param initial The initial upgrade request that started the HTTP2 connection
*/
void handleInitialRequest(HttpServerExchange initial, Http2Channel channel) {
//we have a request
Http2HeadersStreamSinkChannel sink = channel.createInitialUpgradeResponseStream();
final Http2ServerConnection connection = new Http2ServerConnection(channel, sink, undertowOptions, bufferSize, rootHandler);
HeaderMap requestHeaders = new HeaderMap();
for (HeaderValues hv : initial.getRequestHeaders()) {
requestHeaders.putAll(hv.getHeaderName(), hv);
}
final HttpServerExchange exchange = new HttpServerExchange(connection, requestHeaders, sink.getHeaders(), maxEntitySize);
connection.setExchange(exchange);
exchange.setRequestScheme(initial.getRequestScheme());
exchange.setProtocol(initial.getProtocol());
exchange.setRequestMethod(initial.getRequestMethod());
exchange.setQueryString(initial.getQueryString());
String uri = exchange.getQueryString().isEmpty() ? initial.getRequestURI() : initial.getRequestURI() + '?' + exchange.getQueryString();
try {
Connectors.setExchangeRequestPath(exchange, uri, encoding, decode, allowEncodingSlash, decodeBuffer, maxParameters);
} catch (ParameterLimitException e) {
exchange.setStatusCode(StatusCodes.BAD_REQUEST);
exchange.endExchange();
return;
}
SSLSession session = channel.getSslSession();
if (session != null) {
connection.setSslSessionInfo(new Http2SslSessionInfo(channel));
}
Connectors.terminateRequest(exchange);
sink.setCompletionListener(new ChannelListener<Http2DataStreamSinkChannel>() {
@Override
public void handleEvent(Http2DataStreamSinkChannel channel) {
Connectors.terminateResponse(exchange);
}
});
Connectors.executeRootHandler(rootHandler, exchange);
}
use of io.undertow.util.HeaderValues in project undertow by undertow-io.
the class HttpResponseConduit method processStatefulWrite.
/**
* Handles writing out the header data in the case where is is too big to fit into a buffer. This is a much slower code path.
*/
private int processStatefulWrite(int state, final Object userData, int pos, int len) throws IOException {
ByteBuffer buffer = pooledBuffer.getBuffer();
long fiCookie = this.fiCookie;
int valueIdx = this.valueIdx;
int charIndex = this.charIndex;
int length;
String string = this.string;
HeaderValues headerValues = this.headerValues;
int res;
// BUFFER IS FLIPPED COMING IN
if (buffer.hasRemaining()) {
do {
res = next.write(buffer);
if (res == 0) {
return state;
}
} while (buffer.hasRemaining());
}
buffer.clear();
HeaderMap headers = exchange.getResponseHeaders();
// BUFFER IS NOW EMPTY FOR FILLING
for (; ; ) {
switch(state) {
case STATE_HDR_NAME:
{
final HttpString headerName = headerValues.getHeaderName();
length = headerName.length();
while (charIndex < length) {
if (buffer.hasRemaining()) {
buffer.put(headerName.byteAt(charIndex++));
} else {
buffer.flip();
do {
res = next.write(buffer);
if (res == 0) {
this.string = string;
this.headerValues = headerValues;
this.charIndex = charIndex;
this.fiCookie = fiCookie;
this.valueIdx = valueIdx;
return STATE_HDR_NAME;
}
} while (buffer.hasRemaining());
buffer.clear();
}
}
// fall thru
}
case STATE_HDR_D:
{
if (!buffer.hasRemaining()) {
buffer.flip();
do {
res = next.write(buffer);
if (res == 0) {
this.string = string;
this.headerValues = headerValues;
this.charIndex = charIndex;
this.fiCookie = fiCookie;
this.valueIdx = valueIdx;
return STATE_HDR_D;
}
} while (buffer.hasRemaining());
buffer.clear();
}
buffer.put((byte) ':');
// fall thru
}
case STATE_HDR_DS:
{
if (!buffer.hasRemaining()) {
buffer.flip();
do {
res = next.write(buffer);
if (res == 0) {
this.string = string;
this.headerValues = headerValues;
this.charIndex = charIndex;
this.fiCookie = fiCookie;
this.valueIdx = valueIdx;
return STATE_HDR_DS;
}
} while (buffer.hasRemaining());
buffer.clear();
}
buffer.put((byte) ' ');
//if (valueIterator == null) {
// valueIterator = exchange.getResponseHeaders().get(headerName).iterator();
//}
string = headerValues.get(valueIdx++);
charIndex = 0;
// fall thru
}
case STATE_HDR_VAL:
{
length = string.length();
while (charIndex < length) {
if (buffer.hasRemaining()) {
buffer.put((byte) string.charAt(charIndex++));
} else {
buffer.flip();
do {
res = next.write(buffer);
if (res == 0) {
this.string = string;
this.headerValues = headerValues;
this.charIndex = charIndex;
this.fiCookie = fiCookie;
this.valueIdx = valueIdx;
return STATE_HDR_VAL;
}
} while (buffer.hasRemaining());
buffer.clear();
}
}
charIndex = 0;
if (valueIdx == headerValues.size()) {
if (!buffer.hasRemaining()) {
if (flushHeaderBuffer(buffer, string, headerValues, charIndex, fiCookie, valueIdx))
return STATE_HDR_EOL_CR;
}
// CR
buffer.put((byte) 13);
if (!buffer.hasRemaining()) {
if (flushHeaderBuffer(buffer, string, headerValues, charIndex, fiCookie, valueIdx))
return STATE_HDR_EOL_LF;
}
// LF
buffer.put((byte) 10);
if ((fiCookie = headers.fiNextNonEmpty(fiCookie)) != -1L) {
headerValues = headers.fiCurrent(fiCookie);
valueIdx = 0;
state = STATE_HDR_NAME;
break;
} else {
if (!buffer.hasRemaining()) {
if (flushHeaderBuffer(buffer, string, headerValues, charIndex, fiCookie, valueIdx))
return STATE_HDR_FINAL_CR;
}
// CR
buffer.put((byte) 13);
if (!buffer.hasRemaining()) {
if (flushHeaderBuffer(buffer, string, headerValues, charIndex, fiCookie, valueIdx))
return STATE_HDR_FINAL_LF;
}
// LF
buffer.put((byte) 10);
this.fiCookie = -1;
this.valueIdx = 0;
this.string = null;
buffer.flip();
//for performance reasons we use a gather write if there is user data
if (userData == null) {
do {
res = next.write(buffer);
if (res == 0) {
return STATE_BUF_FLUSH;
}
} while (buffer.hasRemaining());
} else if (userData instanceof ByteBuffer) {
ByteBuffer[] b = { buffer, (ByteBuffer) userData };
do {
long r = next.write(b, 0, b.length);
if (r == 0 && buffer.hasRemaining()) {
return STATE_BUF_FLUSH;
}
} while (buffer.hasRemaining());
} else {
ByteBuffer[] b = new ByteBuffer[1 + len];
b[0] = buffer;
System.arraycopy(userData, pos, b, 1, len);
do {
long r = next.write(b, 0, b.length);
if (r == 0 && buffer.hasRemaining()) {
return STATE_BUF_FLUSH;
}
} while (buffer.hasRemaining());
}
bufferDone();
return STATE_BODY;
}
// not reached
}
// fall thru
}
// Clean-up states
case STATE_HDR_EOL_CR:
{
if (!buffer.hasRemaining()) {
if (flushHeaderBuffer(buffer, string, headerValues, charIndex, fiCookie, valueIdx))
return STATE_HDR_EOL_CR;
}
// CR
buffer.put((byte) 13);
}
case STATE_HDR_EOL_LF:
{
if (!buffer.hasRemaining()) {
if (flushHeaderBuffer(buffer, string, headerValues, charIndex, fiCookie, valueIdx))
return STATE_HDR_EOL_LF;
}
// LF
buffer.put((byte) 10);
if (valueIdx < headerValues.size()) {
state = STATE_HDR_NAME;
break;
} else if ((fiCookie = headers.fiNextNonEmpty(fiCookie)) != -1L) {
headerValues = headers.fiCurrent(fiCookie);
valueIdx = 0;
state = STATE_HDR_NAME;
break;
}
// fall thru
}
case STATE_HDR_FINAL_CR:
{
if (!buffer.hasRemaining()) {
if (flushHeaderBuffer(buffer, string, headerValues, charIndex, fiCookie, valueIdx))
return STATE_HDR_FINAL_CR;
}
// CR
buffer.put((byte) 13);
// fall thru
}
case STATE_HDR_FINAL_LF:
{
if (!buffer.hasRemaining()) {
if (flushHeaderBuffer(buffer, string, headerValues, charIndex, fiCookie, valueIdx))
return STATE_HDR_FINAL_LF;
}
// LF
buffer.put((byte) 10);
this.fiCookie = -1L;
this.valueIdx = 0;
this.string = null;
buffer.flip();
//for performance reasons we use a gather write if there is user data
if (userData == null) {
do {
res = next.write(buffer);
if (res == 0) {
return STATE_BUF_FLUSH;
}
} while (buffer.hasRemaining());
} else if (userData instanceof ByteBuffer) {
ByteBuffer[] b = { buffer, (ByteBuffer) userData };
do {
long r = next.write(b, 0, b.length);
if (r == 0 && buffer.hasRemaining()) {
return STATE_BUF_FLUSH;
}
} while (buffer.hasRemaining());
} else {
ByteBuffer[] b = new ByteBuffer[1 + len];
b[0] = buffer;
System.arraycopy(userData, pos, b, 1, len);
do {
long r = next.write(b, 0, b.length);
if (r == 0 && buffer.hasRemaining()) {
return STATE_BUF_FLUSH;
}
} while (buffer.hasRemaining());
}
// fall thru
}
case STATE_BUF_FLUSH:
{
// buffer was successfully flushed above
bufferDone();
return STATE_BODY;
}
default:
{
throw new IllegalStateException();
}
}
}
}
use of io.undertow.util.HeaderValues in project undertow by undertow-io.
the class ChunkedRequestTrailersTestCase method setup.
@BeforeClass
public static void setup() {
final BlockingHandler blockingHandler = new BlockingHandler();
existing = DefaultServer.getUndertowOptions();
DefaultServer.setUndertowOptions(OptionMap.create(UndertowOptions.ALWAYS_SET_DATE, false));
DefaultServer.setRootHandler(blockingHandler);
blockingHandler.setRootHandler(new HttpHandler() {
@Override
public void handleRequest(final HttpServerExchange exchange) {
try {
if (connection == null) {
connection = (HttpServerConnection) exchange.getConnection();
} else if (!DefaultServer.isProxy() && connection != exchange.getConnection()) {
exchange.setStatusCode(StatusCodes.INTERNAL_SERVER_ERROR);
final OutputStream outputStream = exchange.getOutputStream();
outputStream.write("Connection not persistent".getBytes());
outputStream.close();
return;
}
final OutputStream outputStream = exchange.getOutputStream();
final InputStream inputStream = exchange.getInputStream();
String m = HttpClientUtils.readResponse(inputStream);
Assert.assertEquals("abcdefghi", m);
HeaderMap headers = exchange.getAttachment(HttpAttachments.REQUEST_TRAILERS);
for (HeaderValues header : headers) {
for (String val : header) {
outputStream.write(header.getHeaderName().toString().getBytes());
outputStream.write(": ".getBytes());
outputStream.write(val.getBytes());
outputStream.write("\r\n".getBytes());
}
}
inputStream.close();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
});
}
use of io.undertow.util.HeaderValues in project undertow by undertow-io.
the class CrawlerBindingListener method handleRequest.
@Override
public void handleRequest(HttpServerExchange exchange) throws Exception {
boolean isBot = false;
String sessionId = null;
String clientIp = null;
ServletRequestContext src = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
// If the incoming request has a valid session ID, no action is required
if (src.getOriginalRequest().getSession(false) == null) {
// Is this a crawler - check the UA headers
HeaderValues userAgentHeaders = exchange.getRequestHeaders().get(Headers.USER_AGENT);
if (userAgentHeaders != null) {
Iterator<String> uaHeaders = userAgentHeaders.iterator();
String uaHeader = null;
if (uaHeaders.hasNext()) {
uaHeader = uaHeaders.next();
}
// If more than one UA header - assume not a bot
if (uaHeader != null && !uaHeaders.hasNext()) {
if (uaPattern.matcher(uaHeader).matches()) {
isBot = true;
if (UndertowLogger.REQUEST_LOGGER.isDebugEnabled()) {
UndertowLogger.REQUEST_LOGGER.debug(exchange + ": Bot found. UserAgent=" + uaHeader);
}
}
}
// If this is a bot, is the session ID known?
if (isBot) {
clientIp = src.getServletRequest().getRemoteAddr();
sessionId = clientIpSessionId.get(clientIp);
if (sessionId != null) {
src.setOverridenSessionId(sessionId);
if (UndertowLogger.REQUEST_LOGGER.isDebugEnabled()) {
UndertowLogger.REQUEST_LOGGER.debug(exchange + ": SessionID=" + sessionId);
}
}
}
}
}
if (isBot) {
final String finalSessionId = sessionId;
final String finalClientId = clientIp;
exchange.addExchangeCompleteListener(new ExchangeCompletionListener() {
@Override
public void exchangeEvent(HttpServerExchange exchange, NextListener nextListener) {
try {
ServletRequestContext src = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
if (finalSessionId == null) {
// Has bot just created a session, if so make a note of it
HttpSession s = src.getOriginalRequest().getSession(false);
if (s != null) {
clientIpSessionId.put(finalClientId, s.getId());
sessionIdClientIp.put(s.getId(), finalClientId);
// #valueUnbound() will be called on session expiration
s.setAttribute(SESSION_ATTRIBUTE_NAME, new CrawlerBindingListener(clientIpSessionId, sessionIdClientIp));
s.setMaxInactiveInterval(config.getSessionInactiveInterval());
if (UndertowLogger.REQUEST_LOGGER.isDebugEnabled()) {
UndertowLogger.REQUEST_LOGGER.debug(exchange + ": New bot session. SessionID=" + s.getId());
}
}
} else {
if (UndertowLogger.REQUEST_LOGGER.isDebugEnabled()) {
UndertowLogger.REQUEST_LOGGER.debug(exchange + ": Bot session accessed. SessionID=" + finalSessionId);
}
}
} finally {
nextListener.proceed();
}
}
});
}
next.handleRequest(exchange);
}
Aggregations