Search in sources :

Example 6 with ClientRequest

use of io.undertow.client.ClientRequest in project undertow by undertow-io.

the class HttpRequestConduit method processWrite.

/**
     * Handles writing out the header data. It can also take a byte buffer of user
     * data, to enable both user data and headers to be written out in a single operation,
     * which has a noticeable performance impact.
     *
     * It is up to the caller to note the current position of this buffer before and after they
     * call this method, and use this to figure out how many bytes (if any) have been written.
     * @param state
     * @param userData
     * @return
     * @throws java.io.IOException
     */
private int processWrite(int state, final ByteBuffer userData) throws IOException {
    if (state == STATE_START) {
        pooledBuffer = pool.allocate();
    }
    ClientRequest request = this.request;
    ByteBuffer buffer = pooledBuffer.getBuffer();
    Iterator<HttpString> nameIterator = this.nameIterator;
    Iterator<String> valueIterator = this.valueIterator;
    int charIndex = this.charIndex;
    int length;
    String string = this.string;
    HttpString headerName = this.headerName;
    int res;
    // BUFFER IS FLIPPED COMING IN
    if (state != STATE_START && buffer.hasRemaining()) {
        log.trace("Flushing remaining buffer");
        do {
            res = next.write(buffer);
            if (res == 0) {
                return state;
            }
        } while (buffer.hasRemaining());
    }
    buffer.clear();
    // BUFFER IS NOW EMPTY FOR FILLING
    for (; ; ) {
        switch(state) {
            case STATE_BODY:
                {
                    // shouldn't be possible, but might as well do the right thing anyway
                    return state;
                }
            case STATE_START:
                {
                    log.trace("Starting request");
                    int len = request.getMethod().length() + request.getPath().length() + request.getProtocol().length() + 4;
                    // test that our buffer has enough space for the initial request line plus one more CR+LF
                    if (len <= buffer.remaining()) {
                        assert buffer.remaining() >= 50;
                        request.getMethod().appendTo(buffer);
                        buffer.put((byte) ' ');
                        string = request.getPath();
                        length = string.length();
                        for (charIndex = 0; charIndex < length; charIndex++) {
                            buffer.put((byte) string.charAt(charIndex));
                        }
                        buffer.put((byte) ' ');
                        request.getProtocol().appendTo(buffer);
                        buffer.put((byte) '\r').put((byte) '\n');
                    } else {
                        StringBuilder sb = new StringBuilder(len);
                        sb.append(request.getMethod().toString());
                        sb.append(" ");
                        sb.append(request.getPath());
                        sb.append(" ");
                        sb.append(request.getProtocol());
                        sb.append("\r\n");
                        string = sb.toString();
                        charIndex = 0;
                        state = STATE_URL;
                        break;
                    }
                    HeaderMap headers = request.getRequestHeaders();
                    nameIterator = headers.getHeaderNames().iterator();
                    if (!nameIterator.hasNext()) {
                        log.trace("No request headers");
                        buffer.put((byte) '\r').put((byte) '\n');
                        buffer.flip();
                        while (buffer.hasRemaining()) {
                            res = next.write(buffer);
                            if (res == 0) {
                                log.trace("Continuation");
                                return STATE_BUF_FLUSH;
                            }
                        }
                        pooledBuffer.close();
                        pooledBuffer = null;
                        log.trace("Body");
                        return STATE_BODY;
                    }
                    headerName = nameIterator.next();
                    charIndex = 0;
                // fall thru
                }
            case STATE_HDR_NAME:
                {
                    log.tracef("Processing header '%s'", headerName);
                    length = headerName.length();
                    while (charIndex < length) {
                        if (buffer.hasRemaining()) {
                            buffer.put(headerName.byteAt(charIndex++));
                        } else {
                            log.trace("Buffer flush");
                            buffer.flip();
                            do {
                                res = next.write(buffer);
                                if (res == 0) {
                                    this.string = string;
                                    this.headerName = headerName;
                                    this.charIndex = charIndex;
                                    this.valueIterator = valueIterator;
                                    this.nameIterator = nameIterator;
                                    log.trace("Continuation");
                                    return STATE_HDR_NAME;
                                }
                            } while (buffer.hasRemaining());
                            buffer.clear();
                        }
                    }
                // fall thru
                }
            case STATE_HDR_D:
                {
                    if (!buffer.hasRemaining()) {
                        buffer.flip();
                        do {
                            res = next.write(buffer);
                            if (res == 0) {
                                log.trace("Continuation");
                                this.string = string;
                                this.headerName = headerName;
                                this.charIndex = charIndex;
                                this.valueIterator = valueIterator;
                                this.nameIterator = nameIterator;
                                return STATE_HDR_D;
                            }
                        } while (buffer.hasRemaining());
                        buffer.clear();
                    }
                    buffer.put((byte) ':');
                // fall thru
                }
            case STATE_HDR_DS:
                {
                    if (!buffer.hasRemaining()) {
                        buffer.flip();
                        do {
                            res = next.write(buffer);
                            if (res == 0) {
                                log.trace("Continuation");
                                this.string = string;
                                this.headerName = headerName;
                                this.charIndex = charIndex;
                                this.valueIterator = valueIterator;
                                this.nameIterator = nameIterator;
                                return STATE_HDR_DS;
                            }
                        } while (buffer.hasRemaining());
                        buffer.clear();
                    }
                    buffer.put((byte) ' ');
                    if (valueIterator == null) {
                        valueIterator = request.getRequestHeaders().get(headerName).iterator();
                    }
                    assert valueIterator.hasNext();
                    string = valueIterator.next();
                    charIndex = 0;
                // fall thru
                }
            case STATE_HDR_VAL:
                {
                    log.tracef("Processing header value '%s'", string);
                    length = string.length();
                    while (charIndex < length) {
                        if (buffer.hasRemaining()) {
                            buffer.put((byte) string.charAt(charIndex++));
                        } else {
                            buffer.flip();
                            do {
                                res = next.write(buffer);
                                if (res == 0) {
                                    this.string = string;
                                    this.headerName = headerName;
                                    this.charIndex = charIndex;
                                    this.valueIterator = valueIterator;
                                    this.nameIterator = nameIterator;
                                    log.trace("Continuation");
                                    return STATE_HDR_VAL;
                                }
                            } while (buffer.hasRemaining());
                            buffer.clear();
                        }
                    }
                    charIndex = 0;
                    if (!valueIterator.hasNext()) {
                        if (!buffer.hasRemaining()) {
                            buffer.flip();
                            do {
                                res = next.write(buffer);
                                if (res == 0) {
                                    log.trace("Continuation");
                                    return STATE_HDR_EOL_CR;
                                }
                            } while (buffer.hasRemaining());
                            buffer.clear();
                        }
                        // CR
                        buffer.put((byte) 13);
                        if (!buffer.hasRemaining()) {
                            buffer.flip();
                            do {
                                res = next.write(buffer);
                                if (res == 0) {
                                    log.trace("Continuation");
                                    return STATE_HDR_EOL_LF;
                                }
                            } while (buffer.hasRemaining());
                            buffer.clear();
                        }
                        // LF
                        buffer.put((byte) 10);
                        if (nameIterator.hasNext()) {
                            headerName = nameIterator.next();
                            valueIterator = null;
                            state = STATE_HDR_NAME;
                            break;
                        } else {
                            if (!buffer.hasRemaining()) {
                                buffer.flip();
                                do {
                                    res = next.write(buffer);
                                    if (res == 0) {
                                        log.trace("Continuation");
                                        return STATE_HDR_FINAL_CR;
                                    }
                                } while (buffer.hasRemaining());
                                buffer.clear();
                            }
                            // CR
                            buffer.put((byte) 13);
                            if (!buffer.hasRemaining()) {
                                buffer.flip();
                                do {
                                    res = next.write(buffer);
                                    if (res == 0) {
                                        log.trace("Continuation");
                                        return STATE_HDR_FINAL_LF;
                                    }
                                } while (buffer.hasRemaining());
                                buffer.clear();
                            }
                            // LF
                            buffer.put((byte) 10);
                            this.nameIterator = null;
                            this.valueIterator = null;
                            this.string = null;
                            buffer.flip();
                            //for performance reasons we use a gather write if there is user data
                            if (userData == null) {
                                do {
                                    res = next.write(buffer);
                                    if (res == 0) {
                                        log.trace("Continuation");
                                        return STATE_BUF_FLUSH;
                                    }
                                } while (buffer.hasRemaining());
                            } else {
                                ByteBuffer[] b = { buffer, userData };
                                do {
                                    long r = next.write(b, 0, b.length);
                                    if (r == 0 && buffer.hasRemaining()) {
                                        log.trace("Continuation");
                                        return STATE_BUF_FLUSH;
                                    }
                                } while (buffer.hasRemaining());
                            }
                            pooledBuffer.close();
                            pooledBuffer = null;
                            log.trace("Body");
                            return STATE_BODY;
                        }
                    // not reached
                    }
                // fall thru
                }
            // Clean-up states
            case STATE_HDR_EOL_CR:
                {
                    if (!buffer.hasRemaining()) {
                        buffer.flip();
                        do {
                            res = next.write(buffer);
                            if (res == 0) {
                                log.trace("Continuation");
                                return STATE_HDR_EOL_CR;
                            }
                        } while (buffer.hasRemaining());
                        buffer.clear();
                    }
                    // CR
                    buffer.put((byte) 13);
                }
            case STATE_HDR_EOL_LF:
                {
                    if (!buffer.hasRemaining()) {
                        buffer.flip();
                        do {
                            res = next.write(buffer);
                            if (res == 0) {
                                log.trace("Continuation");
                                return STATE_HDR_EOL_LF;
                            }
                        } while (buffer.hasRemaining());
                        buffer.clear();
                    }
                    // LF
                    buffer.put((byte) 10);
                    if (valueIterator.hasNext()) {
                        state = STATE_HDR_NAME;
                        break;
                    } else if (nameIterator.hasNext()) {
                        headerName = nameIterator.next();
                        valueIterator = null;
                        state = STATE_HDR_NAME;
                        break;
                    }
                // fall thru
                }
            case STATE_HDR_FINAL_CR:
                {
                    if (!buffer.hasRemaining()) {
                        buffer.flip();
                        do {
                            res = next.write(buffer);
                            if (res == 0) {
                                log.trace("Continuation");
                                return STATE_HDR_FINAL_CR;
                            }
                        } while (buffer.hasRemaining());
                        buffer.clear();
                    }
                    // CR
                    buffer.put((byte) 13);
                // fall thru
                }
            case STATE_HDR_FINAL_LF:
                {
                    if (!buffer.hasRemaining()) {
                        buffer.flip();
                        do {
                            res = next.write(buffer);
                            if (res == 0) {
                                log.trace("Continuation");
                                return STATE_HDR_FINAL_LF;
                            }
                        } while (buffer.hasRemaining());
                        buffer.clear();
                    }
                    // LF
                    buffer.put((byte) 10);
                    this.nameIterator = null;
                    this.valueIterator = null;
                    this.string = null;
                    buffer.flip();
                    //for performance reasons we use a gather write if there is user data
                    if (userData == null) {
                        do {
                            res = next.write(buffer);
                            if (res == 0) {
                                log.trace("Continuation");
                                return STATE_BUF_FLUSH;
                            }
                        } while (buffer.hasRemaining());
                    } else {
                        ByteBuffer[] b = { buffer, userData };
                        do {
                            long r = next.write(b, 0, b.length);
                            if (r == 0 && buffer.hasRemaining()) {
                                log.trace("Continuation");
                                return STATE_BUF_FLUSH;
                            }
                        } while (buffer.hasRemaining());
                    }
                // fall thru
                }
            case STATE_BUF_FLUSH:
                {
                    // buffer was successfully flushed above
                    pooledBuffer.close();
                    pooledBuffer = null;
                    return STATE_BODY;
                }
            case STATE_URL:
                {
                    for (int i = charIndex; i < string.length(); ++i) {
                        if (!buffer.hasRemaining()) {
                            buffer.flip();
                            do {
                                res = next.write(buffer);
                                if (res == 0) {
                                    log.trace("Continuation");
                                    this.charIndex = i;
                                    this.string = string;
                                    this.state = STATE_URL;
                                    return STATE_URL;
                                }
                            } while (buffer.hasRemaining());
                            buffer.clear();
                        }
                        buffer.put((byte) string.charAt(i));
                    }
                    HeaderMap headers = request.getRequestHeaders();
                    nameIterator = headers.getHeaderNames().iterator();
                    state = STATE_HDR_NAME;
                    if (!nameIterator.hasNext()) {
                        log.trace("No request headers");
                        buffer.put((byte) '\r').put((byte) '\n');
                        buffer.flip();
                        while (buffer.hasRemaining()) {
                            res = next.write(buffer);
                            if (res == 0) {
                                log.trace("Continuation");
                                return STATE_BUF_FLUSH;
                            }
                        }
                        pooledBuffer.close();
                        pooledBuffer = null;
                        log.trace("Body");
                        return STATE_BODY;
                    }
                    headerName = nameIterator.next();
                    charIndex = 0;
                    break;
                }
            default:
                {
                    throw new IllegalStateException();
                }
        }
    }
}
Also used : HeaderMap(io.undertow.util.HeaderMap) HttpString(io.undertow.util.HttpString) ByteBuffer(java.nio.ByteBuffer) PooledByteBuffer(io.undertow.connector.PooledByteBuffer) ClientRequest(io.undertow.client.ClientRequest) HttpString(io.undertow.util.HttpString)

