use of org.xnio.channels.StreamSinkChannel in project spring-framework by spring-projects.
the class UndertowServerHttpResponse method writeWith.
@Override
public Mono<Void> writeWith(File file, long position, long count) {
return doCommit(() -> {
FileChannel source = null;
try {
source = new FileInputStream(file).getChannel();
StreamSinkChannel destination = getUndertowExchange().getResponseChannel();
Channels.transferBlocking(destination, source, position, count);
return Mono.empty();
} catch (IOException ex) {
return Mono.error(ex);
} finally {
if (source != null) {
try {
source.close();
} catch (IOException ex) {
// ignore
}
}
}
});
}
use of org.xnio.channels.StreamSinkChannel in project undertow by undertow-io.
the class UndertowOutputStream method close.
/**
* {@inheritDoc}
*/
public void close() throws IOException {
if (anyAreSet(state, FLAG_CLOSED))
return;
try {
state |= FLAG_CLOSED;
if (anyAreClear(state, FLAG_WRITE_STARTED) && channel == null) {
if (buffer == null) {
exchange.getResponseHeaders().put(Headers.CONTENT_LENGTH, "0");
} else {
exchange.getResponseHeaders().put(Headers.CONTENT_LENGTH, "" + buffer.position());
}
}
if (buffer != null) {
writeBufferBlocking(true);
}
if (channel == null) {
channel = exchange.getResponseChannel();
}
if (channel == null) {
return;
}
StreamSinkChannel channel = this.channel;
channel.shutdownWrites();
Channels.flushBlocking(channel);
} finally {
if (pooledBuffer != null) {
pooledBuffer.close();
buffer = null;
} else {
buffer = null;
}
}
}
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 || this.fileChannel != null) {
throw UndertowMessages.MESSAGES.dataAlreadyQueued();
}
long responseContentLength = exchange.getResponseContentLength();
if (responseContentLength > 0 && buffer.remaining() > responseContentLength) {
invokeOnException(callback, UndertowLogger.ROOT_LOGGER.dataLargerThanContentLength(buffer.remaining(), 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(buffer.remaining());
}
}
this.channel = channel = exchange.getResponseChannel();
if (channel == null) {
throw UndertowMessages.MESSAGES.responseChannelAlreadyProvided();
}
}
this.callback = callback;
if (inCallback) {
this.buffer = new ByteBuffer[] { buffer };
return;
}
try {
do {
if (buffer.remaining() == 0) {
callback.onComplete(exchange, this);
return;
}
int res = channel.write(buffer);
if (res == 0) {
this.buffer = new ByteBuffer[] { buffer };
this.callback = callback;
if (writeListener == null) {
initWriteListener();
}
channel.getWriteSetter().set(writeListener);
channel.resumeWrites();
return;
}
} while (buffer.hasRemaining());
invokeOnComplete();
} catch (IOException e) {
invokeOnException(callback, e);
}
}
use of org.xnio.channels.StreamSinkChannel in project undertow by undertow-io.
the class ServerSentEventHandler method handleRequest.
@Override
public void handleRequest(final HttpServerExchange exchange) throws Exception {
exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/event-stream; charset=UTF-8");
exchange.setPersistent(false);
final StreamSinkChannel sink = exchange.getResponseChannel();
if (!sink.flush()) {
sink.getWriteSetter().set(ChannelListeners.flushingChannelListener(new ChannelListener<StreamSinkChannel>() {
@Override
public void handleEvent(StreamSinkChannel channel) {
handleConnect(channel, exchange);
}
}, new ChannelExceptionHandler<StreamSinkChannel>() {
@Override
public void handleException(StreamSinkChannel channel, IOException exception) {
IoUtils.safeClose(exchange.getConnection());
}
}));
sink.resumeWrites();
} else {
exchange.dispatch(exchange.getIoThread(), new Runnable() {
@Override
public void run() {
handleConnect(sink, exchange);
}
});
}
}
use of org.xnio.channels.StreamSinkChannel in project undertow by undertow-io.
the class AjpReadListener method handleEvent.
public void handleEvent(final StreamSourceChannel channel) {
if (connection.getOriginalSinkConduit().isWriteShutdown() || connection.getOriginalSourceConduit().isReadShutdown()) {
safeClose(connection);
channel.suspendReads();
return;
}
PooledByteBuffer existing = connection.getExtraBytes();
final PooledByteBuffer pooled = existing == null ? connection.getByteBufferPool().allocate() : existing;
final ByteBuffer buffer = pooled.getBuffer();
boolean free = true;
boolean bytesRead = false;
try {
int res;
do {
if (existing == null) {
buffer.clear();
try {
res = channel.read(buffer);
} catch (IOException e) {
UndertowLogger.REQUEST_IO_LOGGER.ioException(e);
safeClose(connection);
return;
}
} else {
res = buffer.remaining();
}
if (res == 0) {
if (bytesRead && parseTimeoutUpdater != null) {
parseTimeoutUpdater.failedParse();
}
if (!channel.isReadResumed()) {
channel.getReadSetter().set(this);
channel.resumeReads();
}
return;
}
if (res == -1) {
try {
channel.shutdownReads();
final StreamSinkChannel responseChannel = connection.getChannel().getSinkChannel();
responseChannel.shutdownWrites();
safeClose(connection);
} catch (IOException e) {
UndertowLogger.REQUEST_IO_LOGGER.ioException(e);
// fuck it, it's all ruined
safeClose(connection);
return;
}
return;
}
bytesRead = true;
//TODO: we need to handle parse errors
if (existing != null) {
existing = null;
connection.setExtraBytes(null);
} else {
buffer.flip();
}
int begin = buffer.remaining();
if (httpServerExchange == null) {
httpServerExchange = new HttpServerExchange(connection, maxEntitySize);
}
parser.parse(buffer, state, httpServerExchange);
read += begin - buffer.remaining();
if (buffer.hasRemaining()) {
free = false;
connection.setExtraBytes(pooled);
}
if (read > maxRequestSize) {
UndertowLogger.REQUEST_LOGGER.requestHeaderWasTooLarge(connection.getPeerAddress(), maxRequestSize);
safeClose(connection);
return;
}
} while (!state.isComplete());
if (parseTimeoutUpdater != null) {
parseTimeoutUpdater.requestStarted();
}
if (state.prefix != AjpRequestParser.FORWARD_REQUEST) {
if (state.prefix == AjpRequestParser.CPING) {
UndertowLogger.REQUEST_LOGGER.debug("Received CPING, sending CPONG");
handleCPing();
} else if (state.prefix == AjpRequestParser.CPONG) {
UndertowLogger.REQUEST_LOGGER.debug("Received CPONG, starting next request");
state = new AjpRequestParseState();
channel.getReadSetter().set(this);
channel.resumeReads();
} else {
UndertowLogger.REQUEST_LOGGER.ignoringAjpRequestWithPrefixCode(state.prefix);
safeClose(connection);
}
return;
}
// we remove ourselves as the read listener from the channel;
// if the http handler doesn't set any then reads will suspend, which is the right thing to do
channel.getReadSetter().set(null);
channel.suspendReads();
final HttpServerExchange httpServerExchange = this.httpServerExchange;
final AjpServerResponseConduit responseConduit = new AjpServerResponseConduit(connection.getChannel().getSinkChannel().getConduit(), connection.getByteBufferPool(), httpServerExchange, new ConduitListener<AjpServerResponseConduit>() {
@Override
public void handleEvent(AjpServerResponseConduit channel) {
Connectors.terminateResponse(httpServerExchange);
}
}, httpServerExchange.getRequestMethod().equals(Methods.HEAD));
connection.getChannel().getSinkChannel().setConduit(responseConduit);
connection.getChannel().getSourceChannel().setConduit(createSourceConduit(connection.getChannel().getSourceChannel().getConduit(), responseConduit, httpServerExchange));
//we need to set the write ready handler. This allows the response conduit to wrap it
responseConduit.setWriteReadyHandler(writeReadyHandler);
try {
connection.setSSLSessionInfo(state.createSslSessionInfo());
httpServerExchange.setSourceAddress(state.createPeerAddress());
httpServerExchange.setDestinationAddress(state.createDestinationAddress());
if (scheme != null) {
httpServerExchange.setRequestScheme(scheme);
}
if (state.attributes != null) {
httpServerExchange.putAttachment(HttpServerExchange.REQUEST_ATTRIBUTES, state.attributes);
}
AjpRequestParseState oldState = state;
state = null;
this.httpServerExchange = null;
httpServerExchange.setPersistent(true);
if (recordRequestStartTime) {
Connectors.setRequestStartTime(httpServerExchange);
}
connection.setCurrentExchange(httpServerExchange);
if (connectorStatistics != null) {
connectorStatistics.setup(httpServerExchange);
}
if (oldState.badRequest) {
httpServerExchange.setStatusCode(StatusCodes.BAD_REQUEST);
httpServerExchange.endExchange();
} else {
Connectors.executeRootHandler(connection.getRootHandler(), httpServerExchange);
}
} catch (Throwable t) {
//TODO: we should attempt to return a 500 status code in this situation
UndertowLogger.REQUEST_LOGGER.exceptionProcessingRequest(t);
safeClose(connection);
}
} catch (Exception e) {
UndertowLogger.REQUEST_LOGGER.exceptionProcessingRequest(e);
safeClose(connection);
} finally {
if (free)
pooled.close();
}
}
Aggregations