use of org.xnio.channels.StreamSinkChannel in project undertow by undertow-io.
the class ConnectHandler method handleRequest.
@Override
public void handleRequest(final HttpServerExchange exchange) throws Exception {
if (exchange.getRequestMethod().equals(Methods.CONNECT)) {
if (!allowed.resolve(exchange)) {
//not sure if this is the best response
exchange.setStatusCode(StatusCodes.METHOD_NOT_ALLOWED);
return;
}
String[] parts = exchange.getRequestPath().split(":");
if (parts.length != 2) {
//not sure if this is the best response
exchange.setStatusCode(StatusCodes.BAD_REQUEST);
return;
}
final String host = parts[0];
final Integer port = Integer.parseInt(parts[1]);
exchange.dispatch(SameThreadExecutor.INSTANCE, new Runnable() {
@Override
public void run() {
exchange.getConnection().getIoThread().openStreamConnection(new InetSocketAddress(host, port), new ChannelListener<StreamConnection>() {
@Override
public void handleEvent(final StreamConnection clientChannel) {
exchange.acceptConnectRequest(new HttpUpgradeListener() {
@Override
public void handleUpgrade(StreamConnection streamConnection, HttpServerExchange exchange) {
final ClosingExceptionHandler handler = new ClosingExceptionHandler(streamConnection, clientChannel);
Transfer.initiateTransfer(clientChannel.getSourceChannel(), streamConnection.getSinkChannel(), ChannelListeners.closingChannelListener(), ChannelListeners.writeShutdownChannelListener(ChannelListeners.<StreamSinkChannel>flushingChannelListener(ChannelListeners.closingChannelListener(), ChannelListeners.closingChannelExceptionHandler()), ChannelListeners.closingChannelExceptionHandler()), handler, handler, exchange.getConnection().getByteBufferPool());
Transfer.initiateTransfer(streamConnection.getSourceChannel(), clientChannel.getSinkChannel(), ChannelListeners.closingChannelListener(), ChannelListeners.writeShutdownChannelListener(ChannelListeners.<StreamSinkChannel>flushingChannelListener(ChannelListeners.closingChannelListener(), ChannelListeners.closingChannelExceptionHandler()), ChannelListeners.closingChannelExceptionHandler()), handler, handler, exchange.getConnection().getByteBufferPool());
}
});
exchange.setStatusCode(200);
exchange.endExchange();
}
}, OptionMap.create(Options.TCP_NODELAY, true)).addNotifier(new IoFuture.Notifier<StreamConnection, Object>() {
@Override
public void notify(IoFuture<? extends StreamConnection> ioFuture, Object attachment) {
if (ioFuture.getStatus() == IoFuture.Status.FAILED) {
exchange.setStatusCode(503);
exchange.endExchange();
}
}
}, null);
}
});
} else {
next.handleRequest(exchange);
}
}
use of org.xnio.channels.StreamSinkChannel in project undertow by undertow-io.
the class ServletOutputStreamImpl method writeTooLargeForBuffer.
private void writeTooLargeForBuffer(byte[] b, int off, int len, ByteBuffer buffer) throws IOException {
//so what we have will not fit.
//We allocate multiple buffers up to MAX_BUFFERS_TO_ALLOCATE
//and put it in them
//if it still dopes not fit we loop, re-using these buffers
StreamSinkChannel channel = this.channel;
if (channel == null) {
this.channel = channel = servletRequestContext.getExchange().getResponseChannel();
}
final ByteBufferPool bufferPool = servletRequestContext.getExchange().getConnection().getByteBufferPool();
ByteBuffer[] buffers = new ByteBuffer[MAX_BUFFERS_TO_ALLOCATE + 1];
PooledByteBuffer[] pooledBuffers = new PooledByteBuffer[MAX_BUFFERS_TO_ALLOCATE];
try {
buffers[0] = buffer;
int bytesWritten = 0;
int rem = buffer.remaining();
buffer.put(b, bytesWritten + off, rem);
buffer.flip();
bytesWritten += rem;
int bufferCount = 1;
for (int i = 0; i < MAX_BUFFERS_TO_ALLOCATE; ++i) {
PooledByteBuffer pooled = bufferPool.allocate();
pooledBuffers[bufferCount - 1] = pooled;
buffers[bufferCount++] = pooled.getBuffer();
ByteBuffer cb = pooled.getBuffer();
int toWrite = len - bytesWritten;
if (toWrite > cb.remaining()) {
rem = cb.remaining();
cb.put(b, bytesWritten + off, rem);
cb.flip();
bytesWritten += rem;
} else {
cb.put(b, bytesWritten + off, toWrite);
bytesWritten = len;
cb.flip();
break;
}
}
Channels.writeBlocking(channel, buffers, 0, bufferCount);
while (bytesWritten < len) {
//ok, it did not fit, loop and loop and loop until it is done
bufferCount = 0;
for (int i = 0; i < MAX_BUFFERS_TO_ALLOCATE + 1; ++i) {
ByteBuffer cb = buffers[i];
cb.clear();
bufferCount++;
int toWrite = len - bytesWritten;
if (toWrite > cb.remaining()) {
rem = cb.remaining();
cb.put(b, bytesWritten + off, rem);
cb.flip();
bytesWritten += rem;
} else {
cb.put(b, bytesWritten + off, toWrite);
bytesWritten = len;
cb.flip();
break;
}
}
Channels.writeBlocking(channel, buffers, 0, bufferCount);
}
buffer.clear();
} finally {
for (int i = 0; i < pooledBuffers.length; ++i) {
PooledByteBuffer p = pooledBuffers[i];
if (p == null) {
break;
}
p.close();
}
}
}
use of org.xnio.channels.StreamSinkChannel in project undertow by undertow-io.
the class ServletOutputStreamImpl method close.
/**
* {@inheritDoc}
*/
public void close() throws IOException {
if (servletRequestContext.getOriginalRequest().getDispatcherType() == DispatcherType.INCLUDE || servletRequestContext.getOriginalResponse().isTreatAsCommitted()) {
return;
}
if (listener == null) {
if (anyAreSet(state, FLAG_CLOSED))
return;
state |= FLAG_CLOSED;
state &= ~FLAG_READY;
if (allAreClear(state, FLAG_WRITE_STARTED) && channel == null && servletRequestContext.getOriginalResponse().getHeader(Headers.CONTENT_LENGTH_STRING) == null) {
if (servletRequestContext.getOriginalResponse().getHeader(Headers.TRANSFER_ENCODING_STRING) == null) {
if (buffer == null) {
servletRequestContext.getExchange().getResponseHeaders().put(Headers.CONTENT_LENGTH, "0");
} else {
servletRequestContext.getExchange().getResponseHeaders().put(Headers.CONTENT_LENGTH, Integer.toString(buffer.position()));
}
}
}
try {
if (buffer != null) {
writeBufferBlocking(true);
}
if (channel == null) {
channel = servletRequestContext.getExchange().getResponseChannel();
}
state |= FLAG_DELEGATE_SHUTDOWN;
StreamSinkChannel channel = this.channel;
if (channel != null) {
//mock requests
channel.shutdownWrites();
Channels.flushBlocking(channel);
}
} catch (IOException e) {
IoUtils.safeClose(this.channel);
throw e;
} finally {
if (pooledBuffer != null) {
pooledBuffer.close();
buffer = null;
} else {
buffer = null;
}
}
} else {
closeAsync();
}
}
use of org.xnio.channels.StreamSinkChannel in project undertow by undertow-io.
the class Http2ClientConnection method sendRequest.
@Override
public void sendRequest(ClientRequest request, ClientCallback<ClientExchange> clientCallback) {
request.getRequestHeaders().put(METHOD, request.getMethod().toString());
boolean connectRequest = request.getMethod().equals(Methods.CONNECT);
if (!connectRequest) {
request.getRequestHeaders().put(PATH, request.getPath());
request.getRequestHeaders().put(SCHEME, secure ? "https" : "http");
}
final String host = request.getRequestHeaders().getFirst(Headers.HOST);
if (host != null) {
request.getRequestHeaders().put(AUTHORITY, host);
} else {
request.getRequestHeaders().put(AUTHORITY, defaultHost);
}
request.getRequestHeaders().remove(Headers.HOST);
boolean hasContent = true;
String fixedLengthString = request.getRequestHeaders().getFirst(CONTENT_LENGTH);
String transferEncodingString = request.getRequestHeaders().getLast(TRANSFER_ENCODING);
if (fixedLengthString != null) {
try {
long length = Long.parseLong(fixedLengthString);
hasContent = length != 0;
} catch (NumberFormatException e) {
handleError(new IOException(e));
return;
}
} else if (transferEncodingString == null && !connectRequest) {
hasContent = false;
}
request.getRequestHeaders().remove(Headers.CONNECTION);
request.getRequestHeaders().remove(Headers.KEEP_ALIVE);
request.getRequestHeaders().remove(Headers.TRANSFER_ENCODING);
//setup the X-Forwarded-* headers
String peer = request.getAttachment(ProxiedRequestAttachments.REMOTE_HOST);
if (peer != null) {
request.getRequestHeaders().put(Headers.X_FORWARDED_FOR, peer);
}
Boolean proto = request.getAttachment(ProxiedRequestAttachments.IS_SSL);
if (proto == null || !proto) {
request.getRequestHeaders().put(Headers.X_FORWARDED_PROTO, "http");
} else {
request.getRequestHeaders().put(Headers.X_FORWARDED_PROTO, "https");
}
String hn = request.getAttachment(ProxiedRequestAttachments.SERVER_NAME);
if (hn != null) {
request.getRequestHeaders().put(Headers.X_FORWARDED_HOST, NetworkUtils.formatPossibleIpv6Address(hn));
}
Integer port = request.getAttachment(ProxiedRequestAttachments.SERVER_PORT);
if (port != null) {
request.getRequestHeaders().put(Headers.X_FORWARDED_PORT, port);
}
Http2HeadersStreamSinkChannel sinkChannel;
try {
sinkChannel = http2Channel.createStream(request.getRequestHeaders());
} catch (IOException e) {
clientCallback.failed(e);
return;
}
Http2ClientExchange exchange = new Http2ClientExchange(this, sinkChannel, request);
currentExchanges.put(sinkChannel.getStreamId(), exchange);
if (clientCallback != null) {
clientCallback.completed(exchange);
}
if (!hasContent) {
//otherwise it is up to the user
try {
sinkChannel.shutdownWrites();
if (!sinkChannel.flush()) {
sinkChannel.getWriteSetter().set(ChannelListeners.flushingChannelListener(null, new ChannelExceptionHandler<StreamSinkChannel>() {
@Override
public void handleException(StreamSinkChannel channel, IOException exception) {
handleError(exception);
}
}));
sinkChannel.resumeWrites();
}
} catch (IOException e) {
handleError(e);
}
} else if (!sinkChannel.isWriteResumed()) {
try {
//TODO: this needs some more thought
if (!sinkChannel.flush()) {
sinkChannel.getWriteSetter().set(new ChannelListener<StreamSinkChannel>() {
@Override
public void handleEvent(StreamSinkChannel channel) {
try {
if (channel.flush()) {
channel.suspendWrites();
}
} catch (IOException e) {
handleError(e);
}
}
});
sinkChannel.resumeWrites();
}
} catch (IOException e) {
handleError(e);
}
}
}
use of org.xnio.channels.StreamSinkChannel in project undertow by undertow-io.
the class AsyncSenderImpl method send.
@Override
public void send(final ByteBuffer[] buffer, final IoCallback callback) {
if (callback == null) {
throw UndertowMessages.MESSAGES.argumentCannotBeNull("callback");
}
if (exchange.isResponseComplete()) {
throw UndertowMessages.MESSAGES.responseComplete();
}
if (this.buffer != null) {
throw UndertowMessages.MESSAGES.dataAlreadyQueued();
}
this.callback = callback;
if (inCallback) {
this.buffer = buffer;
return;
}
long totalToWrite = Buffers.remaining(buffer);
long responseContentLength = exchange.getResponseContentLength();
if (responseContentLength > 0 && totalToWrite > responseContentLength) {
invokeOnException(callback, UndertowLogger.ROOT_LOGGER.dataLargerThanContentLength(totalToWrite, responseContentLength));
return;
}
StreamSinkChannel channel = this.channel;
if (channel == null) {
if (callback == IoCallback.END_EXCHANGE) {
if (responseContentLength == -1 && !exchange.getResponseHeaders().contains(Headers.TRANSFER_ENCODING)) {
exchange.setResponseContentLength(totalToWrite);
}
}
this.channel = channel = exchange.getResponseChannel();
if (channel == null) {
throw UndertowMessages.MESSAGES.responseChannelAlreadyProvided();
}
}
final long total = totalToWrite;
long written = 0;
try {
do {
long res = channel.write(buffer);
written += res;
if (res == 0) {
this.buffer = buffer;
this.callback = callback;
if (writeListener == null) {
initWriteListener();
}
channel.getWriteSetter().set(writeListener);
channel.resumeWrites();
return;
}
} while (written < total);
invokeOnComplete();
} catch (IOException e) {
invokeOnException(callback, e);
}
}
Aggregations