Example 7 with ClientRequest

use of io.undertow.client.ClientRequest in project undertow by undertow-io.

the class AjpClientConnection method initiateRequest.

private void initiateRequest(AjpClientExchange AjpClientExchange) {
    currentRequest = AjpClientExchange;
    ClientRequest request = AjpClientExchange.getRequest();
    String connectionString = request.getRequestHeaders().getFirst(CONNECTION);
    if (connectionString != null) {
        if (CLOSE.equalToString(connectionString)) {
            state |= CLOSE_REQ;
        }
    } else if (request.getProtocol() != Protocols.HTTP_1_1) {
        state |= CLOSE_REQ;
    }
    if (request.getRequestHeaders().contains(UPGRADE)) {
        state |= UPGRADE_REQUESTED;
    }
    long length = 0;
    String fixedLengthString = request.getRequestHeaders().getFirst(CONTENT_LENGTH);
    String transferEncodingString = request.getRequestHeaders().getLast(TRANSFER_ENCODING);
    if (fixedLengthString != null) {
        length = Long.parseLong(fixedLengthString);
    } else if (transferEncodingString != null) {
        length = -1;
    }
    AjpClientRequestClientStreamSinkChannel sinkChannel = connection.sendRequest(request.getMethod(), request.getPath(), request.getProtocol(), request.getRequestHeaders(), request, requestFinishListener);
    currentRequest.setRequestChannel(sinkChannel);
    AjpClientExchange.invokeReadReadyCallback(AjpClientExchange);
    if (length == 0) {
        //otherwise it is up to the user
        try {
            sinkChannel.shutdownWrites();
            if (!sinkChannel.flush()) {
                handleFailedFlush(sinkChannel);
            }
        } catch (IOException e) {
            handleError(e);
        }
    }
}
Also used : IOException(java.io.IOException) ClientRequest(io.undertow.client.ClientRequest) AjpClientRequestClientStreamSinkChannel(io.undertow.protocols.ajp.AjpClientRequestClientStreamSinkChannel)

