| // |
| // ======================================================================== |
| // Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. |
| // ------------------------------------------------------------------------ |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the Eclipse Public License v1.0 |
| // and Apache License v2.0 which accompanies this distribution. |
| // |
| // The Eclipse Public License is available at |
| // http://www.eclipse.org/legal/epl-v10.html |
| // |
| // The Apache License v2.0 is available at |
| // http://www.opensource.org/licenses/apache2.0.php |
| // |
| // You may elect to redistribute this code under either of these licenses. |
| // ======================================================================== |
| // |
| |
| package org.eclipse.jetty.http.client; |
| |
| import java.util.concurrent.CountDownLatch; |
| import java.util.concurrent.TimeUnit; |
| import java.util.function.Predicate; |
| |
| import org.eclipse.jetty.client.HttpClient; |
| import org.eclipse.jetty.client.HttpClientTransport; |
| import org.eclipse.jetty.client.HttpDestination; |
| import org.eclipse.jetty.client.HttpExchange; |
| import org.eclipse.jetty.client.api.Connection; |
| import org.eclipse.jetty.client.http.HttpChannelOverHTTP; |
| import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP; |
| import org.eclipse.jetty.client.http.HttpConnectionOverHTTP; |
| import org.eclipse.jetty.fcgi.client.http.HttpChannelOverFCGI; |
| import org.eclipse.jetty.fcgi.client.http.HttpClientTransportOverFCGI; |
| import org.eclipse.jetty.fcgi.client.http.HttpConnectionOverFCGI; |
| import org.eclipse.jetty.http2.api.Session; |
| import org.eclipse.jetty.http2.client.HTTP2Client; |
| import org.eclipse.jetty.http2.client.http.HttpChannelOverHTTP2; |
| import org.eclipse.jetty.http2.client.http.HttpClientTransportOverHTTP2; |
| import org.eclipse.jetty.http2.client.http.HttpConnectionOverHTTP2; |
| import org.eclipse.jetty.io.EndPoint; |
| import org.eclipse.jetty.util.Promise; |
| import org.eclipse.jetty.util.thread.QueuedThreadPool; |
| import org.junit.Assert; |
| import org.junit.Test; |
| |
| public class HttpChannelAssociationTest extends AbstractTest |
| { |
| public HttpChannelAssociationTest(Transport transport) |
| { |
| super(transport); |
| } |
| |
| @Test |
| public void testAssociationFailedAbortsRequest() throws Exception |
| { |
| startServer(new EmptyServerHandler()); |
| |
| client = new HttpClient(newHttpClientTransport(transport, exchange -> false), sslContextFactory); |
| QueuedThreadPool clientThreads = new QueuedThreadPool(); |
| clientThreads.setName("client"); |
| client.setExecutor(clientThreads); |
| client.start(); |
| |
| CountDownLatch latch = new CountDownLatch(1); |
| client.newRequest(newURI()) |
| .send(result -> |
| { |
| if (result.isFailed()) |
| latch.countDown(); |
| }); |
| |
| Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); |
| } |
| |
| @Test |
| public void testIdleTimeoutJustBeforeAssociation() throws Exception |
| { |
| startServer(new EmptyServerHandler()); |
| |
| long idleTimeout = 1000; |
| client = new HttpClient(newHttpClientTransport(transport, exchange -> |
| { |
| // We idle timeout just before the association, |
| // we must be able to send the request successfully. |
| sleep(2 * idleTimeout); |
| return true; |
| }), sslContextFactory); |
| QueuedThreadPool clientThreads = new QueuedThreadPool(); |
| clientThreads.setName("client"); |
| client.setExecutor(clientThreads); |
| client.setIdleTimeout(idleTimeout); |
| client.start(); |
| |
| CountDownLatch latch = new CountDownLatch(1); |
| client.newRequest(newURI()) |
| .send(result -> |
| { |
| if (result.isSucceeded()) |
| latch.countDown(); |
| }); |
| |
| Assert.assertTrue(latch.await(5 * idleTimeout, TimeUnit.MILLISECONDS)); |
| } |
| |
| private HttpClientTransport newHttpClientTransport(Transport transport, Predicate<HttpExchange> code) |
| { |
| switch (transport) |
| { |
| case HTTP: |
| case HTTPS: |
| { |
| return new HttpClientTransportOverHTTP(1) |
| { |
| @Override |
| protected HttpConnectionOverHTTP newHttpConnection(EndPoint endPoint, HttpDestination destination, Promise<Connection> promise) |
| { |
| return new HttpConnectionOverHTTP(endPoint, destination, promise) |
| { |
| @Override |
| protected HttpChannelOverHTTP newHttpChannel() |
| { |
| return new HttpChannelOverHTTP(this) |
| { |
| @Override |
| public boolean associate(HttpExchange exchange) |
| { |
| return code.test(exchange) && super.associate(exchange); |
| } |
| }; |
| } |
| }; |
| } |
| }; |
| } |
| case H2C: |
| case H2: |
| { |
| HTTP2Client http2Client = new HTTP2Client(); |
| http2Client.setSelectors(1); |
| return new HttpClientTransportOverHTTP2(http2Client) |
| { |
| @Override |
| protected HttpConnectionOverHTTP2 newHttpConnection(HttpDestination destination, Session session) |
| { |
| return new HttpConnectionOverHTTP2(destination, session) |
| { |
| @Override |
| protected HttpChannelOverHTTP2 newHttpChannel(boolean push) |
| { |
| return new HttpChannelOverHTTP2(getHttpDestination(), this, getSession(), push) |
| { |
| @Override |
| public boolean associate(HttpExchange exchange) |
| { |
| return code.test(exchange) && super.associate(exchange); |
| } |
| }; |
| } |
| }; |
| } |
| }; |
| } |
| case FCGI: |
| { |
| return new HttpClientTransportOverFCGI(1, false, "") |
| { |
| @Override |
| protected HttpConnectionOverFCGI newHttpConnection(EndPoint endPoint, HttpDestination destination, Promise<Connection> promise) |
| { |
| return new HttpConnectionOverFCGI(endPoint, destination, promise, isMultiplexed()) |
| { |
| @Override |
| protected HttpChannelOverFCGI newHttpChannel(int id, org.eclipse.jetty.client.api.Request request) |
| { |
| return new HttpChannelOverFCGI(this, getFlusher(), id, request.getIdleTimeout()) |
| { |
| @Override |
| public boolean associate(HttpExchange exchange) |
| { |
| return code.test(exchange) && super.associate(exchange); |
| } |
| }; |
| } |
| }; |
| } |
| }; |
| } |
| default: |
| { |
| throw new IllegalArgumentException(); |
| } |
| } |
| } |
| |
| private void sleep(long time) |
| { |
| try |
| { |
| Thread.sleep(time); |
| } |
| catch (InterruptedException x) |
| { |
| throw new RuntimeException(x); |
| } |
| } |
| } |