use of io.undertow.util.HeaderMap 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.HeaderMap in project undertow by undertow-io.
the class HttpRequestConduit 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.
*
* 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 java.io.IOException
*/
private int processWrite(int state, final ByteBuffer userData) throws IOException {
if (state == STATE_START) {
pooledBuffer = pool.allocate();
}
ClientRequest request = this.request;
ByteBuffer buffer = pooledBuffer.getBuffer();
Iterator<HttpString> nameIterator = this.nameIterator;
Iterator<String> valueIterator = this.valueIterator;
int charIndex = this.charIndex;
int length;
String string = this.string;
HttpString headerName = this.headerName;
int res;
// BUFFER IS FLIPPED COMING IN
if (state != STATE_START && buffer.hasRemaining()) {
log.trace("Flushing remaining buffer");
do {
res = next.write(buffer);
if (res == 0) {
return state;
}
} while (buffer.hasRemaining());
}
buffer.clear();
// BUFFER IS NOW EMPTY FOR FILLING
for (; ; ) {
switch(state) {
case STATE_BODY:
{
// shouldn't be possible, but might as well do the right thing anyway
return state;
}
case STATE_START:
{
log.trace("Starting request");
int len = request.getMethod().length() + request.getPath().length() + request.getProtocol().length() + 4;
// test that our buffer has enough space for the initial request line plus one more CR+LF
if (len <= buffer.remaining()) {
assert buffer.remaining() >= 50;
request.getMethod().appendTo(buffer);
buffer.put((byte) ' ');
string = request.getPath();
length = string.length();
for (charIndex = 0; charIndex < length; charIndex++) {
buffer.put((byte) string.charAt(charIndex));
}
buffer.put((byte) ' ');
request.getProtocol().appendTo(buffer);
buffer.put((byte) '\r').put((byte) '\n');
} else {
StringBuilder sb = new StringBuilder(len);
sb.append(request.getMethod().toString());
sb.append(" ");
sb.append(request.getPath());
sb.append(" ");
sb.append(request.getProtocol());
sb.append("\r\n");
string = sb.toString();
charIndex = 0;
state = STATE_URL;
break;
}
HeaderMap headers = request.getRequestHeaders();
nameIterator = headers.getHeaderNames().iterator();
if (!nameIterator.hasNext()) {
log.trace("No request headers");
buffer.put((byte) '\r').put((byte) '\n');
buffer.flip();
while (buffer.hasRemaining()) {
res = next.write(buffer);
if (res == 0) {
log.trace("Continuation");
return STATE_BUF_FLUSH;
}
}
pooledBuffer.close();
pooledBuffer = null;
log.trace("Body");
return STATE_BODY;
}
headerName = nameIterator.next();
charIndex = 0;
// fall thru
}
case STATE_HDR_NAME:
{
log.tracef("Processing header '%s'", headerName);
length = headerName.length();
while (charIndex < length) {
if (buffer.hasRemaining()) {
buffer.put(headerName.byteAt(charIndex++));
} else {
log.trace("Buffer flush");
buffer.flip();
do {
res = next.write(buffer);
if (res == 0) {
this.string = string;
this.headerName = headerName;
this.charIndex = charIndex;
this.valueIterator = valueIterator;
this.nameIterator = nameIterator;
log.trace("Continuation");
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) {
log.trace("Continuation");
this.string = string;
this.headerName = headerName;
this.charIndex = charIndex;
this.valueIterator = valueIterator;
this.nameIterator = nameIterator;
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) {
log.trace("Continuation");
this.string = string;
this.headerName = headerName;
this.charIndex = charIndex;
this.valueIterator = valueIterator;
this.nameIterator = nameIterator;
return STATE_HDR_DS;
}
} while (buffer.hasRemaining());
buffer.clear();
}
buffer.put((byte) ' ');
if (valueIterator == null) {
valueIterator = request.getRequestHeaders().get(headerName).iterator();
}
assert valueIterator.hasNext();
string = valueIterator.next();
charIndex = 0;
// fall thru
}
case STATE_HDR_VAL:
{
log.tracef("Processing header value '%s'", string);
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.headerName = headerName;
this.charIndex = charIndex;
this.valueIterator = valueIterator;
this.nameIterator = nameIterator;
log.trace("Continuation");
return STATE_HDR_VAL;
}
} while (buffer.hasRemaining());
buffer.clear();
}
}
charIndex = 0;
if (!valueIterator.hasNext()) {
if (!buffer.hasRemaining()) {
buffer.flip();
do {
res = next.write(buffer);
if (res == 0) {
log.trace("Continuation");
return STATE_HDR_EOL_CR;
}
} while (buffer.hasRemaining());
buffer.clear();
}
// CR
buffer.put((byte) 13);
if (!buffer.hasRemaining()) {
buffer.flip();
do {
res = next.write(buffer);
if (res == 0) {
log.trace("Continuation");
return STATE_HDR_EOL_LF;
}
} while (buffer.hasRemaining());
buffer.clear();
}
// LF
buffer.put((byte) 10);
if (nameIterator.hasNext()) {
headerName = nameIterator.next();
valueIterator = null;
state = STATE_HDR_NAME;
break;
} else {
if (!buffer.hasRemaining()) {
buffer.flip();
do {
res = next.write(buffer);
if (res == 0) {
log.trace("Continuation");
return STATE_HDR_FINAL_CR;
}
} while (buffer.hasRemaining());
buffer.clear();
}
// CR
buffer.put((byte) 13);
if (!buffer.hasRemaining()) {
buffer.flip();
do {
res = next.write(buffer);
if (res == 0) {
log.trace("Continuation");
return STATE_HDR_FINAL_LF;
}
} while (buffer.hasRemaining());
buffer.clear();
}
// LF
buffer.put((byte) 10);
this.nameIterator = null;
this.valueIterator = null;
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) {
log.trace("Continuation");
return STATE_BUF_FLUSH;
}
} while (buffer.hasRemaining());
} else {
ByteBuffer[] b = { buffer, userData };
do {
long r = next.write(b, 0, b.length);
if (r == 0 && buffer.hasRemaining()) {
log.trace("Continuation");
return STATE_BUF_FLUSH;
}
} while (buffer.hasRemaining());
}
pooledBuffer.close();
pooledBuffer = null;
log.trace("Body");
return STATE_BODY;
}
// not reached
}
// fall thru
}
// Clean-up states
case STATE_HDR_EOL_CR:
{
if (!buffer.hasRemaining()) {
buffer.flip();
do {
res = next.write(buffer);
if (res == 0) {
log.trace("Continuation");
return STATE_HDR_EOL_CR;
}
} while (buffer.hasRemaining());
buffer.clear();
}
// CR
buffer.put((byte) 13);
}
case STATE_HDR_EOL_LF:
{
if (!buffer.hasRemaining()) {
buffer.flip();
do {
res = next.write(buffer);
if (res == 0) {
log.trace("Continuation");
return STATE_HDR_EOL_LF;
}
} while (buffer.hasRemaining());
buffer.clear();
}
// LF
buffer.put((byte) 10);
if (valueIterator.hasNext()) {
state = STATE_HDR_NAME;
break;
} else if (nameIterator.hasNext()) {
headerName = nameIterator.next();
valueIterator = null;
state = STATE_HDR_NAME;
break;
}
// fall thru
}
case STATE_HDR_FINAL_CR:
{
if (!buffer.hasRemaining()) {
buffer.flip();
do {
res = next.write(buffer);
if (res == 0) {
log.trace("Continuation");
return STATE_HDR_FINAL_CR;
}
} while (buffer.hasRemaining());
buffer.clear();
}
// CR
buffer.put((byte) 13);
// fall thru
}
case STATE_HDR_FINAL_LF:
{
if (!buffer.hasRemaining()) {
buffer.flip();
do {
res = next.write(buffer);
if (res == 0) {
log.trace("Continuation");
return STATE_HDR_FINAL_LF;
}
} while (buffer.hasRemaining());
buffer.clear();
}
// LF
buffer.put((byte) 10);
this.nameIterator = null;
this.valueIterator = null;
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) {
log.trace("Continuation");
return STATE_BUF_FLUSH;
}
} while (buffer.hasRemaining());
} else {
ByteBuffer[] b = { buffer, userData };
do {
long r = next.write(b, 0, b.length);
if (r == 0 && buffer.hasRemaining()) {
log.trace("Continuation");
return STATE_BUF_FLUSH;
}
} while (buffer.hasRemaining());
}
// fall thru
}
case STATE_BUF_FLUSH:
{
// buffer was successfully flushed above
pooledBuffer.close();
pooledBuffer = null;
return STATE_BODY;
}
case STATE_URL:
{
for (int i = charIndex; i < string.length(); ++i) {
if (!buffer.hasRemaining()) {
buffer.flip();
do {
res = next.write(buffer);
if (res == 0) {
log.trace("Continuation");
this.charIndex = i;
this.string = string;
this.state = STATE_URL;
return STATE_URL;
}
} while (buffer.hasRemaining());
buffer.clear();
}
buffer.put((byte) string.charAt(i));
}
HeaderMap headers = request.getRequestHeaders();
nameIterator = headers.getHeaderNames().iterator();
state = STATE_HDR_NAME;
if (!nameIterator.hasNext()) {
log.trace("No request headers");
buffer.put((byte) '\r').put((byte) '\n');
buffer.flip();
while (buffer.hasRemaining()) {
res = next.write(buffer);
if (res == 0) {
log.trace("Continuation");
return STATE_BUF_FLUSH;
}
}
pooledBuffer.close();
pooledBuffer = null;
log.trace("Body");
return STATE_BODY;
}
headerName = nameIterator.next();
charIndex = 0;
break;
}
default:
{
throw new IllegalStateException();
}
}
}
}
use of io.undertow.util.HeaderMap 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.HeaderMap in project undertow by undertow-io.
the class HttpTransferEncoding method setupRequest.
public static void setupRequest(final HttpServerExchange exchange) {
final HeaderMap requestHeaders = exchange.getRequestHeaders();
final String connectionHeader = requestHeaders.getFirst(Headers.CONNECTION);
final String transferEncodingHeader = requestHeaders.getLast(Headers.TRANSFER_ENCODING);
final String contentLengthHeader = requestHeaders.getFirst(Headers.CONTENT_LENGTH);
final HttpServerConnection connection = (HttpServerConnection) exchange.getConnection();
//if we are already using the pipelineing buffer add it to the exchange
PipeliningBufferingStreamSinkConduit pipeliningBuffer = connection.getPipelineBuffer();
if (pipeliningBuffer != null) {
pipeliningBuffer.setupPipelineBuffer(exchange);
}
ConduitStreamSourceChannel sourceChannel = connection.getChannel().getSourceChannel();
sourceChannel.setConduit(connection.getReadDataStreamSourceConduit());
boolean persistentConnection = persistentConnection(exchange, connectionHeader);
if (transferEncodingHeader == null && contentLengthHeader == null) {
if (persistentConnection && connection.getExtraBytes() != null && pipeliningBuffer == null && connection.getUndertowOptions().get(UndertowOptions.BUFFER_PIPELINED_DATA, false)) {
pipeliningBuffer = new PipeliningBufferingStreamSinkConduit(connection.getOriginalSinkConduit(), connection.getByteBufferPool());
connection.setPipelineBuffer(pipeliningBuffer);
pipeliningBuffer.setupPipelineBuffer(exchange);
}
// no content - immediately start the next request, returning an empty stream for this one
Connectors.terminateRequest(exchange);
} else {
persistentConnection = handleRequestEncoding(exchange, transferEncodingHeader, contentLengthHeader, connection, pipeliningBuffer, persistentConnection);
}
exchange.setPersistent(persistentConnection);
if (!exchange.isRequestComplete() || connection.getExtraBytes() != null) {
//if there is more data we suspend reads
sourceChannel.setReadListener(null);
sourceChannel.suspendReads();
}
}
use of io.undertow.util.HeaderMap in project undertow by undertow-io.
the class Http2ServerConnection method sendOutOfBandResponse.
@Override
public HttpServerExchange sendOutOfBandResponse(HttpServerExchange exchange) {
if (exchange == null || !HttpContinue.requiresContinueResponse(exchange)) {
throw UndertowMessages.MESSAGES.outOfBandResponseOnlyAllowedFor100Continue();
}
final HttpServerExchange newExchange = new HttpServerExchange(this);
for (HttpString header : exchange.getRequestHeaders().getHeaderNames()) {
newExchange.getRequestHeaders().putAll(header, exchange.getRequestHeaders().get(header));
}
newExchange.setProtocol(exchange.getProtocol());
newExchange.setRequestMethod(exchange.getRequestMethod());
exchange.setRequestURI(exchange.getRequestURI(), exchange.isHostIncludedInRequestURI());
exchange.setRequestPath(exchange.getRequestPath());
exchange.setRelativePath(exchange.getRelativePath());
newExchange.setPersistent(true);
Connectors.terminateRequest(newExchange);
newExchange.addResponseWrapper(new ConduitWrapper<StreamSinkConduit>() {
@Override
public StreamSinkConduit wrap(ConduitFactory<StreamSinkConduit> factory, HttpServerExchange exchange) {
HeaderMap headers = newExchange.getResponseHeaders();
DateUtils.addDateHeaderIfRequired(exchange);
headers.add(STATUS, exchange.getStatusCode());
Connectors.flattenCookies(exchange);
Http2HeadersStreamSinkChannel sink = new Http2HeadersStreamSinkChannel(channel, requestChannel.getStreamId(), headers);
StreamSinkChannelWrappingConduit ret = new StreamSinkChannelWrappingConduit(sink);
ret.setWriteReadyHandler(new WriteReadyHandler.ChannelListenerHandler(Connectors.getConduitSinkChannel(exchange)));
return ret;
}
});
continueSent = true;
return newExchange;
}
Aggregations