Example 8 with ClientRequest

use of io.undertow.client.ClientRequest in project spring-framework by spring-projects.

the class UndertowXhrTransport method executeReceiveRequest.

private void executeReceiveRequest(final TransportRequest transportRequest, final URI url, final HttpHeaders headers, final XhrClientSockJsSession session, final SettableListenableFuture<WebSocketSession> connectFuture) {
    if (logger.isTraceEnabled()) {
        logger.trace("Starting XHR receive request for " + url);
    }
    ClientCallback<ClientConnection> clientCallback = new ClientCallback<ClientConnection>() {

        @Override
        public void completed(ClientConnection connection) {
            ClientRequest request = new ClientRequest().setMethod(Methods.POST).setPath(url.getPath());
            HttpString headerName = HttpString.tryFromString(HttpHeaders.HOST);
            request.getRequestHeaders().add(headerName, url.getHost());
            addHttpHeaders(request, headers);
            HttpHeaders httpHeaders = transportRequest.getHttpRequestHeaders();
            connection.sendRequest(request, createReceiveCallback(transportRequest, url, httpHeaders, session, connectFuture));
        }

        @Override
        public void failed(IOException ex) {
            throw new SockJsTransportFailureException("Failed to execute request to " + url, ex);
        }
    };
    this.httpClient.connect(clientCallback, url, this.worker, this.bufferPool, this.optionMap);
}
Also used : SockJsTransportFailureException(org.springframework.web.socket.sockjs.SockJsTransportFailureException) ClientCallback(io.undertow.client.ClientCallback) HttpHeaders(org.springframework.http.HttpHeaders) ClientConnection(io.undertow.client.ClientConnection) IOException(java.io.IOException) ClientRequest(io.undertow.client.ClientRequest) HttpString(io.undertow.util.HttpString)

