use of org.xnio.channels.StreamSinkChannel in project undertow by undertow-io.
the class AsyncSenderImpl method invokeOnComplete.
/**
* Invokes the onComplete method. If send is called again in onComplete then
* we loop and write it out. This prevents possible stack overflows due to recursion
*/
private void invokeOnComplete() {
for (; ; ) {
if (pooledBuffers != null) {
for (PooledByteBuffer buffer : pooledBuffers) {
buffer.close();
}
pooledBuffers = null;
}
IoCallback callback = this.callback;
this.buffer = null;
this.fileChannel = null;
this.callback = null;
inCallback = true;
try {
callback.onComplete(exchange, this);
} finally {
inCallback = false;
}
StreamSinkChannel channel = this.channel;
if (this.buffer != null) {
long t = Buffers.remaining(buffer);
final long total = t;
long written = 0;
try {
do {
long res = channel.write(buffer);
written += res;
if (res == 0) {
if (writeListener == null) {
initWriteListener();
}
channel.getWriteSetter().set(writeListener);
channel.resumeWrites();
return;
}
} while (written < total);
//we loop and invoke onComplete again
} catch (IOException e) {
invokeOnException(callback, e);
}
} else if (this.fileChannel != null) {
if (transferTask == null) {
transferTask = new TransferTask();
}
if (!transferTask.run(false)) {
return;
}
} else {
return;
}
}
}
use of org.xnio.channels.StreamSinkChannel in project undertow by undertow-io.
the class AsyncSenderImpl method close.
@Override
public void close(final IoCallback callback) {
try {
StreamSinkChannel channel = this.channel;
if (channel == null) {
if (exchange.getResponseContentLength() == -1 && !exchange.getResponseHeaders().contains(Headers.TRANSFER_ENCODING)) {
exchange.setResponseContentLength(0);
}
this.channel = channel = exchange.getResponseChannel();
if (channel == null) {
throw UndertowMessages.MESSAGES.responseChannelAlreadyProvided();
}
}
channel.shutdownWrites();
if (!channel.flush()) {
channel.getWriteSetter().set(ChannelListeners.flushingChannelListener(new ChannelListener<StreamSinkChannel>() {
@Override
public void handleEvent(final StreamSinkChannel channel) {
if (callback != null) {
callback.onComplete(exchange, AsyncSenderImpl.this);
}
}
}, new ChannelExceptionHandler<StreamSinkChannel>() {
@Override
public void handleException(final StreamSinkChannel channel, final IOException exception) {
try {
if (callback != null) {
invokeOnException(callback, exception);
}
} finally {
IoUtils.safeClose(channel);
}
}
}));
channel.resumeWrites();
} else {
if (callback != null) {
callback.onComplete(exchange, this);
}
}
} catch (IOException e) {
if (callback != null) {
invokeOnException(callback, e);
}
}
}
use of org.xnio.channels.StreamSinkChannel in project undertow by undertow-io.
the class UndertowOutputStream method write.
/**
* {@inheritDoc}
*/
public void write(final byte[] b, final int off, final int len) throws IOException {
if (len < 1) {
return;
}
if (Thread.currentThread() == exchange.getIoThread()) {
throw UndertowMessages.MESSAGES.blockingIoFromIOThread();
}
if (anyAreSet(state, FLAG_CLOSED)) {
throw UndertowMessages.MESSAGES.streamIsClosed();
}
//if this is the last of the content
ByteBuffer buffer = buffer();
if (len == contentLength - written || buffer.remaining() < len) {
if (buffer.remaining() < len) {
//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 = exchange.getResponseChannel();
}
final ByteBufferPool bufferPool = exchange.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, len - bytesWritten);
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, len - bytesWritten);
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();
}
}
} else {
buffer.put(b, off, len);
if (buffer.remaining() == 0) {
writeBufferBlocking(false);
}
}
} else {
buffer.put(b, off, len);
if (buffer.remaining() == 0) {
writeBufferBlocking(false);
}
}
updateWritten(len);
}
use of org.xnio.channels.StreamSinkChannel in project undertow by undertow-io.
the class HttpContinue method createResponseSender.
/**
* Creates a response sender that can be used to send a HTTP 100-continue response.
*
* @param exchange The exchange
* @return The response sender
*/
public static ContinueResponseSender createResponseSender(final HttpServerExchange exchange) throws IOException {
if (!exchange.isResponseChannelAvailable()) {
throw UndertowMessages.MESSAGES.cannotSendContinueResponse();
}
if (exchange.getAttachment(ALREADY_SENT) != null) {
return new ContinueResponseSender() {
@Override
public boolean send() throws IOException {
return true;
}
@Override
public void awaitWritable() throws IOException {
}
@Override
public void awaitWritable(long time, TimeUnit timeUnit) throws IOException {
}
};
}
HttpServerExchange newExchange = exchange.getConnection().sendOutOfBandResponse(exchange);
exchange.putAttachment(ALREADY_SENT, true);
newExchange.setStatusCode(StatusCodes.CONTINUE);
newExchange.getResponseHeaders().put(Headers.CONTENT_LENGTH, 0);
final StreamSinkChannel responseChannel = newExchange.getResponseChannel();
return new ContinueResponseSender() {
boolean shutdown = false;
@Override
public boolean send() throws IOException {
if (!shutdown) {
shutdown = true;
responseChannel.shutdownWrites();
}
return responseChannel.flush();
}
@Override
public void awaitWritable() throws IOException {
responseChannel.awaitWritable();
}
@Override
public void awaitWritable(final long time, final TimeUnit timeUnit) throws IOException {
responseChannel.awaitWritable(time, timeUnit);
}
};
}
use of org.xnio.channels.StreamSinkChannel in project spring-framework by spring-projects.
the class UndertowXhrTransport method createReceiveCallback.
private ClientCallback<ClientExchange> createReceiveCallback(final TransportRequest transportRequest, final URI url, final HttpHeaders headers, final XhrClientSockJsSession sockJsSession, final SettableListenableFuture<WebSocketSession> connectFuture) {
return new ClientCallback<ClientExchange>() {
@Override
public void completed(final ClientExchange exchange) {
exchange.setResponseListener(new ClientCallback<ClientExchange>() {
@Override
public void completed(ClientExchange result) {
ClientResponse response = result.getResponse();
if (response.getResponseCode() != 200) {
HttpStatus status = HttpStatus.valueOf(response.getResponseCode());
IoUtils.safeClose(result.getConnection());
onFailure(new HttpServerErrorException(status, "Unexpected XHR receive status"));
} else {
SockJsResponseListener listener = new SockJsResponseListener(transportRequest, result.getConnection(), url, headers, sockJsSession, connectFuture);
listener.setup(result.getResponseChannel());
}
if (logger.isTraceEnabled()) {
logger.trace("XHR receive headers: " + toHttpHeaders(response.getResponseHeaders()));
}
try {
StreamSinkChannel channel = result.getRequestChannel();
channel.shutdownWrites();
if (!channel.flush()) {
channel.getWriteSetter().set(ChannelListeners.<StreamSinkChannel>flushingChannelListener(null, null));
channel.resumeWrites();
}
} catch (IOException exc) {
IoUtils.safeClose(result.getConnection());
onFailure(exc);
}
}
@Override
public void failed(IOException exc) {
IoUtils.safeClose(exchange.getConnection());
onFailure(exc);
}
});
}
@Override
public void failed(IOException exc) {
onFailure(exc);
}
private void onFailure(Throwable failure) {
if (connectFuture.setException(failure)) {
return;
}
if (sockJsSession.isDisconnected()) {
sockJsSession.afterTransportClosed(null);
} else {
sockJsSession.handleTransportError(failure);
sockJsSession.afterTransportClosed(new CloseStatus(1006, failure.getMessage()));
}
}
};
}
Aggregations