Search in sources :

Example 6 with StreamSinkChannel

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;
        }
    }
}
Also used : PooledByteBuffer(io.undertow.connector.PooledByteBuffer) StreamSinkChannel(org.xnio.channels.StreamSinkChannel) IOException(java.io.IOException)

Example 7 with StreamSinkChannel

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);
        }
    }
}
Also used : ChannelListener(org.xnio.ChannelListener) StreamSinkChannel(org.xnio.channels.StreamSinkChannel) ChannelExceptionHandler(org.xnio.ChannelExceptionHandler) IOException(java.io.IOException)

Example 8 with StreamSinkChannel

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);
}
Also used : ByteBufferPool(io.undertow.connector.ByteBufferPool) PooledByteBuffer(io.undertow.connector.PooledByteBuffer) StreamSinkChannel(org.xnio.channels.StreamSinkChannel) ByteBuffer(java.nio.ByteBuffer) PooledByteBuffer(io.undertow.connector.PooledByteBuffer)

Example 9 with StreamSinkChannel

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);
        }
    };
}
Also used : HttpServerExchange(io.undertow.server.HttpServerExchange) TimeUnit(java.util.concurrent.TimeUnit) StreamSinkChannel(org.xnio.channels.StreamSinkChannel)

Example 10 with StreamSinkChannel

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()));
            }
        }
    };
}
Also used : ClientExchange(io.undertow.client.ClientExchange) ClientResponse(io.undertow.client.ClientResponse) ClientCallback(io.undertow.client.ClientCallback) HttpStatus(org.springframework.http.HttpStatus) StreamSinkChannel(org.xnio.channels.StreamSinkChannel) IOException(java.io.IOException) CloseStatus(org.springframework.web.socket.CloseStatus) HttpServerErrorException(org.springframework.web.client.HttpServerErrorException)

Aggregations

StreamSinkChannel (org.xnio.channels.StreamSinkChannel)19 IOException (java.io.IOException)14 ChannelListener (org.xnio.ChannelListener)5 PooledByteBuffer (io.undertow.connector.PooledByteBuffer)4 HttpServerExchange (io.undertow.server.HttpServerExchange)4 ByteBuffer (java.nio.ByteBuffer)4 ChannelExceptionHandler (org.xnio.ChannelExceptionHandler)4 Channel (java.nio.channels.Channel)3 ByteBufferPool (io.undertow.connector.ByteBufferPool)2 TestHttpClient (io.undertow.testutils.TestHttpClient)2 StringWriteChannelListener (io.undertow.util.StringWriteChannelListener)2 InputStream (java.io.InputStream)2 Test (org.junit.Test)2 ConduitStreamSinkChannel (org.xnio.conduits.ConduitStreamSinkChannel)2 ClientCallback (io.undertow.client.ClientCallback)1 ClientExchange (io.undertow.client.ClientExchange)1 ClientResponse (io.undertow.client.ClientResponse)1 Http2HeadersStreamSinkChannel (io.undertow.protocols.http2.Http2HeadersStreamSinkChannel)1 HttpHandler (io.undertow.server.HttpHandler)1 HttpUpgradeListener (io.undertow.server.HttpUpgradeListener)1