Example 9 with ClientRequest

use of io.undertow.client.ClientRequest in project undertow by undertow-io.

the class HttpClientTestCase method testSimpleBasic.

@Test
public void testSimpleBasic() throws Exception {
    //
    DefaultServer.setRootHandler(SIMPLE_MESSAGE_HANDLER);
    final UndertowClient client = createClient();
    final List<ClientResponse> responses = new CopyOnWriteArrayList<>();
    final CountDownLatch latch = new CountDownLatch(10);
    final ClientConnection connection = client.connect(ADDRESS, worker, DefaultServer.getBufferPool(), OptionMap.EMPTY).get();
    try {
        connection.getIoThread().execute(new Runnable() {

            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    final ClientRequest request = new ClientRequest().setMethod(Methods.GET).setPath("/");
                    request.getRequestHeaders().put(Headers.HOST, DefaultServer.getHostAddress());
                    connection.sendRequest(request, createClientCallback(responses, latch));
                }
            }
        });
        latch.await(10, TimeUnit.SECONDS);
        Assert.assertEquals(10, responses.size());
        for (final ClientResponse response : responses) {
            Assert.assertEquals(message, response.getAttachment(RESPONSE_BODY));
        }
    } finally {
        IoUtils.safeClose(connection);
    }
}
Also used : ClientResponse(io.undertow.client.ClientResponse) UndertowClient(io.undertow.client.UndertowClient) ClientConnection(io.undertow.client.ClientConnection) CountDownLatch(java.util.concurrent.CountDownLatch) ClientRequest(io.undertow.client.ClientRequest) CopyOnWriteArrayList(java.util.concurrent.CopyOnWriteArrayList) Test(org.junit.Test)

