Search in sources :

Example 1 with ConduitStreamSinkChannel

use of org.xnio.conduits.ConduitStreamSinkChannel in project undertow by undertow-io.

the class ContentEncodedResourceManager method getResource.

/**
     * Gets a pre-encoded resource.
     * <p>
     * TODO: blocking / non-blocking semantics
     *
     * @param resource
     * @param exchange
     * @return
     * @throws IOException
     */
public ContentEncodedResource getResource(final Resource resource, final HttpServerExchange exchange) throws IOException {
    final String path = resource.getPath();
    Path file = resource.getFilePath();
    if (file == null) {
        return null;
    }
    if (minResourceSize > 0 && resource.getContentLength() < minResourceSize || maxResourceSize > 0 && resource.getContentLength() > maxResourceSize || !(encodingAllowed == null || encodingAllowed.resolve(exchange))) {
        return null;
    }
    AllowedContentEncodings encodings = contentEncodingRepository.getContentEncodings(exchange);
    if (encodings == null || encodings.isNoEncodingsAllowed()) {
        return null;
    }
    EncodingMapping encoding = encodings.getEncoding();
    if (encoding == null || encoding.getName().equals(ContentEncodingRepository.IDENTITY)) {
        return null;
    }
    String newPath = path + ".undertow.encoding." + encoding.getName();
    Resource preCompressed = encoded.getResource(newPath);
    if (preCompressed != null) {
        return new ContentEncodedResource(preCompressed, encoding.getName());
    }
    final LockKey key = new LockKey(path, encoding.getName());
    if (fileLocks.putIfAbsent(key, this) != null) {
        //we don't do anything fancy here, just return and serve non-compressed content
        return null;
    }
    FileChannel targetFileChannel = null;
    FileChannel sourceFileChannel = null;
    try {
        //double check, the compressing thread could have finished just before we acquired the lock
        preCompressed = encoded.getResource(newPath);
        if (preCompressed != null) {
            return new ContentEncodedResource(preCompressed, encoding.getName());
        }
        final Path finalTarget = encodedResourcesRoot.resolve(newPath);
        final Path tempTarget = encodedResourcesRoot.resolve(newPath);
        //horrible hack to work around XNIO issue
        OutputStream tmp = Files.newOutputStream(tempTarget);
        try {
            tmp.close();
        } finally {
            IoUtils.safeClose(tmp);
        }
        targetFileChannel = FileChannel.open(tempTarget, StandardOpenOption.READ, StandardOpenOption.WRITE);
        sourceFileChannel = FileChannel.open(file, StandardOpenOption.READ);
        StreamSinkConduit conduit = encoding.getEncoding().getResponseWrapper().wrap(new ImmediateConduitFactory<StreamSinkConduit>(new FileConduitTarget(targetFileChannel, exchange)), exchange);
        final ConduitStreamSinkChannel targetChannel = new ConduitStreamSinkChannel(null, conduit);
        long transferred = sourceFileChannel.transferTo(0, resource.getContentLength(), targetChannel);
        targetChannel.shutdownWrites();
        org.xnio.channels.Channels.flushBlocking(targetChannel);
        if (transferred != resource.getContentLength()) {
            UndertowLogger.REQUEST_LOGGER.failedToWritePreCachedFile();
        }
        Files.move(tempTarget, finalTarget);
        encoded.invalidate(newPath);
        final Resource encodedResource = encoded.getResource(newPath);
        return new ContentEncodedResource(encodedResource, encoding.getName());
    } finally {
        IoUtils.safeClose(targetFileChannel);
        IoUtils.safeClose(sourceFileChannel);
        fileLocks.remove(key);
    }
}
Also used : Path(java.nio.file.Path) FileChannel(java.nio.channels.FileChannel) OutputStream(java.io.OutputStream) Resource(io.undertow.server.handlers.resource.Resource) StreamSinkConduit(org.xnio.conduits.StreamSinkConduit) ConduitStreamSinkChannel(org.xnio.conduits.ConduitStreamSinkChannel)

Example 2 with ConduitStreamSinkChannel

use of org.xnio.conduits.ConduitStreamSinkChannel in project undertow by undertow-io.

the class HttpClientConnection method initiateRequest.

