use of io.undertow.util.HeaderValues in project undertow by undertow-io.
the class SavedRequest method trySaveRequest.
public static void trySaveRequest(final HttpServerExchange exchange) {
int maxSize = exchange.getConnection().getUndertowOptions().get(UndertowOptions.MAX_BUFFERED_REQUEST_SIZE, 16384);
if (maxSize > 0) {
//if this request has a body try and cache the response
if (!exchange.isRequestComplete()) {
final long requestContentLength = exchange.getRequestContentLength();
if (requestContentLength > maxSize) {
UndertowLogger.REQUEST_LOGGER.debugf("Request to %s was to large to save", exchange.getRequestURI());
//failed to save the request, we just return
return;
}
//TODO: we should really be used pooled buffers
//TODO: we should probably limit the number of saved requests at any given time
byte[] buffer = new byte[maxSize];
int read = 0;
int res = 0;
InputStream in = exchange.getInputStream();
try {
while ((res = in.read(buffer, read, buffer.length - read)) > 0) {
read += res;
if (read == maxSize) {
UndertowLogger.REQUEST_LOGGER.debugf("Request to %s was to large to save", exchange.getRequestURI());
//failed to save the request, we just return
return;
}
}
HeaderMap headers = new HeaderMap();
for (HeaderValues entry : exchange.getRequestHeaders()) {
if (entry.getHeaderName().equals(Headers.CONTENT_LENGTH) || entry.getHeaderName().equals(Headers.TRANSFER_ENCODING) || entry.getHeaderName().equals(Headers.CONNECTION)) {
continue;
}
headers.putAll(entry.getHeaderName(), entry);
}
SavedRequest request = new SavedRequest(buffer, read, exchange.getRequestMethod(), exchange.getRelativePath(), exchange.getRequestHeaders());
final ServletRequestContext sc = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
HttpSessionImpl session = sc.getCurrentServletContext().getSession(exchange, true);
Session underlyingSession;
if (System.getSecurityManager() == null) {
underlyingSession = session.getSession();
} else {
underlyingSession = AccessController.doPrivileged(new HttpSessionImpl.UnwrapSessionAction(session));
}
underlyingSession.setAttribute(SESSION_KEY, request);
} catch (IOException e) {
UndertowLogger.REQUEST_IO_LOGGER.ioException(e);
}
}
}
}
use of io.undertow.util.HeaderValues in project undertow by undertow-io.
the class SavedRequest method tryRestoreRequest.
public static void tryRestoreRequest(final HttpServerExchange exchange, HttpSession session) {
if (session instanceof HttpSessionImpl) {
Session underlyingSession;
if (System.getSecurityManager() == null) {
underlyingSession = ((HttpSessionImpl) session).getSession();
} else {
underlyingSession = AccessController.doPrivileged(new HttpSessionImpl.UnwrapSessionAction(session));
}
SavedRequest request = (SavedRequest) underlyingSession.getAttribute(SESSION_KEY);
if (request != null) {
if (request.requestPath.equals(exchange.getRelativePath()) && exchange.isRequestComplete()) {
UndertowLogger.REQUEST_LOGGER.debugf("restoring request body for request to %s", request.requestPath);
exchange.setRequestMethod(request.method);
Connectors.ungetRequestBytes(exchange, new ImmediatePooledByteBuffer(ByteBuffer.wrap(request.data, 0, request.dataLength)));
underlyingSession.removeAttribute(SESSION_KEY);
//clear the existing header map of everything except the connection header
//TODO: are there other headers we should preserve?
Iterator<HeaderValues> headerIterator = exchange.getRequestHeaders().iterator();
while (headerIterator.hasNext()) {
HeaderValues header = headerIterator.next();
if (!header.getHeaderName().equals(Headers.CONNECTION)) {
headerIterator.remove();
}
}
for (Map.Entry<HttpString, List<String>> header : request.headerMap.entrySet()) {
exchange.getRequestHeaders().putAll(header.getKey(), header.getValue());
}
}
}
}
}
use of io.undertow.util.HeaderValues in project undertow by undertow-io.
the class HttpResponseConduit method processWrite.
/**
* Handles writing out the header data. It can also take a byte buffer of user
* data, to enable both user data and headers to be written out in a single operation,
* which has a noticeable performance impact.
* <p/>
* It is up to the caller to note the current position of this buffer before and after they
* call this method, and use this to figure out how many bytes (if any) have been written.
*
* @param state
* @param userData
* @return
* @throws IOException
*/
private int processWrite(int state, final Object userData, int pos, int length) throws IOException {
if (done || exchange == null) {
throw new ClosedChannelException();
}
try {
assert state != STATE_BODY;
if (state == STATE_BUF_FLUSH) {
final ByteBuffer byteBuffer = pooledBuffer.getBuffer();
do {
long res = 0;
ByteBuffer[] data;
if (userData == null || length == 0) {
res = next.write(byteBuffer);
} else if (userData instanceof ByteBuffer) {
data = writevBuffer;
if (data == null) {
data = writevBuffer = new ByteBuffer[2];
}
data[0] = byteBuffer;
data[1] = (ByteBuffer) userData;
res = next.write(data, 0, 2);
} else {
data = writevBuffer;
if (data == null || data.length < length + 1) {
data = writevBuffer = new ByteBuffer[length + 1];
}
data[0] = byteBuffer;
System.arraycopy(userData, pos, data, 1, length);
res = next.write(data, 0, data.length);
}
if (res == 0) {
return STATE_BUF_FLUSH;
}
} while (byteBuffer.hasRemaining());
bufferDone();
return STATE_BODY;
} else if (state != STATE_START) {
return processStatefulWrite(state, userData, pos, length);
}
//merge the cookies into the header map
Connectors.flattenCookies(exchange);
if (pooledBuffer == null) {
pooledBuffer = pool.allocate();
}
ByteBuffer buffer = pooledBuffer.getBuffer();
assert buffer.remaining() >= 50;
exchange.getProtocol().appendTo(buffer);
buffer.put((byte) ' ');
int code = exchange.getStatusCode();
assert 999 >= code && code >= 100;
buffer.put((byte) (code / 100 + '0'));
buffer.put((byte) (code / 10 % 10 + '0'));
buffer.put((byte) (code % 10 + '0'));
buffer.put((byte) ' ');
String string = exchange.getReasonPhrase();
if (string == null) {
string = StatusCodes.getReason(code);
}
if (string.length() > buffer.remaining()) {
pooledBuffer.close();
pooledBuffer = null;
truncateWrites();
throw UndertowMessages.MESSAGES.reasonPhraseToLargeForBuffer(string);
}
writeString(buffer, string);
buffer.put((byte) '\r').put((byte) '\n');
int remaining = buffer.remaining();
HeaderMap headers = exchange.getResponseHeaders();
long fiCookie = headers.fastIterateNonEmpty();
while (fiCookie != -1) {
HeaderValues headerValues = headers.fiCurrent(fiCookie);
HttpString header = headerValues.getHeaderName();
int headerSize = header.length();
int valueIdx = 0;
while (valueIdx < headerValues.size()) {
remaining -= (headerSize + 2);
if (remaining < 0) {
this.fiCookie = fiCookie;
this.string = string;
this.headerValues = headerValues;
this.valueIdx = valueIdx;
this.charIndex = 0;
this.state = STATE_HDR_NAME;
buffer.flip();
return processStatefulWrite(STATE_HDR_NAME, userData, pos, length);
}
header.appendTo(buffer);
buffer.put((byte) ':').put((byte) ' ');
string = headerValues.get(valueIdx++);
remaining -= (string.length() + 2);
if (remaining < 2) {
//we use 2 here, to make sure we always have room for the final \r\n
this.fiCookie = fiCookie;
this.string = string;
this.headerValues = headerValues;
this.valueIdx = valueIdx;
this.charIndex = 0;
this.state = STATE_HDR_VAL;
buffer.flip();
return processStatefulWrite(STATE_HDR_VAL, userData, pos, length);
}
writeString(buffer, string);
buffer.put((byte) '\r').put((byte) '\n');
}
fiCookie = headers.fiNextNonEmpty(fiCookie);
}
buffer.put((byte) '\r').put((byte) '\n');
buffer.flip();
do {
long res = 0;
ByteBuffer[] data;
if (userData == null) {
res = next.write(buffer);
} else if (userData instanceof ByteBuffer) {
data = writevBuffer;
if (data == null) {
data = writevBuffer = new ByteBuffer[2];
}
data[0] = buffer;
data[1] = (ByteBuffer) userData;
res = next.write(data, 0, 2);
} else {
data = writevBuffer;
if (data == null || data.length < length + 1) {
data = writevBuffer = new ByteBuffer[length + 1];
}
data[0] = buffer;
System.arraycopy(userData, pos, data, 1, length);
res = next.write(data, 0, length + 1);
}
if (res == 0) {
return STATE_BUF_FLUSH;
}
} while (buffer.hasRemaining());
bufferDone();
return STATE_BODY;
} catch (IOException | RuntimeException e) {
//WFLY-4696, just to be safe
if (pooledBuffer != null) {
pooledBuffer.close();
pooledBuffer = null;
}
throw e;
}
}
use of io.undertow.util.HeaderValues in project indy by Commonjava.
the class HeaderDebugger method handleRequest.
@Override
public void handleRequest(final HttpServerExchange exchange) throws Exception {
if (logger.isTraceEnabled()) {
logger.trace("{} {}", exchange.getRequestMethod(), exchange.getRequestPath());
logger.trace("FROM: {}", exchange.getSourceAddress());
final HeaderMap headerMap = exchange.getRequestHeaders();
final Collection<HttpString> names = headerMap.getHeaderNames();
logger.trace("HEADERS: ");
for (final HttpString name : names) {
final HeaderValues values = headerMap.get(name);
for (final String value : values) {
logger.trace("{}: {}", name, value);
}
}
logger.trace("COOKIES: ");
final Map<String, Cookie> cookies = exchange.getRequestCookies();
for (final String key : cookies.keySet()) {
final Cookie cookie = cookies.get(key);
if (cookie == null) {
continue;
}
logger.trace("Cookie({}):\n Domain: {}\n Name: {}\n Path: {}\n Value: {}\n Expires: {}\n Max-Age: {}\n Comment: {}\n Version: {}\n\n", key, cookie.getDomain(), cookie.getName(), cookie.getPath(), cookie.getValue(), cookie.getExpires(), cookie.getMaxAge(), cookie.getComment(), cookie.getVersion());
}
}
handler.handleRequest(exchange);
}
use of io.undertow.util.HeaderValues in project undertow by undertow-io.
the class ChunkedStreamSinkConduit method createLastChunk.
private void createLastChunk(final boolean writeFinal) throws UnsupportedEncodingException {
PooledByteBuffer lastChunkBufferPooled = bufferPool.allocate();
ByteBuffer lastChunkBuffer = lastChunkBufferPooled.getBuffer();
if (writeFinal) {
lastChunkBuffer.put(CRLF);
} else if (chunkingSepBuffer.hasRemaining()) {
//the end of chunk /r/n has not been written yet
//just add it to this buffer to make managing state easier
lastChunkBuffer.put(chunkingSepBuffer);
}
lastChunkBuffer.put(LAST_CHUNK);
//we just assume it will fit
HeaderMap trailers = attachable.getAttachment(HttpAttachments.RESPONSE_TRAILERS);
if (trailers != null && trailers.size() != 0) {
for (HeaderValues trailer : trailers) {
for (String val : trailer) {
trailer.getHeaderName().appendTo(lastChunkBuffer);
lastChunkBuffer.put((byte) ':');
lastChunkBuffer.put((byte) ' ');
lastChunkBuffer.put(val.getBytes(StandardCharsets.US_ASCII));
lastChunkBuffer.put(CRLF);
}
}
lastChunkBuffer.put(CRLF);
} else {
lastChunkBuffer.put(CRLF);
}
//horrible hack
//there is a situation where we can get a buffer leak here if the connection is terminated abnormaly
//this should be fixed once this channel has its lifecycle tied to the connection, same as fixed length
lastChunkBuffer.flip();
ByteBuffer data = ByteBuffer.allocate(lastChunkBuffer.remaining());
data.put(lastChunkBuffer);
data.flip();
this.lastChunkBuffer = new ImmediatePooledByteBuffer(data);
lastChunkBufferPooled.close();
}
Aggregations