Example 10 with ClientRequest

use of io.undertow.client.ClientRequest in project undertow by undertow-io.

the class LoadBalancingProxyHTTP2TestCase method testHttp2ClientMultipleStreamsThreadSafety.

@Test
public void testHttp2ClientMultipleStreamsThreadSafety() throws IOException, URISyntaxException, ExecutionException, InterruptedException, TimeoutException {
    //not actually a proxy test
    //but convent to put it here
    UndertowXnioSsl ssl = new UndertowXnioSsl(DefaultServer.getWorker().getXnio(), OptionMap.EMPTY, DefaultServer.SSL_BUFFER_POOL, DefaultServer.createClientSslContext());
    final UndertowClient client = UndertowClient.getInstance();
    final ClientConnection connection = client.connect(new URI("https", null, DefaultServer.getHostAddress(), DefaultServer.getHostPort() + 1, "/", null, null), DefaultServer.getWorker(), ssl, DefaultServer.getBufferPool(), OptionMap.create(UndertowOptions.ENABLE_HTTP2, true)).get();
    final ExecutorService service = Executors.newFixedThreadPool(10);
    try {
        Deque<FutureResult<String>> futures = new ArrayDeque<>();
        for (int i = 0; i < 100; ++i) {
            final FutureResult<String> future = new FutureResult<>();
            futures.add(future);
            service.submit(new Callable<String>() {

                @Override
                public String call() throws Exception {
                    ClientRequest cr = new ClientRequest().setMethod(Methods.GET).setPath("/path").setProtocol(Protocols.HTTP_1_1);
                    connection.sendRequest(cr, new ClientCallback<ClientExchange>() {

                        @Override
                        public void completed(ClientExchange result) {
                            result.setResponseListener(new ClientCallback<ClientExchange>() {

                                @Override
                                public void completed(ClientExchange result) {
                                    new StringReadChannelListener(DefaultServer.getBufferPool()) {

                                        @Override
                                        protected void stringDone(String string) {
                                            future.setResult(string);
                                        }

                                        @Override
                                        protected void error(IOException e) {
                                            future.setException(e);
                                        }
                                    }.setup(result.getResponseChannel());
                                }

                                @Override
                                public void failed(IOException e) {
                                    future.setException(e);
                                }
                            });
                        }

                        @Override
                        public void failed(IOException e) {
                            future.setException(e);
                        }
                    });
                    return null;
                }
            });
        }
        while (!futures.isEmpty()) {
            FutureResult<String> future = futures.poll();
            Assert.assertNotEquals(IoFuture.Status.WAITING, future.getIoFuture().awaitInterruptibly(10, TimeUnit.SECONDS));
            Assert.assertEquals("/path", future.getIoFuture().get());
        }
    } finally {
        service.shutdownNow();
    }
}
Also used : ClientExchange(io.undertow.client.ClientExchange) ClientCallback(io.undertow.client.ClientCallback) StringReadChannelListener(io.undertow.util.StringReadChannelListener) UndertowClient(io.undertow.client.UndertowClient) HttpString(io.undertow.util.HttpString) IOException(java.io.IOException) URI(java.net.URI) ArrayDeque(java.util.ArrayDeque) URISyntaxException(java.net.URISyntaxException) TimeoutException(java.util.concurrent.TimeoutException) IOException(java.io.IOException) ExecutionException(java.util.concurrent.ExecutionException) FutureResult(org.xnio.FutureResult) ExecutorService(java.util.concurrent.ExecutorService) ClientConnection(io.undertow.client.ClientConnection) UndertowXnioSsl(io.undertow.protocols.ssl.UndertowXnioSsl) ClientRequest(io.undertow.client.ClientRequest) Test(org.junit.Test)