private void initiateRequest(HttpClientExchange httpClientExchange) {
    this.requestCount++;
    currentRequest = httpClientExchange;
    pendingResponse = new HttpResponseBuilder();
    ClientRequest request = httpClientExchange.getRequest();
    String connectionString = request.getRequestHeaders().getFirst(CONNECTION);
    if (connectionString != null) {
        HttpString connectionHttpString = new HttpString(connectionString);
        if (connectionHttpString.equals(CLOSE)) {
            state |= CLOSE_REQ;
        } else if (connectionHttpString.equals(UPGRADE)) {
            state |= UPGRADE_REQUESTED;
        }
    } else if (request.getProtocol() != Protocols.HTTP_1_1) {
        state |= CLOSE_REQ;
    }
    if (request.getRequestHeaders().contains(UPGRADE)) {
        state |= UPGRADE_REQUESTED;
    }
    if (request.getMethod().equals(Methods.CONNECT)) {
        //we treat CONNECT like upgrade requests
        state |= UPGRADE_REQUESTED;
    }
    //setup the client request conduits
    final ConduitStreamSourceChannel sourceChannel = connection.getSourceChannel();
    sourceChannel.setReadListener(clientReadListener);
    sourceChannel.resumeReads();
    ConduitStreamSinkChannel sinkChannel = connection.getSinkChannel();
    StreamSinkConduit conduit = originalSinkConduit;
    conduit = new HttpRequestConduit(conduit, bufferPool, request);
    String fixedLengthString = request.getRequestHeaders().getFirst(CONTENT_LENGTH);
    String transferEncodingString = request.getRequestHeaders().getLast(TRANSFER_ENCODING);
    boolean hasContent = true;
    if (fixedLengthString != null) {
        try {
            long length = Long.parseLong(fixedLengthString);
            conduit = new ClientFixedLengthStreamSinkConduit(conduit, length, false, false, currentRequest);
            hasContent = length != 0;
        } catch (NumberFormatException e) {
            handleError(new IOException(e));
            return;
        }
    } else if (transferEncodingString != null) {
        if (!transferEncodingString.toLowerCase(Locale.ENGLISH).contains(Headers.CHUNKED.toString())) {
            handleError(UndertowClientMessages.MESSAGES.unknownTransferEncoding(transferEncodingString));
            return;
        }
        conduit = new ChunkedStreamSinkConduit(conduit, httpClientExchange.getConnection().getBufferPool(), false, false, httpClientExchange.getRequest().getRequestHeaders(), requestFinishListener, httpClientExchange);
    } else {
        conduit = new ClientFixedLengthStreamSinkConduit(conduit, 0, false, false, currentRequest);
        hasContent = false;
    }
    sinkChannel.setConduit(conduit);
    httpClientExchange.invokeReadReadyCallback();
    if (!hasContent) {
        //otherwise it is up to the user
        try {
            sinkChannel.shutdownWrites();
            if (!sinkChannel.flush()) {
                sinkChannel.setWriteListener(ChannelListeners.flushingChannelListener(null, new ChannelExceptionHandler<ConduitStreamSinkChannel>() {

                    @Override
                    public void handleException(ConduitStreamSinkChannel channel, IOException exception) {
                        handleError(exception);
                    }
                }));
                sinkChannel.resumeWrites();
            }
        } catch (IOException e) {
            handleError(e);
        }
    }
}
Also used : ChunkedStreamSinkConduit(io.undertow.conduits.ChunkedStreamSinkConduit) HttpString(io.undertow.util.HttpString) IOException(java.io.IOException) StreamSinkConduit(org.xnio.conduits.StreamSinkConduit) BytesSentStreamSinkConduit(io.undertow.conduits.BytesSentStreamSinkConduit) ChunkedStreamSinkConduit(io.undertow.conduits.ChunkedStreamSinkConduit) ChannelExceptionHandler(org.xnio.ChannelExceptionHandler) ConduitStreamSourceChannel(org.xnio.conduits.ConduitStreamSourceChannel) ClientRequest(io.undertow.client.ClientRequest) ConduitStreamSinkChannel(org.xnio.conduits.ConduitStreamSinkChannel) HttpString(io.undertow.util.HttpString)

Example 3 with ConduitStreamSinkChannel

use of org.xnio.conduits.ConduitStreamSinkChannel in project undertow by undertow-io.

the class Http2PriorKnowledgeClientProvider method handleConnected.

