Search in sources :

Example 1 with StreamSinkChannel

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);
    }
}
Also used : InetSocketAddress(java.net.InetSocketAddress) StreamSinkChannel(org.xnio.channels.StreamSinkChannel) IoFuture(org.xnio.IoFuture) StreamConnection(org.xnio.StreamConnection) HttpServerExchange(io.undertow.server.HttpServerExchange) HttpUpgradeListener(io.undertow.server.HttpUpgradeListener)

Example 2 with StreamSinkChannel

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();
        }
    }
}
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 3 with StreamSinkChannel

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

Example 4 with StreamSinkChannel

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

Example 5 with StreamSinkChannel

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

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