Aggregations

ClientRequest (io.undertow.client.ClientRequest)10 ClientConnection (io.undertow.client.ClientConnection)7 HttpString (io.undertow.util.HttpString)6 IOException (java.io.IOException)6 UndertowClient (io.undertow.client.UndertowClient)5 ClientResponse (io.undertow.client.ClientResponse)4 CopyOnWriteArrayList (java.util.concurrent.CopyOnWriteArrayList)4 CountDownLatch (java.util.concurrent.CountDownLatch)4 Test (org.junit.Test)4 URI (java.net.URI)3 ClientCallback (io.undertow.client.ClientCallback)2 UndertowXnioSsl (io.undertow.protocols.ssl.UndertowXnioSsl)2 HeaderMap (io.undertow.util.HeaderMap)2 URISyntaxException (java.net.URISyntaxException)2 ByteBuffer (java.nio.ByteBuffer)2 HttpHeaders (org.springframework.http.HttpHeaders)2 SockJsTransportFailureException (org.springframework.web.socket.sockjs.SockJsTransportFailureException)2 ClientExchange (io.undertow.client.ClientExchange)1 BytesSentStreamSinkConduit (io.undertow.conduits.BytesSentStreamSinkConduit)1 ChunkedStreamSinkConduit (io.undertow.conduits.ChunkedStreamSinkConduit)1