private void handleConnected(final StreamConnection connection, final ClientCallback<ClientConnection> listener, final ByteBufferPool bufferPool, final OptionMap options, final String defaultHost) {
    try {
        final ClientStatisticsImpl clientStatistics;
        //first we set up statistics, if required
        if (options.get(UndertowOptions.ENABLE_STATISTICS, false)) {
            clientStatistics = new ClientStatisticsImpl();
            connection.getSinkChannel().setConduit(new BytesSentStreamSinkConduit(connection.getSinkChannel().getConduit(), new ByteActivityCallback() {

                @Override
                public void activity(long bytes) {
                    clientStatistics.written += bytes;
                }
            }));
            connection.getSourceChannel().setConduit(new BytesReceivedStreamSourceConduit(connection.getSourceChannel().getConduit(), new ByteActivityCallback() {

                @Override
                public void activity(long bytes) {
                    clientStatistics.read += bytes;
                }
            }));
        } else {
            clientStatistics = null;
        }
        final ByteBuffer pri = ByteBuffer.wrap(PRI_REQUEST);
        pri.flip();
        ConduitStreamSinkChannel sink = connection.getSinkChannel();
        sink.write(pri);
        if (pri.hasRemaining()) {
            sink.setWriteListener(new ChannelListener<ConduitStreamSinkChannel>() {

                @Override
                public void handleEvent(ConduitStreamSinkChannel channel) {
                    try {
                        channel.write(pri);
                        if (pri.hasRemaining()) {
                            return;
                        }
                        listener.completed(new Http2ClientConnection(new Http2Channel(connection, null, bufferPool, null, true, false, options), false, defaultHost, clientStatistics, false));
                    } catch (IOException e) {
                        listener.failed(e);
                    }
                }
            });
            return;
        }
        listener.completed(new Http2ClientConnection(new Http2Channel(connection, null, bufferPool, null, true, false, options), false, defaultHost, clientStatistics, false));
    } catch (IOException e) {
        listener.failed(e);
    }
}
Also used : Http2Channel(io.undertow.protocols.http2.Http2Channel) ByteActivityCallback(io.undertow.conduits.ByteActivityCallback) IOException(java.io.IOException) BytesSentStreamSinkConduit(io.undertow.conduits.BytesSentStreamSinkConduit) BytesReceivedStreamSourceConduit(io.undertow.conduits.BytesReceivedStreamSourceConduit) ByteBuffer(java.nio.ByteBuffer) ConduitStreamSinkChannel(org.xnio.conduits.ConduitStreamSinkChannel)

Example 4 with ConduitStreamSinkChannel

use of org.xnio.conduits.ConduitStreamSinkChannel in project undertow by undertow-io.

the class HttpReadListener method exchangeComplete.

public void exchangeComplete(final HttpServerExchange exchange) {
    connection.clearChannel();
    final HttpServerConnection connection = this.connection;
    if (exchange.isPersistent() && !isUpgradeOrConnect(exchange)) {
        final StreamConnection channel = connection.getChannel();
        if (connection.getExtraBytes() == null) {
            //we have to resume from with the io thread
            if (exchange.isInIoThread()) {
                //no need for CAS, we are in the IO thread
                newRequest();
                channel.getSourceChannel().setReadListener(HttpReadListener.this);
                channel.getSourceChannel().resumeReads();
                requestStateUpdater.set(this, 0);
            } else {
                while (true) {
                    if (connection.getOriginalSourceConduit().isReadShutdown() || connection.getOriginalSinkConduit().isWriteShutdown()) {
                        channel.getSourceChannel().suspendReads();
                        channel.getSinkChannel().suspendWrites();
                        IoUtils.safeClose(connection);
                        return;
                    } else {
                        if (requestStateUpdater.compareAndSet(this, 1, 2)) {
                            try {
                                newRequest();
                                channel.getSourceChannel().setReadListener(HttpReadListener.this);
                                channel.getSourceChannel().resumeReads();
                            } finally {
                                requestStateUpdater.set(this, 0);
                            }
                            break;
                        }
                    }
                }
            }
        } else {
            if (exchange.isInIoThread()) {
                //no need to CAS, as we don't actually resume
                requestStateUpdater.set(this, 0);
                newRequest();
                //no need to suspend reads here, the task will always run before the read listener anyway
                channel.getIoThread().execute(this);
            } else {
                while (true) {
                    if (connection.getOriginalSinkConduit().isWriteShutdown()) {
                        channel.getSourceChannel().suspendReads();
                        channel.getSinkChannel().suspendWrites();
                        IoUtils.safeClose(connection);
                        return;
                    } else if (requestStateUpdater.compareAndSet(this, 1, 2)) {
                        try {
                            newRequest();
                            channel.getSourceChannel().suspendReads();
                        } finally {
                            requestStateUpdater.set(this, 0);
                        }
                        break;
                    }
                }
                Executor executor = exchange.getDispatchExecutor();
                if (executor == null) {
                    executor = exchange.getConnection().getWorker();
                }
                executor.execute(this);
            }
        }
    } else if (!exchange.isPersistent()) {
        ConnectionUtils.cleanClose(connection.getChannel(), connection);
    } else {
        //upgrade or connect handling
        if (connection.getExtraBytes() != null) {
            connection.getChannel().getSourceChannel().setConduit(new ReadDataStreamSourceConduit(connection.getChannel().getSourceChannel().getConduit(), connection));
        }
        try {
            if (!connection.getChannel().getSinkChannel().flush()) {
                connection.getChannel().getSinkChannel().setWriteListener(ChannelListeners.flushingChannelListener(new ChannelListener<ConduitStreamSinkChannel>() {

                    @Override
                    public void handleEvent(ConduitStreamSinkChannel conduitStreamSinkChannel) {
                        connection.getUpgradeListener().handleUpgrade(connection.getChannel(), exchange);
                    }
                }, new ClosingChannelExceptionHandler<ConduitStreamSinkChannel>(connection)));
                connection.getChannel().getSinkChannel().resumeWrites();
                return;
            }
            connection.getUpgradeListener().handleUpgrade(connection.getChannel(), exchange);
        } catch (IOException e) {
            UndertowLogger.REQUEST_IO_LOGGER.ioException(e);
            IoUtils.safeClose(connection);
        }
    }
}
Also used : Executor(java.util.concurrent.Executor) ReadDataStreamSourceConduit(io.undertow.conduits.ReadDataStreamSourceConduit) IOException(java.io.IOException) StreamConnection(org.xnio.StreamConnection) ConduitStreamSinkChannel(org.xnio.conduits.ConduitStreamSinkChannel)

Example 5 with ConduitStreamSinkChannel

use of org.xnio.conduits.ConduitStreamSinkChannel in project undertow by undertow-io.

the class AjpReadListener method handleCPing.

private void handleCPing() {
    state = new AjpRequestParseState();
    final StreamConnection underlyingChannel = connection.getChannel();
    underlyingChannel.getSourceChannel().suspendReads();
    final ByteBuffer buffer = ByteBuffer.wrap(CPONG);
    int res;
    try {
        do {
            res = underlyingChannel.getSinkChannel().write(buffer);
            if (res == 0) {
                underlyingChannel.getSinkChannel().setWriteListener(new ChannelListener<ConduitStreamSinkChannel>() {

                    @Override
                    public void handleEvent(ConduitStreamSinkChannel channel) {
                        int res;
                        do {
                            try {
                                res = channel.write(buffer);
                                if (res == 0) {
                                    return;
                                }
                            } catch (IOException e) {
                                UndertowLogger.REQUEST_IO_LOGGER.ioException(e);
                                safeClose(connection);
                            }
                        } while (buffer.hasRemaining());
                        channel.suspendWrites();
                        AjpReadListener.this.handleEvent(underlyingChannel.getSourceChannel());
                    }
                });
                underlyingChannel.getSinkChannel().resumeWrites();
                return;
            }
        } while (buffer.hasRemaining());
        AjpReadListener.this.handleEvent(underlyingChannel.getSourceChannel());
    } catch (IOException e) {
        UndertowLogger.REQUEST_IO_LOGGER.ioException(e);
        safeClose(connection);
    }
}
Also used : IOException(java.io.IOException) StreamConnection(org.xnio.StreamConnection) ByteBuffer(java.nio.ByteBuffer) PooledByteBuffer(io.undertow.connector.PooledByteBuffer) ConduitStreamSinkChannel(org.xnio.conduits.ConduitStreamSinkChannel)

Aggregations

ConduitStreamSinkChannel (org.xnio.conduits.ConduitStreamSinkChannel)7 IOException (java.io.IOException)5 StreamConnection (org.xnio.StreamConnection)3 BytesSentStreamSinkConduit (io.undertow.conduits.BytesSentStreamSinkConduit)2 ByteBuffer (java.nio.ByteBuffer)2 ConduitStreamSourceChannel (org.xnio.conduits.ConduitStreamSourceChannel)2 StreamSinkConduit (org.xnio.conduits.StreamSinkConduit)2 ClientRequest (io.undertow.client.ClientRequest)1 ByteActivityCallback (io.undertow.conduits.ByteActivityCallback)1 BytesReceivedStreamSourceConduit (io.undertow.conduits.BytesReceivedStreamSourceConduit)1 ChunkedStreamSinkConduit (io.undertow.conduits.ChunkedStreamSinkConduit)1 ReadDataStreamSourceConduit (io.undertow.conduits.ReadDataStreamSourceConduit)1 PooledByteBuffer (io.undertow.connector.PooledByteBuffer)1 Http2Channel (io.undertow.protocols.http2.Http2Channel)1 Resource (io.undertow.server.handlers.resource.Resource)1 HttpString (io.undertow.util.HttpString)1 OutputStream (java.io.OutputStream)1 FileChannel (java.nio.channels.FileChannel)1 Path (java.nio.file.Path)1 Executor (java.util.concurrent.Executor)1