Reorganization of jetty-client classes. (#9127)

* Reorganization of jetty-client classes.

* Moved oej.client.api to oej.client
* Moved oej.client.util to oej.client
* Moved implementation classes to oej.client.internal
* Moved transports to oej.client.transport
* Moved transport implementation classes to oej.client.transport.internal
* Moved TunnelRequest to oej.client.internal.

* Moved FastCGI transport classes to o.e.j.fcgi.transport
* Moved FastCGI transport implementation classes to o.e.j.fcgi.transport.internal

* Updated WebSocket core client to use only exported, non-internal, oej.client classes.

* Expanded oej.client.Destination APIs:
  - added: getOrigin(), isSecure(), getProxy(), getConnectionPool(), getHttpClient(), send(..).
  - removed: getScheme(), getHost(), getPort() because they don't uniquely identify a Destination anymore (Origin does)
* Moved destination sweeper functionality from HttpDestination to HttpClient.
  HttpDestination does not implement close() anymore, now relies on LifeCycle.stop()
* Moved HttpReceiver.storeCookie() logic to HttpClient.putCookie() to avoid exposing CookieManager.
* Moved HttpClient.getAcceptEncodingField() to ContentDecoder.Factories

* Avoid public/protected Logger instances.

Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
Simone Bordet 2023-01-11 10:05:43 +01:00 committed by GitHub
parent 03569efb6c
commit a1c5cefd0d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
468 changed files with 1765 additions and 2105 deletions

View File

@ -26,34 +26,34 @@ import java.nio.file.Paths;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.client.AsyncRequestContent;
import org.eclipse.jetty.client.Authentication;
import org.eclipse.jetty.client.AuthenticationStore;
import org.eclipse.jetty.client.BasicAuthentication;
import org.eclipse.jetty.client.BufferingResponseListener;
import org.eclipse.jetty.client.BytesRequestContent;
import org.eclipse.jetty.client.ConnectionPool; import org.eclipse.jetty.client.ConnectionPool;
import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.client.Destination;
import org.eclipse.jetty.client.DigestAuthentication;
import org.eclipse.jetty.client.FutureResponseListener;
import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.HttpClientTransport; import org.eclipse.jetty.client.HttpClientTransport;
import org.eclipse.jetty.client.HttpDestination;
import org.eclipse.jetty.client.HttpProxy; import org.eclipse.jetty.client.HttpProxy;
import org.eclipse.jetty.client.InputStreamRequestContent;
import org.eclipse.jetty.client.InputStreamResponseListener;
import org.eclipse.jetty.client.OutputStreamRequestContent;
import org.eclipse.jetty.client.PathRequestContent;
import org.eclipse.jetty.client.ProxyConfiguration; import org.eclipse.jetty.client.ProxyConfiguration;
import org.eclipse.jetty.client.Request;
import org.eclipse.jetty.client.Response;
import org.eclipse.jetty.client.Result;
import org.eclipse.jetty.client.RoundRobinConnectionPool; import org.eclipse.jetty.client.RoundRobinConnectionPool;
import org.eclipse.jetty.client.api.Authentication; import org.eclipse.jetty.client.StringRequestContent;
import org.eclipse.jetty.client.api.AuthenticationStore; import org.eclipse.jetty.client.transport.HttpClientConnectionFactory;
import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.client.transport.HttpClientTransportDynamic;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.transport.HttpClientTransportOverHTTP;
import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.fcgi.client.transport.HttpClientTransportOverFCGI;
import org.eclipse.jetty.client.api.Result;
import org.eclipse.jetty.client.dynamic.HttpClientTransportDynamic;
import org.eclipse.jetty.client.http.HttpClientConnectionFactory;
import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
import org.eclipse.jetty.client.util.AsyncRequestContent;
import org.eclipse.jetty.client.util.BasicAuthentication;
import org.eclipse.jetty.client.util.BufferingResponseListener;
import org.eclipse.jetty.client.util.BytesRequestContent;
import org.eclipse.jetty.client.util.DigestAuthentication;
import org.eclipse.jetty.client.util.FutureResponseListener;
import org.eclipse.jetty.client.util.InputStreamRequestContent;
import org.eclipse.jetty.client.util.InputStreamResponseListener;
import org.eclipse.jetty.client.util.OutputStreamRequestContent;
import org.eclipse.jetty.client.util.PathRequestContent;
import org.eclipse.jetty.client.util.StringRequestContent;
import org.eclipse.jetty.fcgi.client.http.HttpClientTransportOverFCGI;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpStatus;
@ -870,13 +870,11 @@ public class HTTPClientDocs
httpClient.start(); httpClient.start();
ConnectionPool connectionPool = httpClient.getDestinations().stream() ConnectionPool connectionPool = httpClient.getDestinations().stream()
// Cast to HttpDestination.
.map(HttpDestination.class::cast)
// Find the destination by filtering on the Origin. // Find the destination by filtering on the Origin.
.filter(destination -> destination.getOrigin().getAddress().getHost().equals("domain.com")) .filter(destination -> destination.getOrigin().getAddress().getHost().equals("domain.com"))
.findAny() .findAny()
// Get the ConnectionPool. // Get the ConnectionPool.
.map(HttpDestination::getConnectionPool) .map(Destination::getConnectionPool)
.orElse(null); .orElse(null);
// end::getConnectionPool[] // end::getConnectionPool[]
} }
@ -901,7 +899,6 @@ public class HTTPClientDocs
transport.setConnectionPoolFactory(destination -> transport.setConnectionPoolFactory(destination ->
new RoundRobinConnectionPool(destination, new RoundRobinConnectionPool(destination,
maxConnectionsPerDestination, maxConnectionsPerDestination,
destination,
maxRequestsPerConnection)); maxRequestsPerConnection));
// end::setConnectionPool[] // end::setConnectionPool[]
} }

View File

@ -19,9 +19,9 @@ import java.util.concurrent.CompletableFuture;
import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.HttpProxy; import org.eclipse.jetty.client.HttpProxy;
import org.eclipse.jetty.client.HttpRequest; import org.eclipse.jetty.client.Request;
import org.eclipse.jetty.client.HttpResponse; import org.eclipse.jetty.client.Response;
import org.eclipse.jetty.client.dynamic.HttpClientTransportDynamic; import org.eclipse.jetty.client.transport.HttpClientTransportDynamic;
import org.eclipse.jetty.ee10.websocket.api.Session; import org.eclipse.jetty.ee10.websocket.api.Session;
import org.eclipse.jetty.ee10.websocket.client.ClientUpgradeRequest; import org.eclipse.jetty.ee10.websocket.client.ClientUpgradeRequest;
import org.eclipse.jetty.ee10.websocket.client.JettyUpgradeListener; import org.eclipse.jetty.ee10.websocket.client.JettyUpgradeListener;
@ -175,7 +175,7 @@ public class WebSocketClientDocs
JettyUpgradeListener listener = new JettyUpgradeListener() JettyUpgradeListener listener = new JettyUpgradeListener()
{ {
@Override @Override
public void onHandshakeResponse(HttpRequest request, HttpResponse response) public void onHandshakeResponse(Request request, Response response)
{ {
// Inspect the HTTP response here. // Inspect the HTTP response here.
} }

View File

@ -20,8 +20,8 @@ import java.security.Security;
import org.conscrypt.OpenSSLProvider; import org.conscrypt.OpenSSLProvider;
import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory; import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory;
import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.http2.client.HTTP2Client; import org.eclipse.jetty.http2.client.HTTP2Client;
import org.eclipse.jetty.http2.client.transport.HttpClientTransportOverHTTP2; import org.eclipse.jetty.http2.client.transport.HttpClientTransportOverHTTP2;
import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory; import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;

View File

@ -25,11 +25,13 @@ module org.eclipse.jetty.client
requires static org.eclipse.jetty.jmx; requires static org.eclipse.jetty.jmx;
exports org.eclipse.jetty.client; exports org.eclipse.jetty.client;
exports org.eclipse.jetty.client.api; exports org.eclipse.jetty.client.transport;
exports org.eclipse.jetty.client.dynamic;
exports org.eclipse.jetty.client.http;
exports org.eclipse.jetty.client.util;
exports org.eclipse.jetty.client.jmx to exports org.eclipse.jetty.client.jmx to
org.eclipse.jetty.jmx; org.eclipse.jetty.jmx;
exports org.eclipse.jetty.client.internal to
org.eclipse.jetty.fcgi.client,
org.eclipse.jetty.http2.client.transport,
org.eclipse.jetty.http3.client.transport;
} }

View File

@ -11,13 +11,10 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client.util; package org.eclipse.jetty.client;
import java.net.URI; import java.net.URI;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.Authentication;
public abstract class AbstractAuthentication implements Authentication public abstract class AbstractAuthentication implements Authentication
{ {
private final URI uri; private final URI uri;

View File

@ -25,9 +25,8 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.eclipse.jetty.client.api.Connection; import org.eclipse.jetty.client.internal.HttpDestination;
import org.eclipse.jetty.util.Attachable; import org.eclipse.jetty.util.Attachable;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.NanoTime; import org.eclipse.jetty.util.NanoTime;
import org.eclipse.jetty.util.Pool; import org.eclipse.jetty.util.Pool;
@ -49,17 +48,15 @@ public abstract class AbstractConnectionPool extends ContainerLifeCycle implemen
private final AtomicInteger pending = new AtomicInteger(); private final AtomicInteger pending = new AtomicInteger();
private final HttpDestination destination; private final HttpDestination destination;
private final Callback requester;
private final Pool<Connection> pool; private final Pool<Connection> pool;
private boolean maximizeConnections; private boolean maximizeConnections;
private volatile long maxDurationNanos; private volatile long maxDurationNanos;
private volatile int maxUsage; private volatile int maxUsage;
private volatile int initialMaxMultiplex; private volatile int initialMaxMultiplex;
protected AbstractConnectionPool(HttpDestination destination, Pool<Connection> pool, Callback requester, int initialMaxMultiplex) protected AbstractConnectionPool(Destination destination, Pool<Connection> pool, int initialMaxMultiplex)
{ {
this.destination = destination; this.destination = (HttpDestination)destination;
this.requester = requester;
this.pool = pool; this.pool = pool;
this.initialMaxMultiplex = initialMaxMultiplex; this.initialMaxMultiplex = initialMaxMultiplex;
addBean(pool); addBean(pool);
@ -307,7 +304,7 @@ public abstract class AbstractConnectionPool extends ContainerLifeCycle implemen
protected void proceed() protected void proceed()
{ {
requester.succeeded(); destination.succeeded();
} }
protected Connection activate() protected Connection activate()
@ -587,7 +584,7 @@ public abstract class AbstractConnectionPool extends ContainerLifeCycle implemen
pending.decrementAndGet(); pending.decrementAndGet();
reserved.remove(); reserved.remove();
completeExceptionally(x); completeExceptionally(x);
requester.failed(x); destination.failed(x);
} }
} }

View File

@ -19,7 +19,7 @@ import java.time.Duration;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import org.eclipse.jetty.client.api.Connection; import org.eclipse.jetty.client.internal.HttpDestination;
import org.eclipse.jetty.io.ClientConnector; import org.eclipse.jetty.io.ClientConnector;
import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedAttribute;

View File

@ -15,7 +15,6 @@ package org.eclipse.jetty.client;
import java.util.Map; import java.util.Map;
import org.eclipse.jetty.client.api.Connection;
import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.ContainerLifeCycle; import org.eclipse.jetty.util.component.ContainerLifeCycle;

View File

@ -11,12 +11,11 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client.util; package org.eclipse.jetty.client;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.io.content.AsyncContent; import org.eclipse.jetty.io.content.AsyncContent;
import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Callback;

View File

@ -11,7 +11,7 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client.api; package org.eclipse.jetty.client;
import java.net.URI; import java.net.URI;
import java.util.Map; import java.util.Map;
@ -54,7 +54,7 @@ public interface Authentication
/** /**
* Executes the authentication mechanism for the given request, returning a {@link Result} that can be * Executes the authentication mechanism for the given request, returning a {@link Result} that can be
* used to actually authenticate the request via {@link org.eclipse.jetty.client.api.Authentication.Result#apply(Request)}. * used to actually authenticate the request via {@link Authentication.Result#apply(Request)}.
* <p> * <p>
* If a request for {@code "/secure"} returns a {@link Result}, then the result may be used for other * If a request for {@code "/secure"} returns a {@link Result}, then the result may be used for other
* requests such as {@code "/secure/foo"} or {@code "/secure/bar"}, unless those resources are protected * requests such as {@code "/secure/foo"} or {@code "/secure/bar"}, unless those resources are protected
@ -136,7 +136,7 @@ public interface Authentication
} }
/** /**
* {@link Result} holds the information needed to authenticate a {@link Request} via {@link org.eclipse.jetty.client.api.Authentication.Result#apply(org.eclipse.jetty.client.api.Request)}. * {@link Result} holds the information needed to authenticate a {@link Request} via {@link Authentication.Result#apply(Request)}.
*/ */
public static interface Result public static interface Result
{ {

View File

@ -23,14 +23,11 @@ import java.util.concurrent.TimeoutException;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.eclipse.jetty.client.api.Authentication; import org.eclipse.jetty.client.Authentication.HeaderInfo;
import org.eclipse.jetty.client.api.Authentication.HeaderInfo; import org.eclipse.jetty.client.internal.HttpContentResponse;
import org.eclipse.jetty.client.api.Connection; import org.eclipse.jetty.client.internal.HttpConversation;
import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.client.internal.HttpRequest;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.internal.ResponseNotifier;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.client.api.Result;
import org.eclipse.jetty.client.util.BufferingResponseListener;
import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpStatus;
@ -42,13 +39,13 @@ import org.slf4j.LoggerFactory;
public abstract class AuthenticationProtocolHandler implements ProtocolHandler public abstract class AuthenticationProtocolHandler implements ProtocolHandler
{ {
public static final int DEFAULT_MAX_CONTENT_LENGTH = 16 * 1024; public static final int DEFAULT_MAX_CONTENT_LENGTH = 16 * 1024;
public static final Logger LOG = LoggerFactory.getLogger(AuthenticationProtocolHandler.class); private static final Logger LOG = LoggerFactory.getLogger(AuthenticationProtocolHandler.class);
private static final Pattern CHALLENGE_PATTERN = Pattern.compile("(?<schemeOnly>[!#$%&'*+\\-.^_`|~0-9A-Za-z]+)|(?:(?<scheme>[!#$%&'*+\\-.^_`|~0-9A-Za-z]+)\\s+)?(?:(?<token68>[a-zA-Z0-9\\-._~+/]+=*)|(?<paramName>[!#$%&'*+\\-.^_`|~0-9A-Za-z]+)\\s*=\\s*(?:(?<paramValue>.*)))");
private final HttpClient client; private final HttpClient client;
private final int maxContentLength; private final int maxContentLength;
private final ResponseNotifier notifier; private final ResponseNotifier notifier;
private static final Pattern CHALLENGE_PATTERN = Pattern.compile("(?<schemeOnly>[!#$%&'*+\\-.^_`|~0-9A-Za-z]+)|(?:(?<scheme>[!#$%&'*+\\-.^_`|~0-9A-Za-z]+)\\s+)?(?:(?<token68>[a-zA-Z0-9\\-._~+/]+=*)|(?<paramName>[!#$%&'*+\\-.^_`|~0-9A-Za-z]+)\\s*=\\s*(?:(?<paramValue>.*)))");
protected AuthenticationProtocolHandler(HttpClient client, int maxContentLength) protected AuthenticationProtocolHandler(HttpClient client, int maxContentLength)
{ {
this.client = client; this.client = client;

View File

@ -11,7 +11,7 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client.api; package org.eclipse.jetty.client;
import java.net.URI; import java.net.URI;

View File

@ -11,17 +11,13 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client.util; package org.eclipse.jetty.client;
import java.net.URI; import java.net.URI;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Base64; import java.util.Base64;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.AuthenticationStore;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.util.Attributes; import org.eclipse.jetty.util.Attributes;
@ -68,7 +64,7 @@ public class BasicAuthentication extends AbstractAuthentication
* Basic authentication result. * Basic authentication result.
* <p> * <p>
* Application may utilize this class directly via * Application may utilize this class directly via
* {@link org.eclipse.jetty.client.api.AuthenticationStore#addAuthenticationResult(Result)} * {@link AuthenticationStore#addAuthenticationResult(Result)}
* to perform preemptive authentication, that is immediately * to perform preemptive authentication, that is immediately
* sending the authorization header based on the fact that the * sending the authorization header based on the fact that the
* URI is known to require authentication and that username * URI is known to require authentication and that username

View File

@ -11,7 +11,7 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client.util; package org.eclipse.jetty.client;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.InputStream; import java.io.InputStream;
@ -20,10 +20,7 @@ import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Locale; import java.util.Locale;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.Response.Listener;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.client.api.Response.Listener;
import org.eclipse.jetty.client.api.Result;
import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpMethod;
@ -112,6 +109,8 @@ public abstract class BufferingResponseListener extends Listener.Adapter
public void onContent(Response response, ByteBuffer content) public void onContent(Response response, ByteBuffer content)
{ {
int length = content.remaining(); int length = content.remaining();
if (length == 0)
return;
if (length > BufferUtil.space(buffer)) if (length > BufferUtil.space(buffer))
{ {
int remaining = buffer == null ? 0 : buffer.remaining(); int remaining = buffer == null ? 0 : buffer.remaining();

View File

@ -11,13 +11,12 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client.util; package org.eclipse.jetty.client;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.io.content.ByteBufferContentSource; import org.eclipse.jetty.io.content.ByteBufferContentSource;
/** /**

View File

@ -11,13 +11,11 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client.util; package org.eclipse.jetty.client;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.eclipse.jetty.client.api.Request;
/** /**
* A {@link Request.Content} for byte arrays. * A {@link Request.Content} for byte arrays.
*/ */

View File

@ -11,7 +11,7 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client.api; package org.eclipse.jetty.client;
import java.io.Closeable; import java.io.Closeable;

View File

@ -16,8 +16,6 @@ package org.eclipse.jetty.client;
import java.io.Closeable; import java.io.Closeable;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import org.eclipse.jetty.client.api.Connection;
/** /**
* <p>Client-side connection pool abstraction.</p> * <p>Client-side connection pool abstraction.</p>
*/ */
@ -102,7 +100,7 @@ public interface ConnectionPool extends Closeable
* @param destination the destination to create the ConnectionPool for * @param destination the destination to create the ConnectionPool for
* @return the newly created ConnectionPool * @return the newly created ConnectionPool
*/ */
ConnectionPool newConnectionPool(HttpDestination destination); ConnectionPool newConnectionPool(Destination destination);
} }
/** /**

View File

@ -14,6 +14,12 @@
package org.eclipse.jetty.client; package org.eclipse.jetty.client;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader;
/** /**
* {@link ContentDecoder} decodes content bytes of a response. * {@link ContentDecoder} decodes content bytes of a response.
@ -89,4 +95,35 @@ public interface ContentDecoder
*/ */
public abstract ContentDecoder newContentDecoder(); public abstract ContentDecoder newContentDecoder();
} }
public static class Factories implements Iterable<ContentDecoder.Factory>
{
private final Map<String, Factory> factories = new LinkedHashMap<>();
private HttpField acceptEncodingField;
public HttpField getAcceptEncodingField()
{
return acceptEncodingField;
}
@Override
public Iterator<Factory> iterator()
{
return factories.values().iterator();
}
public void clear()
{
factories.clear();
acceptEncodingField = null;
}
public Factory put(Factory factory)
{
Factory result = factories.put(factory.getEncoding(), factory);
String value = String.join(",", factories.keySet());
acceptEncodingField = new HttpField(HttpHeader.ACCEPT_ENCODING, value);
return result;
}
}
} }

View File

@ -11,13 +11,27 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client.api; package org.eclipse.jetty.client;
import org.eclipse.jetty.client.internal.HttpContentResponse;
/** /**
* A specialized {@link Response} that can hold a limited content in memory. * A specialized {@link Response} that can hold a limited content in memory.
*/ */
public interface ContentResponse extends Response public interface ContentResponse extends Response
{ {
/**
* @param response the Response with status code and headers
* @param content the content bytes associated to the response
* @param mediaType the media type of the content bytes
* @param encoding the encoding of the content bytes
* @return a new ContentResponse from the given arguments
*/
static ContentResponse from(Response response, byte[] content, String mediaType, String encoding)
{
return new HttpContentResponse(response, content, mediaType, encoding);
}
/** /**
* @return the media type of the content, such as "text/html" or "application/octet-stream" * @return the media type of the content, such as "text/html" or "application/octet-stream"
*/ */

View File

@ -15,10 +15,11 @@ package org.eclipse.jetty.client;
import java.util.List; import java.util.List;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.internal.HttpContentResponse;
import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.internal.HttpConversation;
import org.eclipse.jetty.client.api.Result; import org.eclipse.jetty.client.internal.HttpExchange;
import org.eclipse.jetty.client.util.BufferingResponseListener; import org.eclipse.jetty.client.internal.HttpRequest;
import org.eclipse.jetty.client.internal.ResponseNotifier;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpHeaderValue; import org.eclipse.jetty.http.HttpHeaderValue;
import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpStatus;

View File

@ -0,0 +1,95 @@
//
// ========================================================================
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.client;
import org.eclipse.jetty.util.FuturePromise;
import org.eclipse.jetty.util.Promise;
/**
* <p>A {@link Destination} represents the receiver of HTTP requests, and it is
* identified by an {@link Origin}.</p>
* <p>{@link Destination} holds a pool of {@link Connection}s, but allows to create unpooled
* connections if the application wants full control over connection management via
* {@link #newConnection(Promise)}.</p>
* <p>{@link Destination}s may be obtained via {@link HttpClient#resolveDestination(Request)}.</p>
*/
public interface Destination
{
/**
* @return the origin of this destination
*/
Origin getOrigin();
/**
* @return whether the communication with the destination is secure
*/
boolean isSecure();
/**
* @return the proxy associated with this destination,
* or {@code null} if there is no proxy
*/
ProxyConfiguration.Proxy getProxy();
/**
* @return the connection pool associated with this destination
*/
ConnectionPool getConnectionPool();
/**
* @return the {@code HttpClient} that manages this destination
*/
HttpClient getHttpClient();
/**
* Creates asynchronously a new, unpooled, {@link Connection} that will be returned
* at a later time through the given {@link Promise}.
* <p>
* Use {@link FuturePromise} to wait for the connection:
* <pre>{@code
* Destination destination = ...;
* FuturePromise<Connection> futureConnection = new FuturePromise<>();
* destination.newConnection(futureConnection);
* Connection connection = futureConnection.get(5, TimeUnit.SECONDS);
* }</pre>
*
* @param promise the promise of a new, unpooled, {@link Connection}
*/
void newConnection(Promise<Connection> promise);
/**
* <p>Sends the given request to this destination.</p>
* <p>You can use this method to send the request to a specific
* destination that may be different from the request authority.</p>
* <p>For example when {@link HttpClient} is used in a proxy, it may
* receive a request with authority {@code yourserver.com} but the
* proxy logic may want to forward the request to a specific backend
* server, say {@code backend01}, therefore:</p>
* <pre>{@code
* // Resolve the backend destination.
* Origin backendOrigin = new Origin(backendScheme, "backend01", backendPort);
* Destination backendDestination = httpClient.resolveDestination(backendOrigin);
*
* // Create a request with the original authority.
* Request request = httpClient.newRequest("https://yourserver.com/path");
*
* // Send the request to the specific backend.
* backendDestination.send(request, result -> { ... });
* }</pre>
*
* @param request the request to send to this destination
* @param listener the listener that receives response events
*/
void send(Request request, Response.CompleteListener listener);
}

View File

@ -11,7 +11,7 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client.util; package org.eclipse.jetty.client;
import java.net.URI; import java.net.URI;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -25,10 +25,6 @@ import java.util.Objects;
import java.util.Random; import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.AuthenticationStore;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.util.Attributes; import org.eclipse.jetty.util.Attributes;
import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.StringUtil;

View File

@ -13,15 +13,14 @@
package org.eclipse.jetty.client; package org.eclipse.jetty.client;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Pool; import org.eclipse.jetty.util.Pool;
import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.ManagedObject;
@ManagedObject @ManagedObject
public class DuplexConnectionPool extends AbstractConnectionPool public class DuplexConnectionPool extends AbstractConnectionPool
{ {
public DuplexConnectionPool(HttpDestination destination, int maxConnections, Callback requester) public DuplexConnectionPool(Destination destination, int maxConnections)
{ {
super(destination, new Pool<>(Pool.StrategyType.FIRST, maxConnections, false), requester, 1); super(destination, new Pool<>(Pool.StrategyType.FIRST, maxConnections, false), 1);
} }
} }

View File

@ -15,10 +15,11 @@ package org.eclipse.jetty.client;
import java.util.List; import java.util.List;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.internal.HttpContentResponse;
import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.internal.HttpConversation;
import org.eclipse.jetty.client.api.Result; import org.eclipse.jetty.client.internal.HttpExchange;
import org.eclipse.jetty.client.util.BufferingResponseListener; import org.eclipse.jetty.client.internal.HttpRequest;
import org.eclipse.jetty.client.internal.ResponseNotifier;
import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpStatus;

View File

@ -11,13 +11,12 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client.util; package org.eclipse.jetty.client;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.util.Fields; import org.eclipse.jetty.util.Fields;
/** /**

View File

@ -11,7 +11,7 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client.util; package org.eclipse.jetty.client;
import java.util.concurrent.CancellationException; import java.util.concurrent.CancellationException;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
@ -21,10 +21,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import org.eclipse.jetty.client.HttpContentResponse; import org.eclipse.jetty.client.internal.HttpContentResponse;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Result;
/** /**
* A {@link BufferingResponseListener} that is also a {@link Future}, to allow applications * A {@link BufferingResponseListener} that is also a {@link Future}, to allow applications

View File

@ -25,14 +25,11 @@ import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel; import java.nio.channels.SocketChannel;
import java.time.Duration; import java.time.Duration;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@ -40,14 +37,11 @@ import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import org.eclipse.jetty.client.api.AuthenticationStore; import org.eclipse.jetty.client.internal.HttpAuthenticationStore;
import org.eclipse.jetty.client.api.Connection; import org.eclipse.jetty.client.internal.HttpConversation;
import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.client.internal.HttpDestination;
import org.eclipse.jetty.client.api.Destination; import org.eclipse.jetty.client.internal.HttpRequest;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.transport.HttpClientTransportOverHTTP;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
import org.eclipse.jetty.client.util.FormRequestContent;
import org.eclipse.jetty.http.HttpCompliance; import org.eclipse.jetty.http.HttpCompliance;
import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
@ -124,7 +118,7 @@ public class HttpClient extends ContainerLifeCycle
private final ConcurrentMap<Origin, HttpDestination> destinations = new ConcurrentHashMap<>(); private final ConcurrentMap<Origin, HttpDestination> destinations = new ConcurrentHashMap<>();
private final ProtocolHandlers handlers = new ProtocolHandlers(); private final ProtocolHandlers handlers = new ProtocolHandlers();
private final List<Request.Listener> requestListeners = new ArrayList<>(); private final List<Request.Listener> requestListeners = new ArrayList<>();
private final Set<ContentDecoder.Factory> decoderFactories = new ContentDecoderFactorySet(); private final ContentDecoder.Factories decoderFactories = new ContentDecoder.Factories();
private final ProxyConfiguration proxyConfig = new ProxyConfiguration(); private final ProxyConfiguration proxyConfig = new ProxyConfiguration();
private final HttpClientTransport transport; private final HttpClientTransport transport;
private final ClientConnector connector; private final ClientConnector connector;
@ -140,9 +134,7 @@ public class HttpClient extends ContainerLifeCycle
private int responseBufferSize = 16384; private int responseBufferSize = 16384;
private int maxRedirects = 8; private int maxRedirects = 8;
private long addressResolutionTimeout = 15000; private long addressResolutionTimeout = 15000;
private boolean tcpNoDelay = true;
private boolean strictEventOrdering = false; private boolean strictEventOrdering = false;
private HttpField encodingField;
private long destinationIdleTimeout; private long destinationIdleTimeout;
private String name = getClass().getSimpleName() + "@" + Integer.toHexString(hashCode()); private String name = getClass().getSimpleName() + "@" + Integer.toHexString(hashCode());
private HttpCompliance httpCompliance = HttpCompliance.RFC7230; private HttpCompliance httpCompliance = HttpCompliance.RFC7230;
@ -232,7 +224,7 @@ public class HttpClient extends ContainerLifeCycle
handlers.put(new ProxyAuthenticationProtocolHandler(this)); handlers.put(new ProxyAuthenticationProtocolHandler(this));
handlers.put(new UpgradeProtocolHandler()); handlers.put(new UpgradeProtocolHandler());
decoderFactories.add(new GZIPContentDecoder.Factory(byteBufferPool)); decoderFactories.put(new GZIPContentDecoder.Factory(byteBufferPool));
cookieManager = newCookieManager(); cookieManager = newCookieManager();
cookieStore = cookieManager.getCookieStore(); cookieStore = cookieManager.getCookieStore();
@ -264,13 +256,7 @@ public class HttpClient extends ContainerLifeCycle
decoderFactories.clear(); decoderFactories.clear();
handlers.clear(); handlers.clear();
for (HttpDestination destination : destinations.values())
{
destination.close();
}
destinations.clear(); destinations.clear();
requestListeners.clear(); requestListeners.clear();
authenticationStore.clearAuthentications(); authenticationStore.clearAuthentications();
authenticationStore.clearAuthenticationResults(); authenticationStore.clearAuthenticationResults();
@ -279,10 +265,10 @@ public class HttpClient extends ContainerLifeCycle
} }
/** /**
* Returns a <em>non</em> thread-safe list of {@link org.eclipse.jetty.client.api.Request.Listener}s that can be modified before * Returns a <em>non</em> thread-safe list of {@link Request.Listener}s that can be modified before
* performing requests. * performing requests.
* *
* @return a list of {@link org.eclipse.jetty.client.api.Request.Listener} that can be used to add and remove listeners * @return a list of {@link Request.Listener} that can be used to add and remove listeners
*/ */
public List<Request.Listener> getRequestListeners() public List<Request.Listener> getRequestListeners()
{ {
@ -308,20 +294,23 @@ public class HttpClient extends ContainerLifeCycle
this.cookieManager = newCookieManager(); this.cookieManager = newCookieManager();
} }
/** public void putCookie(URI uri, HttpField field)
* Keep this method package-private because its interface is so ugly
* that we really don't want to expose it more than strictly needed.
*
* @return the cookie manager
*/
CookieManager getCookieManager()
{ {
return cookieManager; try
{
String value = field.getValue();
if (value != null)
{
Map<String, List<String>> header = new HashMap<>(1);
header.put(field.getHeader().asString(), List.of(value));
cookieManager.put(uri, header);
} }
}
Sweeper getDestinationSweeper() catch (IOException x)
{ {
return destinationSweeper; if (LOG.isDebugEnabled())
LOG.debug("Unable to store cookies {} from {}", field, uri, x);
}
} }
/** /**
@ -348,7 +337,7 @@ public class HttpClient extends ContainerLifeCycle
* *
* @return a set of {@link ContentDecoder.Factory} that can be used to add and remove content decoder factories * @return a set of {@link ContentDecoder.Factory} that can be used to add and remove content decoder factories
*/ */
public Set<ContentDecoder.Factory> getContentDecoderFactories() public ContentDecoder.Factories getContentDecoderFactories()
{ {
return decoderFactories; return decoderFactories;
} }
@ -474,9 +463,9 @@ public class HttpClient extends ContainerLifeCycle
return newHttpRequest(newConversation(), uri); return newHttpRequest(newConversation(), uri);
} }
protected Request copyRequest(HttpRequest oldRequest, URI newURI) protected Request copyRequest(Request oldRequest, URI newURI)
{ {
HttpRequest newRequest = newHttpRequest(oldRequest.getConversation(), newURI); HttpRequest newRequest = newHttpRequest(((HttpRequest)oldRequest).getConversation(), newURI);
newRequest.method(oldRequest.getMethod()) newRequest.method(oldRequest.getMethod())
.version(oldRequest.getVersion()) .version(oldRequest.getVersion())
.body(oldRequest.getBody()) .body(oldRequest.getBody())
@ -510,7 +499,7 @@ public class HttpClient extends ContainerLifeCycle
return newRequest; return newRequest;
} }
protected HttpRequest newHttpRequest(HttpConversation conversation, URI uri) private HttpRequest newHttpRequest(HttpConversation conversation, URI uri)
{ {
return new HttpRequest(this, conversation, checkHost(uri)); return new HttpRequest(this, conversation, checkHost(uri));
} }
@ -534,14 +523,14 @@ public class HttpClient extends ContainerLifeCycle
public Destination resolveDestination(Request request) public Destination resolveDestination(Request request)
{ {
HttpClientTransport transport = getTransport(); HttpClientTransport transport = getTransport();
Origin origin = transport.newOrigin((HttpRequest)request); Origin origin = transport.newOrigin(request);
HttpDestination destination = resolveDestination(origin); Destination destination = resolveDestination(origin);
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("Resolved {} for {}", destination, request); LOG.debug("Resolved {} for {}", destination, request);
return destination; return destination;
} }
public Origin createOrigin(HttpRequest request, Origin.Protocol protocol) public Origin createOrigin(Request request, Origin.Protocol protocol)
{ {
String scheme = request.getScheme(); String scheme = request.getScheme();
if (!HttpScheme.HTTP.is(scheme) && !HttpScheme.HTTPS.is(scheme) && if (!HttpScheme.HTTP.is(scheme) && !HttpScheme.HTTPS.is(scheme) &&
@ -561,15 +550,17 @@ public class HttpClient extends ContainerLifeCycle
* @param origin the origin that identifies the destination * @param origin the origin that identifies the destination
* @return the destination for the given origin * @return the destination for the given origin
*/ */
public HttpDestination resolveDestination(Origin origin) public Destination resolveDestination(Origin origin)
{ {
return destinations.compute(origin, (k, v) -> return destinations.compute(origin, (k, v) ->
{ {
if (v == null || v.stale()) if (v == null || v.stale())
{ {
HttpDestination newDestination = getTransport().newHttpDestination(k); HttpDestination newDestination = (HttpDestination)getTransport().newDestination(k);
// Start the destination before it's published to other threads. // Start the destination before it's published to other threads.
addManaged(newDestination); addManaged(newDestination);
if (destinationSweeper != null)
destinationSweeper.offer(newDestination);
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("Created {}; existing: '{}'", newDestination, v); LOG.debug("Created {}; existing: '{}'", newDestination, v);
return newDestination; return newDestination;
@ -578,10 +569,13 @@ public class HttpClient extends ContainerLifeCycle
}); });
} }
protected boolean removeDestination(HttpDestination destination) public boolean removeDestination(Destination destination)
{ {
boolean removed = destinations.remove(destination.getOrigin(), destination); HttpDestination httpDestination = (HttpDestination)destination;
boolean removed = destinations.remove(destination.getOrigin(), httpDestination);
removeBean(destination); removeBean(destination);
if (destinationSweeper != null)
destinationSweeper.remove(httpDestination);
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("Removed {}; result: {}", destination, removed); LOG.debug("Removed {}; result: {}", destination, removed);
return removed; return removed;
@ -595,13 +589,7 @@ public class HttpClient extends ContainerLifeCycle
return new ArrayList<>(destinations.values()); return new ArrayList<>(destinations.values());
} }
protected void send(HttpRequest request, List<Response.ResponseListener> listeners) public void newConnection(Destination destination, Promise<Connection> promise)
{
HttpDestination destination = (HttpDestination)resolveDestination(request);
destination.send(request, listeners);
}
protected void newConnection(HttpDestination destination, Promise<Connection> promise)
{ {
// Multiple threads may access the map, especially with DEBUG logging enabled. // Multiple threads may access the map, especially with DEBUG logging enabled.
Map<String, Object> context = new ConcurrentHashMap<>(); Map<String, Object> context = new ConcurrentHashMap<>();
@ -611,8 +599,9 @@ public class HttpClient extends ContainerLifeCycle
List<String> protocols = protocol != null ? protocol.getProtocols() : List.of("http/1.1"); List<String> protocols = protocol != null ? protocol.getProtocols() : List.of("http/1.1");
context.put(ClientConnector.APPLICATION_PROTOCOLS_CONTEXT_KEY, protocols); context.put(ClientConnector.APPLICATION_PROTOCOLS_CONTEXT_KEY, protocols);
Origin.Address address = destination.getConnectAddress(); ProxyConfiguration.Proxy proxy = destination.getProxy();
resolver.resolve(address.getHost(), address.getPort(), new Promise<>() Origin.Address address = proxy == null ? destination.getOrigin().getAddress() : proxy.getAddress();
getSocketAddressResolver().resolve(address.getHost(), address.getPort(), new Promise<>()
{ {
@Override @Override
public void succeeded(List<InetSocketAddress> socketAddresses) public void succeeded(List<InetSocketAddress> socketAddresses)
@ -655,7 +644,7 @@ public class HttpClient extends ContainerLifeCycle
return handlers; return handlers;
} }
protected ProtocolHandler findProtocolHandler(Request request, Response response) public ProtocolHandler findProtocolHandler(Request request, Response response)
{ {
return handlers.find(request, response); return handlers.find(request, response);
} }
@ -1002,7 +991,7 @@ public class HttpClient extends ContainerLifeCycle
* Whether request/response events must be strictly ordered with respect to connection usage. * Whether request/response events must be strictly ordered with respect to connection usage.
* <p> * <p>
* From the point of view of connection usage, the connection can be reused just before the * From the point of view of connection usage, the connection can be reused just before the
* "complete" event notified to {@link org.eclipse.jetty.client.api.Response.CompleteListener}s * "complete" event notified to {@link Response.CompleteListener}s
* (but after the "success" event). * (but after the "success" event).
* <p> * <p>
* When a request/response exchange is completing, the destination may have another request * When a request/response exchange is completing, the destination may have another request
@ -1146,11 +1135,6 @@ public class HttpClient extends ContainerLifeCycle
return proxyConfig; return proxyConfig;
} }
protected HttpField getAcceptEncodingField()
{
return encodingField;
}
public static int normalizePort(String scheme, int port) public static int normalizePort(String scheme, int port)
{ {
if (port > 0) if (port > 0)
@ -1168,145 +1152,10 @@ public class HttpClient extends ContainerLifeCycle
return HttpScheme.HTTPS.is(scheme) || HttpScheme.WSS.is(scheme); return HttpScheme.HTTPS.is(scheme) || HttpScheme.WSS.is(scheme);
} }
protected ClientConnectionFactory newSslClientConnectionFactory(SslContextFactory.Client sslContextFactory, ClientConnectionFactory connectionFactory) public ClientConnectionFactory newSslClientConnectionFactory(SslContextFactory.Client sslContextFactory, ClientConnectionFactory connectionFactory)
{ {
if (sslContextFactory == null) if (sslContextFactory == null)
sslContextFactory = getSslContextFactory(); sslContextFactory = getSslContextFactory();
return new SslClientConnectionFactory(sslContextFactory, getByteBufferPool(), getExecutor(), connectionFactory); return new SslClientConnectionFactory(sslContextFactory, getByteBufferPool(), getExecutor(), connectionFactory);
} }
private class ContentDecoderFactorySet implements Set<ContentDecoder.Factory>
{
private final Set<ContentDecoder.Factory> set = new HashSet<>();
@Override
public boolean add(ContentDecoder.Factory e)
{
boolean result = set.add(e);
invalidate();
return result;
}
@Override
public boolean addAll(Collection<? extends ContentDecoder.Factory> c)
{
boolean result = set.addAll(c);
invalidate();
return result;
}
@Override
public boolean remove(Object o)
{
boolean result = set.remove(o);
invalidate();
return result;
}
@Override
public boolean removeAll(Collection<?> c)
{
boolean result = set.removeAll(c);
invalidate();
return result;
}
@Override
public boolean retainAll(Collection<?> c)
{
boolean result = set.retainAll(c);
invalidate();
return result;
}
@Override
public void clear()
{
set.clear();
invalidate();
}
@Override
public int size()
{
return set.size();
}
@Override
public boolean isEmpty()
{
return set.isEmpty();
}
@Override
public boolean contains(Object o)
{
return set.contains(o);
}
@Override
public boolean containsAll(Collection<?> c)
{
return set.containsAll(c);
}
@Override
public Iterator<ContentDecoder.Factory> iterator()
{
Iterator<ContentDecoder.Factory> iterator = set.iterator();
return new Iterator<>()
{
@Override
public boolean hasNext()
{
return iterator.hasNext();
}
@Override
public ContentDecoder.Factory next()
{
return iterator.next();
}
@Override
public void remove()
{
iterator.remove();
invalidate();
}
};
}
@Override
public Object[] toArray()
{
return set.toArray();
}
@Override
public <T> T[] toArray(T[] a)
{
return set.toArray(a);
}
private void invalidate()
{
if (set.isEmpty())
{
encodingField = null;
}
else
{
StringBuilder value = new StringBuilder();
for (Iterator<ContentDecoder.Factory> iterator = set.iterator(); iterator.hasNext(); )
{
ContentDecoder.Factory decoderFactory = iterator.next();
value.append(decoderFactory.getEncoding());
if (iterator.hasNext())
value.append(",");
}
encodingField = new HttpField(HttpHeader.ACCEPT_ENCODING, value.toString());
}
}
}
} }

View File

@ -17,6 +17,7 @@ import java.net.InetSocketAddress;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.util.Map; import java.util.Map;
import org.eclipse.jetty.client.internal.HttpDestination;
import org.eclipse.jetty.io.ClientConnectionFactory; import org.eclipse.jetty.io.ClientConnectionFactory;
/** /**
@ -52,7 +53,7 @@ public interface HttpClientTransport extends ClientConnectionFactory
* @param request the request that triggers the creation of the Origin * @param request the request that triggers the creation of the Origin
* @return an Origin that identifies a destination * @return an Origin that identifies a destination
*/ */
public Origin newOrigin(HttpRequest request); public Origin newOrigin(Request request);
/** /**
* Creates a new, transport-specific, {@link HttpDestination} object. * Creates a new, transport-specific, {@link HttpDestination} object.
@ -63,7 +64,7 @@ public interface HttpClientTransport extends ClientConnectionFactory
* @param origin the destination origin * @param origin the destination origin
* @return a new, transport-specific, {@link HttpDestination} object * @return a new, transport-specific, {@link HttpDestination} object
*/ */
public HttpDestination newHttpDestination(Origin origin); public Destination newDestination(Origin origin);
/** /**
* Establishes a physical connection to the given {@code address}. * Establishes a physical connection to the given {@code address}.

View File

@ -21,11 +21,10 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.client.api.Connection; import org.eclipse.jetty.client.internal.HttpConversation;
import org.eclipse.jetty.client.api.Destination; import org.eclipse.jetty.client.internal.HttpDestination;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.internal.HttpRequest;
import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.internal.TunnelRequest;
import org.eclipse.jetty.client.api.Result;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpScheme;
@ -142,7 +141,7 @@ public class HttpProxy extends ProxyConfiguration.Proxy
// Replace the destination with the proxy destination. // Replace the destination with the proxy destination.
HttpDestination destination = (HttpDestination)context.get(HttpClientTransport.HTTP_DESTINATION_CONTEXT_KEY); HttpDestination destination = (HttpDestination)context.get(HttpClientTransport.HTTP_DESTINATION_CONTEXT_KEY);
HttpClient client = destination.getHttpClient(); HttpClient client = destination.getHttpClient();
HttpDestination proxyDestination = client.resolveDestination(getOrigin()); Destination proxyDestination = client.resolveDestination(getOrigin());
context.put(HttpClientTransport.HTTP_DESTINATION_CONTEXT_KEY, proxyDestination); context.put(HttpClientTransport.HTTP_DESTINATION_CONTEXT_KEY, proxyDestination);
try try
{ {
@ -194,7 +193,8 @@ public class HttpProxy extends ProxyConfiguration.Proxy
private void tunnel(HttpDestination destination, Connection connection) private void tunnel(HttpDestination destination, Connection connection)
{ {
String target = destination.getOrigin().getAddress().asString(); String target = destination.getOrigin().getAddress().asString();
Origin.Address proxyAddress = destination.getConnectAddress(); ProxyConfiguration.Proxy proxy = destination.getProxy();
Origin.Address proxyAddress = proxy.getAddress();
HttpClient httpClient = destination.getHttpClient(); HttpClient httpClient = destination.getHttpClient();
long connectTimeout = httpClient.getConnectTimeout(); long connectTimeout = httpClient.getConnectTimeout();
Request connect = new TunnelRequest(httpClient, proxyAddress) Request connect = new TunnelRequest(httpClient, proxyAddress)
@ -204,7 +204,6 @@ public class HttpProxy extends ProxyConfiguration.Proxy
// Use the connect timeout as a total timeout, // Use the connect timeout as a total timeout,
// since this request is to "connect" to the server. // since this request is to "connect" to the server.
.timeout(connectTimeout, TimeUnit.MILLISECONDS); .timeout(connectTimeout, TimeUnit.MILLISECONDS);
ProxyConfiguration.Proxy proxy = destination.getProxy();
if (proxy.isSecure()) if (proxy.isSecure())
connect.scheme(HttpScheme.HTTPS.asString()); connect.scheme(HttpScheme.HTTPS.asString());
@ -223,7 +222,7 @@ public class HttpProxy extends ProxyConfiguration.Proxy
// Don't want to do DNS resolution here. // Don't want to do DNS resolution here.
InetSocketAddress address = InetSocketAddress.createUnresolved(destination.getHost(), destination.getPort()); InetSocketAddress address = InetSocketAddress.createUnresolved(destination.getHost(), destination.getPort());
context.put(ClientConnector.REMOTE_SOCKET_ADDRESS_CONTEXT_KEY, address); context.put(ClientConnector.REMOTE_SOCKET_ADDRESS_CONTEXT_KEY, address);
connectionFactory = destination.newSslClientConnectionFactory(null, connectionFactory); connectionFactory = destination.getHttpClient().newSslClientConnectionFactory(null, connectionFactory);
} }
var oldConnection = endPoint.getConnection(); var oldConnection = endPoint.getConnection();
var newConnection = connectionFactory.newConnection(endPoint, context); var newConnection = connectionFactory.newConnection(endPoint, context);
@ -360,12 +359,4 @@ public class HttpProxy extends ProxyConfiguration.Proxy
conversation.setAttribute(EndPoint.class.getName(), endPoint); conversation.setAttribute(EndPoint.class.getName(), endPoint);
} }
} }
public static class TunnelRequest extends HttpRequest
{
private TunnelRequest(HttpClient client, Origin.Address address)
{
super(client, new HttpConversation(), URI.create("http://" + address.asString()));
}
}
} }

View File

@ -24,10 +24,10 @@ import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.internal.HttpContentResponse;
import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.internal.HttpConversation;
import org.eclipse.jetty.client.api.Result; import org.eclipse.jetty.client.internal.HttpRequest;
import org.eclipse.jetty.client.util.BufferingResponseListener; import org.eclipse.jetty.client.internal.ResponseNotifier;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpStatus;

View File

@ -13,8 +13,6 @@
package org.eclipse.jetty.client; package org.eclipse.jetty.client;
import org.eclipse.jetty.client.api.Request;
public class HttpRequestException extends RuntimeException public class HttpRequestException extends RuntimeException
{ {
private final Request request; private final Request request;

View File

@ -13,8 +13,6 @@
package org.eclipse.jetty.client; package org.eclipse.jetty.client;
import org.eclipse.jetty.client.api.Response;
public class HttpResponseException extends RuntimeException public class HttpResponseException extends RuntimeException
{ {
private final Response response; private final Response response;

View File

@ -13,7 +13,6 @@
package org.eclipse.jetty.client; package org.eclipse.jetty.client;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Callback;
@ -31,13 +30,19 @@ import org.eclipse.jetty.util.Callback;
*/ */
public interface HttpUpgrader public interface HttpUpgrader
{ {
/**
* <p>The request attribute key for the upgrade protocol,
* used by the HTTP/2 extended CONNECT mechanism.</p>
*/
public static final String PROTOCOL_ATTRIBUTE = HttpUpgrader.class.getName() + ".protocol";
/** /**
* <p>Prepares the request for the upgrade, for example by setting the HTTP method * <p>Prepares the request for the upgrade, for example by setting the HTTP method
* or by setting HTTP headers required for the upgrade.</p> * or by setting HTTP headers required for the upgrade.</p>
* *
* @param request the request to prepare * @param request the request to prepare
*/ */
public void prepare(HttpRequest request); public void prepare(Request request);
/** /**
* <p>Upgrades the given {@code endPoint} to a different protocol.</p> * <p>Upgrades the given {@code endPoint} to a different protocol.</p>
@ -48,7 +53,7 @@ public interface HttpUpgrader
* @param endPoint the EndPoint to upgrade * @param endPoint the EndPoint to upgrade
* @param callback a callback to notify of the success or failure of the upgrade * @param callback a callback to notify of the success or failure of the upgrade
*/ */
public void upgrade(HttpResponse response, EndPoint endPoint, Callback callback); public void upgrade(Response response, EndPoint endPoint, Callback callback);
/** /**
* <p>A factory for {@link HttpUpgrader}s.</p> * <p>A factory for {@link HttpUpgrader}s.</p>

View File

@ -11,11 +11,10 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client.util; package org.eclipse.jetty.client;
import java.io.InputStream; import java.io.InputStream;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.io.RetainableByteBufferPool; import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.io.content.InputStreamContentSource; import org.eclipse.jetty.io.content.InputStreamContentSource;

View File

@ -11,7 +11,7 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client.util; package org.eclipse.jetty.client;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -30,10 +30,7 @@ import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.Response.Listener;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.client.api.Response.Listener;
import org.eclipse.jetty.client.api.Result;
import org.eclipse.jetty.io.Content; import org.eclipse.jetty.io.Content;
import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.thread.AutoLock; import org.eclipse.jetty.util.thread.AutoLock;

View File

@ -13,8 +13,6 @@
package org.eclipse.jetty.client; package org.eclipse.jetty.client;
import org.eclipse.jetty.client.api.Connection;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.LeakDetector; import org.eclipse.jetty.util.LeakDetector;
import org.eclipse.jetty.util.component.LifeCycle; import org.eclipse.jetty.util.component.LifeCycle;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -33,9 +31,9 @@ public class LeakTrackingConnectionPool extends DuplexConnectionPool
} }
}; };
public LeakTrackingConnectionPool(HttpDestination destination, int maxConnections, Callback requester) public LeakTrackingConnectionPool(Destination destination, int maxConnections)
{ {
super(destination, maxConnections, requester); super(destination, maxConnections);
addBean(leakDetector); addBean(leakDetector);
} }

View File

@ -11,9 +11,8 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client.util; package org.eclipse.jetty.client;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.MultiPart; import org.eclipse.jetty.http.MultiPart;

View File

@ -13,7 +13,6 @@
package org.eclipse.jetty.client; package org.eclipse.jetty.client;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Pool; import org.eclipse.jetty.util.Pool;
import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.ManagedObject;
@ -21,12 +20,12 @@ import org.eclipse.jetty.util.annotation.ManagedObject;
@ManagedObject @ManagedObject
public class MultiplexConnectionPool extends AbstractConnectionPool public class MultiplexConnectionPool extends AbstractConnectionPool
{ {
public MultiplexConnectionPool(HttpDestination destination, int maxConnections, Callback requester, int initialMaxMultiplex) public MultiplexConnectionPool(Destination destination, int maxConnections, int initialMaxMultiplex)
{ {
this(destination, Pool.StrategyType.FIRST, maxConnections, false, requester, initialMaxMultiplex); this(destination, Pool.StrategyType.FIRST, maxConnections, false, initialMaxMultiplex);
} }
protected MultiplexConnectionPool(HttpDestination destination, Pool.StrategyType strategy, int maxConnections, boolean cache, Callback requester, int initialMaxMultiplex) protected MultiplexConnectionPool(Destination destination, Pool.StrategyType strategy, int maxConnections, boolean cache, int initialMaxMultiplex)
{ {
super(destination, new Pool<>(strategy, maxConnections, cache, connection -> super(destination, new Pool<>(strategy, maxConnections, cache, connection ->
{ {
@ -34,7 +33,7 @@ public class MultiplexConnectionPool extends AbstractConnectionPool
if (connection instanceof MaxMultiplexable maxMultiplexable) if (connection instanceof MaxMultiplexable maxMultiplexable)
maxMultiplex = maxMultiplexable.getMaxMultiplex(); maxMultiplex = maxMultiplexable.getMaxMultiplex();
return maxMultiplex; return maxMultiplex;
}), requester, initialMaxMultiplex); }), initialMaxMultiplex);
} }
@Override @Override

View File

@ -19,7 +19,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import org.eclipse.jetty.client.dynamic.HttpClientTransportDynamic; import org.eclipse.jetty.client.transport.HttpClientTransportDynamic;
import org.eclipse.jetty.io.ClientConnectionFactory; import org.eclipse.jetty.io.ClientConnectionFactory;
import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.util.HostPort; import org.eclipse.jetty.util.HostPort;

View File

@ -11,12 +11,10 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client.util; package org.eclipse.jetty.client;
import java.io.OutputStream; import java.io.OutputStream;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.io.content.OutputStreamContentSource; import org.eclipse.jetty.io.content.OutputStreamContentSource;
/** /**

View File

@ -11,12 +11,11 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client.util; package org.eclipse.jetty.client;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.io.RetainableByteBufferPool; import org.eclipse.jetty.io.RetainableByteBufferPool;
import org.eclipse.jetty.io.content.PathContentSource; import org.eclipse.jetty.io.content.PathContentSource;

View File

@ -15,10 +15,11 @@ package org.eclipse.jetty.client;
import java.util.List; import java.util.List;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.internal.HttpContentResponse;
import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.internal.HttpConversation;
import org.eclipse.jetty.client.api.Result; import org.eclipse.jetty.client.internal.HttpExchange;
import org.eclipse.jetty.client.util.BufferingResponseListener; import org.eclipse.jetty.client.internal.HttpRequest;
import org.eclipse.jetty.client.internal.ResponseNotifier;
import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpStatus;

View File

@ -13,9 +13,6 @@
package org.eclipse.jetty.client; package org.eclipse.jetty.client;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Response;
/** /**
* <p>A protocol handler performs HTTP protocol operations on * <p>A protocol handler performs HTTP protocol operations on
* behalf of the application, typically like a browser would.</p> * behalf of the application, typically like a browser would.</p>

View File

@ -17,8 +17,6 @@ import java.io.IOException;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.util.component.Dumpable; import org.eclipse.jetty.util.component.Dumpable;
/** /**

View File

@ -15,8 +15,7 @@ package org.eclipse.jetty.client;
import java.net.URI; import java.net.URI;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.internal.HttpDestination;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpStatus;

View File

@ -26,6 +26,7 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import org.eclipse.jetty.client.internal.HttpDestination;
import org.eclipse.jetty.io.AbstractConnection; import org.eclipse.jetty.io.AbstractConnection;
import org.eclipse.jetty.io.ClientConnectionFactory; import org.eclipse.jetty.io.ClientConnectionFactory;
import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.Connection;
@ -79,7 +80,7 @@ public abstract class ProxyProtocolClientConnectionFactory implements ClientConn
/** /**
* <p>PROXY protocol version 1 metadata holder to be used in conjunction * <p>PROXY protocol version 1 metadata holder to be used in conjunction
* with {@link org.eclipse.jetty.client.api.Request#tag(Object)}.</p> * with {@link Request#tag(Object)}.</p>
* <p>Instances of this class are associated to a destination so that * <p>Instances of this class are associated to a destination so that
* all connections of that destination will initiate the communication * all connections of that destination will initiate the communication
* with the PROXY protocol version 1 bytes specified by this metadata.</p> * with the PROXY protocol version 1 bytes specified by this metadata.</p>
@ -228,7 +229,7 @@ public abstract class ProxyProtocolClientConnectionFactory implements ClientConn
/** /**
* <p>PROXY protocol version 2 metadata holder to be used in conjunction * <p>PROXY protocol version 2 metadata holder to be used in conjunction
* with {@link org.eclipse.jetty.client.api.Request#tag(Object)}.</p> * with {@link Request#tag(Object)}.</p>
* <p>Instances of this class are associated to a destination so that * <p>Instances of this class are associated to a destination so that
* all connections of that destination will initiate the communication * all connections of that destination will initiate the communication
* with the PROXY protocol version 2 bytes specified by this metadata.</p> * with the PROXY protocol version 2 bytes specified by this metadata.</p>
@ -461,7 +462,7 @@ public abstract class ProxyProtocolClientConnectionFactory implements ClientConn
protected abstract static class ProxyProtocolConnection extends AbstractConnection implements Callback protected abstract static class ProxyProtocolConnection extends AbstractConnection implements Callback
{ {
protected static final Logger LOG = LoggerFactory.getLogger(ProxyProtocolConnection.class); static final Logger LOG = LoggerFactory.getLogger(ProxyProtocolConnection.class);
private final ClientConnectionFactory factory; private final ClientConnectionFactory factory;
private final Map<String, Object> context; private final Map<String, Object> context;

View File

@ -13,7 +13,6 @@
package org.eclipse.jetty.client; package org.eclipse.jetty.client;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Pool; import org.eclipse.jetty.util.Pool;
import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.ManagedObject;
@ -24,8 +23,8 @@ import org.eclipse.jetty.util.annotation.ManagedObject;
@ManagedObject @ManagedObject
public class RandomConnectionPool extends MultiplexConnectionPool public class RandomConnectionPool extends MultiplexConnectionPool
{ {
public RandomConnectionPool(HttpDestination destination, int maxConnections, Callback requester, int maxMultiplex) public RandomConnectionPool(Destination destination, int maxConnections, int maxMultiplex)
{ {
super(destination, Pool.StrategyType.RANDOM, maxConnections, false, requester, maxMultiplex); super(destination, Pool.StrategyType.RANDOM, maxConnections, false, maxMultiplex);
} }
} }

View File

@ -13,9 +13,6 @@
package org.eclipse.jetty.client; package org.eclipse.jetty.client;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.client.api.Result;
import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;

View File

@ -11,7 +11,7 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client.api; package org.eclipse.jetty.client;
import java.io.IOException; import java.io.IOException;
import java.net.HttpCookie; import java.net.HttpCookie;
@ -30,8 +30,6 @@ import java.util.function.BiFunction;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.util.InputStreamResponseListener;
import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.HttpVersion;

View File

@ -11,14 +11,13 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client.api; package org.eclipse.jetty.client;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.EventListener; import java.util.EventListener;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import org.eclipse.jetty.client.util.BufferingResponseListener;
import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.HttpVersion;
@ -44,7 +43,7 @@ public interface Response
/** /**
* @param listenerClass the listener class * @param listenerClass the listener class
* @param <T> the type of class * @param <T> the type of class
* @return the response listener passed to {@link org.eclipse.jetty.client.api.Request#send(org.eclipse.jetty.client.api.Response.CompleteListener)} * @return the response listener passed to {@link Request#send(Response.CompleteListener)}
*/ */
<T extends ResponseListener> List<T> getListeners(Class<T> listenerClass); <T extends ResponseListener> List<T> getListeners(Class<T> listenerClass);

View File

@ -11,7 +11,7 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client.api; package org.eclipse.jetty.client;
/** /**
* The result of a request / response exchange, containing the {@link Request}, the {@link Response} * The result of a request / response exchange, containing the {@link Request}, the {@link Response}

View File

@ -13,7 +13,6 @@
package org.eclipse.jetty.client; package org.eclipse.jetty.client;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Pool; import org.eclipse.jetty.util.Pool;
import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.ManagedObject;
@ -44,14 +43,14 @@ import org.eclipse.jetty.util.annotation.ManagedObject;
@ManagedObject @ManagedObject
public class RoundRobinConnectionPool extends MultiplexConnectionPool public class RoundRobinConnectionPool extends MultiplexConnectionPool
{ {
public RoundRobinConnectionPool(HttpDestination destination, int maxConnections, Callback requester) public RoundRobinConnectionPool(Destination destination, int maxConnections)
{ {
this(destination, maxConnections, requester, 1); this(destination, maxConnections, 1);
} }
public RoundRobinConnectionPool(HttpDestination destination, int maxConnections, Callback requester, int maxMultiplex) public RoundRobinConnectionPool(Destination destination, int maxConnections, int maxMultiplex)
{ {
super(destination, Pool.StrategyType.ROUND_ROBIN, maxConnections, false, requester, maxMultiplex); super(destination, Pool.StrategyType.ROUND_ROBIN, maxConnections, false, maxMultiplex);
// If there are queued requests and connections get // If there are queued requests and connections get
// closed due to idle timeout or overuse, we want to // closed due to idle timeout or overuse, we want to
// aggressively try to open new connections to replace // aggressively try to open new connections to replace

View File

@ -11,7 +11,7 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client.util; package org.eclipse.jetty.client;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
@ -30,10 +30,6 @@ import javax.security.auth.login.Configuration;
import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException; import javax.security.auth.login.LoginException;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.AuthenticationStore;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.util.Attributes; import org.eclipse.jetty.util.Attributes;
import org.ietf.jgss.GSSContext; import org.ietf.jgss.GSSContext;

View File

@ -23,7 +23,7 @@ import java.util.concurrent.TimeoutException;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.eclipse.jetty.client.api.Connection; import org.eclipse.jetty.client.internal.HttpDestination;
import org.eclipse.jetty.io.AbstractConnection; import org.eclipse.jetty.io.AbstractConnection;
import org.eclipse.jetty.io.ClientConnectionFactory; import org.eclipse.jetty.io.ClientConnectionFactory;
import org.eclipse.jetty.io.ClientConnector; import org.eclipse.jetty.io.ClientConnector;
@ -207,7 +207,7 @@ public class Socks4Proxy extends ProxyConfiguration.Proxy
context.put(ClientConnector.REMOTE_SOCKET_ADDRESS_CONTEXT_KEY, address); context.put(ClientConnector.REMOTE_SOCKET_ADDRESS_CONTEXT_KEY, address);
ClientConnectionFactory connectionFactory = this.connectionFactory; ClientConnectionFactory connectionFactory = this.connectionFactory;
if (destination.isSecure()) if (destination.isSecure())
connectionFactory = destination.newSslClientConnectionFactory(null, connectionFactory); connectionFactory = destination.getHttpClient().newSslClientConnectionFactory(null, connectionFactory);
org.eclipse.jetty.io.Connection newConnection = connectionFactory.newConnection(getEndPoint(), context); org.eclipse.jetty.io.Connection newConnection = connectionFactory.newConnection(getEndPoint(), context);
getEndPoint().upgrade(newConnection); getEndPoint().upgrade(newConnection);
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())

View File

@ -11,13 +11,11 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client.util; package org.eclipse.jetty.client;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import org.eclipse.jetty.client.api.Request;
/** /**
* <p>A {@link Request.Content} for strings.</p> * <p>A {@link Request.Content} for strings.</p>
* <p>It is possible to specify, at the constructor, an encoding used to convert * <p>It is possible to specify, at the constructor, an encoding used to convert

View File

@ -1,40 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.client;
/**
* <p>Implementations of this interface expose a lock object
* via {@link #getLock()} so that callers can synchronize
* externally on that lock:</p>
* <pre>
* if (iterator instanceof Synchronizable)
* {
* Object element = null;
* synchronized (((Synchronizable)iterator).getLock())
* {
* if (iterator.hasNext())
* element = iterator.next();
* }
* }
* </pre>
* <p>In the example above, the calls to {@code hasNext()} and
* {@code next()} are performed "atomically".</p>
*/
public interface Synchronizable
{
/**
* @return the lock object to synchronize on
*/
public Object getLock();
}

View File

@ -1,77 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.client;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.client.api.Result;
import org.eclipse.jetty.io.CyclicTimeout;
import org.eclipse.jetty.io.CyclicTimeouts;
import org.eclipse.jetty.util.NanoTime;
import org.eclipse.jetty.util.thread.Scheduler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @deprecated Do not use it, use {@link CyclicTimeouts} instead.
*/
@Deprecated
public class TimeoutCompleteListener extends CyclicTimeout implements Response.CompleteListener
{
private static final Logger LOG = LoggerFactory.getLogger(TimeoutCompleteListener.class);
private final AtomicReference<Request> requestTimeout = new AtomicReference<>();
public TimeoutCompleteListener(Scheduler scheduler)
{
super(scheduler);
}
@Override
public void onTimeoutExpired()
{
Request request = requestTimeout.getAndSet(null);
if (LOG.isDebugEnabled())
LOG.debug("Total timeout {} ms elapsed for {} on {}", request.getTimeout(), request, this);
if (request != null)
request.abort(new TimeoutException("Total timeout " + request.getTimeout() + " ms elapsed"));
}
@Override
public void onComplete(Result result)
{
Request request = requestTimeout.getAndSet(null);
if (request != null)
{
boolean cancelled = cancel();
if (LOG.isDebugEnabled())
LOG.debug("Cancelled ({}) timeout for {} on {}", cancelled, request, this);
}
}
void schedule(HttpRequest request, long timeoutAt)
{
if (requestTimeout.compareAndSet(null, request))
{
long delay = Math.max(0, NanoTime.until(timeoutAt));
if (LOG.isDebugEnabled())
LOG.debug("Scheduling timeout in {} ms for {} on {}", TimeUnit.NANOSECONDS.toMillis(delay), request, this);
schedule(delay, TimeUnit.NANOSECONDS);
}
}
}

View File

@ -15,9 +15,10 @@ package org.eclipse.jetty.client;
import java.util.List; import java.util.List;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.internal.HttpConversation;
import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.internal.HttpRequest;
import org.eclipse.jetty.client.api.Result; import org.eclipse.jetty.client.internal.HttpResponse;
import org.eclipse.jetty.client.internal.ResponseNotifier;
import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpStatus;

View File

@ -19,8 +19,6 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import org.eclipse.jetty.client.api.Connection;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.NanoTime; import org.eclipse.jetty.util.NanoTime;
import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.component.Dumpable; import org.eclipse.jetty.util.component.Dumpable;
@ -60,9 +58,9 @@ public class ValidatingConnectionPool extends DuplexConnectionPool
private final long timeout; private final long timeout;
private final Map<Connection, Holder> quarantine; private final Map<Connection, Holder> quarantine;
public ValidatingConnectionPool(HttpDestination destination, int maxConnections, Callback requester, Scheduler scheduler, long timeout) public ValidatingConnectionPool(Destination destination, int maxConnections, Scheduler scheduler, long timeout)
{ {
super(destination, maxConnections, requester); super(destination, maxConnections);
this.scheduler = scheduler; this.scheduler = scheduler;
this.timeout = timeout; this.timeout = timeout;
this.quarantine = new ConcurrentHashMap<>(maxConnections); this.quarantine = new ConcurrentHashMap<>(maxConnections);

View File

@ -15,8 +15,6 @@ package org.eclipse.jetty.client;
import java.net.URI; import java.net.URI;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpStatus;

View File

@ -1,61 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.client.api;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.util.FuturePromise;
import org.eclipse.jetty.util.Promise;
/**
* {@link Destination} represents the triple made of the {@link #getScheme}, the {@link #getHost}
* and the {@link #getPort}.
* <p>
* {@link Destination} holds a pool of {@link Connection}s, but allows to create unpooled
* connections if the application wants full control over connection management via {@link #newConnection(Promise)}.
* <p>
* {@link Destination}s may be obtained via {@link HttpClient#resolveDestination(Request)}
*/
public interface Destination
{
/**
* @return the scheme of this destination, such as "http" or "https"
*/
String getScheme();
/**
* @return the host of this destination, such as "127.0.0.1" or "google.com"
*/
String getHost();
/**
* @return the port of this destination such as 80 or 443
*/
int getPort();
/**
* Creates asynchronously a new, unpooled, {@link Connection} that will be returned
* at a later time through the given {@link Promise}.
* <p>
* Use {@link FuturePromise} to wait for the connection:
* <pre>
* Destination destination = ...;
* FuturePromise&lt;Connection&gt; futureConnection = new FuturePromise&lt;&gt;();
* destination.newConnection(futureConnection);
* Connection connection = futureConnection.get(5, TimeUnit.SECONDS);
* </pre>
*
* @param promise the promise of a new, unpooled, {@link Connection}
*/
void newConnection(Promise<Connection> promise);
}

View File

@ -11,7 +11,7 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client; package org.eclipse.jetty.client.internal;
import java.net.URI; import java.net.URI;
import java.util.List; import java.util.List;
@ -19,9 +19,9 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import org.eclipse.jetty.client.api.Authentication; import org.eclipse.jetty.client.AbstractAuthentication;
import org.eclipse.jetty.client.api.AuthenticationStore; import org.eclipse.jetty.client.Authentication;
import org.eclipse.jetty.client.util.AbstractAuthentication; import org.eclipse.jetty.client.AuthenticationStore;
public class HttpAuthenticationStore implements AuthenticationStore public class HttpAuthenticationStore implements AuthenticationStore
{ {

View File

@ -11,9 +11,9 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client; package org.eclipse.jetty.client.internal;
import org.eclipse.jetty.client.api.Result; import org.eclipse.jetty.client.Result;
import org.eclipse.jetty.io.CyclicTimeouts; import org.eclipse.jetty.io.CyclicTimeouts;
import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.thread.AutoLock; import org.eclipse.jetty.util.thread.AutoLock;

View File

@ -11,7 +11,7 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client; package org.eclipse.jetty.client.internal;
import java.net.CookieStore; import java.net.CookieStore;
import java.net.HttpCookie; import java.net.HttpCookie;
@ -21,11 +21,15 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import org.eclipse.jetty.client.api.Authentication; import org.eclipse.jetty.client.Authentication;
import org.eclipse.jetty.client.api.AuthenticationStore; import org.eclipse.jetty.client.AuthenticationStore;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.BytesRequestContent;
import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.util.BytesRequestContent; import org.eclipse.jetty.client.HttpProxy;
import org.eclipse.jetty.client.HttpRequestException;
import org.eclipse.jetty.client.ProxyConfiguration;
import org.eclipse.jetty.client.Request;
import org.eclipse.jetty.client.Response;
import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;

View File

@ -11,7 +11,7 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client; package org.eclipse.jetty.client.internal;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -19,9 +19,9 @@ import java.nio.charset.UnsupportedCharsetException;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.Request;
import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.Response;
import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.HttpVersion;

View File

@ -11,15 +11,17 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client; package org.eclipse.jetty.client.internal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Deque; import java.util.Deque;
import java.util.List; import java.util.List;
import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.ConcurrentLinkedDeque;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.AuthenticationProtocolHandler;
import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.RedirectProtocolHandler;
import org.eclipse.jetty.client.Request;
import org.eclipse.jetty.client.Response;
import org.eclipse.jetty.util.AttributesMap; import org.eclipse.jetty.util.AttributesMap;
import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.Promise;
import org.slf4j.Logger; import org.slf4j.Logger;

View File

@ -11,9 +11,8 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client; package org.eclipse.jetty.client.internal;
import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import java.nio.channels.AsynchronousCloseException; import java.nio.channels.AsynchronousCloseException;
import java.util.ArrayList; import java.util.ArrayList;
@ -23,10 +22,14 @@ import java.util.Queue;
import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import org.eclipse.jetty.client.api.Connection; import org.eclipse.jetty.client.Connection;
import org.eclipse.jetty.client.api.Destination; import org.eclipse.jetty.client.ConnectionPool;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.Destination;
import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.Origin;
import org.eclipse.jetty.client.ProxyConfiguration;
import org.eclipse.jetty.client.Request;
import org.eclipse.jetty.client.Response;
import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.io.ClientConnectionFactory; import org.eclipse.jetty.io.ClientConnectionFactory;
@ -50,7 +53,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ManagedObject @ManagedObject
public class HttpDestination extends ContainerLifeCycle implements Destination, Closeable, Callback, Dumpable, Sweeper.Sweepable public class HttpDestination extends ContainerLifeCycle implements Destination, Callback, Dumpable, Sweeper.Sweepable
{ {
private static final Logger LOG = LoggerFactory.getLogger(HttpDestination.class); private static final Logger LOG = LoggerFactory.getLogger(HttpDestination.class);
@ -112,7 +115,7 @@ public class HttpDestination extends ContainerLifeCycle implements Destination,
public boolean stale() public boolean stale()
{ {
try (AutoLock l = staleLock.lock()) try (AutoLock ignored = staleLock.lock())
{ {
boolean stale = this.stale; boolean stale = this.stale;
if (!stale) if (!stale)
@ -129,7 +132,7 @@ public class HttpDestination extends ContainerLifeCycle implements Destination,
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("Sweep check in progress on {}", this); LOG.debug("Sweep check in progress on {}", this);
boolean remove = false; boolean remove = false;
try (AutoLock l = staleLock.lock()) try (AutoLock ignored = staleLock.lock())
{ {
boolean stale = exchanges.isEmpty() && connectionPool.isEmpty(); boolean stale = exchanges.isEmpty() && connectionPool.isEmpty();
if (!stale) if (!stale)
@ -161,22 +164,19 @@ public class HttpDestination extends ContainerLifeCycle implements Destination,
Sweeper connectionPoolSweeper = client.getBean(Sweeper.class); Sweeper connectionPoolSweeper = client.getBean(Sweeper.class);
if (connectionPoolSweeper != null && connectionPool instanceof Sweeper.Sweepable) if (connectionPoolSweeper != null && connectionPool instanceof Sweeper.Sweepable)
connectionPoolSweeper.offer((Sweeper.Sweepable)connectionPool); connectionPoolSweeper.offer((Sweeper.Sweepable)connectionPool);
Sweeper destinationSweeper = getHttpClient().getDestinationSweeper();
if (destinationSweeper != null)
destinationSweeper.offer(this);
} }
@Override @Override
protected void doStop() throws Exception protected void doStop() throws Exception
{ {
Sweeper destinationSweeper = getHttpClient().getDestinationSweeper(); requestTimeouts.destroy();
if (destinationSweeper != null) abort(new AsynchronousCloseException());
destinationSweeper.remove(this);
Sweeper connectionPoolSweeper = client.getBean(Sweeper.class); Sweeper connectionPoolSweeper = client.getBean(Sweeper.class);
if (connectionPoolSweeper != null && connectionPool instanceof Sweeper.Sweepable) if (connectionPoolSweeper != null && connectionPool instanceof Sweeper.Sweepable)
connectionPoolSweeper.remove((Sweeper.Sweepable)connectionPool); connectionPoolSweeper.remove((Sweeper.Sweepable)connectionPool);
super.doStop(); super.doStop();
removeBean(connectionPool); removeBean(connectionPool);
connectionPool.close();
} }
protected ConnectionPool newConnectionPool(HttpClient client) protected ConnectionPool newConnectionPool(HttpClient client)
@ -192,21 +192,24 @@ public class HttpDestination extends ContainerLifeCycle implements Destination,
return new BlockingArrayQueue<>(maxCapacity); return new BlockingArrayQueue<>(maxCapacity);
} }
protected ClientConnectionFactory newSslClientConnectionFactory(SslContextFactory.Client sslContextFactory, ClientConnectionFactory connectionFactory) private ClientConnectionFactory newSslClientConnectionFactory(SslContextFactory.Client sslContextFactory, ClientConnectionFactory connectionFactory)
{ {
return client.newSslClientConnectionFactory(sslContextFactory, connectionFactory); return client.newSslClientConnectionFactory(sslContextFactory, connectionFactory);
} }
@Override
public boolean isSecure() public boolean isSecure()
{ {
return HttpClient.isSchemeSecure(getScheme()); return HttpClient.isSchemeSecure(getScheme());
} }
@Override
public HttpClient getHttpClient() public HttpClient getHttpClient()
{ {
return client; return client;
} }
@Override
public Origin getOrigin() public Origin getOrigin()
{ {
return origin; return origin;
@ -227,6 +230,7 @@ public class HttpDestination extends ContainerLifeCycle implements Destination,
return responseNotifier; return responseNotifier;
} }
@Override
public ProxyConfiguration.Proxy getProxy() public ProxyConfiguration.Proxy getProxy()
{ {
return proxy; return proxy;
@ -237,14 +241,12 @@ public class HttpDestination extends ContainerLifeCycle implements Destination,
return connectionFactory; return connectionFactory;
} }
@Override
@ManagedAttribute(value = "The destination scheme", readonly = true) @ManagedAttribute(value = "The destination scheme", readonly = true)
public String getScheme() public String getScheme()
{ {
return getOrigin().getScheme(); return getOrigin().getScheme();
} }
@Override
@ManagedAttribute(value = "The destination host", readonly = true) @ManagedAttribute(value = "The destination host", readonly = true)
public String getHost() public String getHost()
{ {
@ -253,7 +255,6 @@ public class HttpDestination extends ContainerLifeCycle implements Destination,
return getOrigin().getAddress().getHost(); return getOrigin().getAddress().getHost();
} }
@Override
@ManagedAttribute(value = "The destination port", readonly = true) @ManagedAttribute(value = "The destination port", readonly = true)
public int getPort() public int getPort()
{ {
@ -266,11 +267,6 @@ public class HttpDestination extends ContainerLifeCycle implements Destination,
return exchanges.size(); return exchanges.size();
} }
public Origin.Address getConnectAddress()
{
return proxy == null ? getOrigin().getAddress() : proxy.getAddress();
}
public HttpField getHostField() public HttpField getHostField()
{ {
return hostField; return hostField;
@ -294,12 +290,13 @@ public class HttpDestination extends ContainerLifeCycle implements Destination,
abort(x); abort(x);
} }
@Override
public void send(Request request, Response.CompleteListener listener) public void send(Request request, Response.CompleteListener listener)
{ {
((HttpRequest)request).sendAsync(this, listener); ((HttpRequest)request).sendAsync(this, listener);
} }
protected void send(HttpRequest request, List<Response.ResponseListener> listeners) void send(HttpRequest request, List<Response.ResponseListener> listeners)
{ {
send(new HttpExchange(this, request, listeners)); send(new HttpExchange(this, request, listeners));
} }
@ -456,16 +453,6 @@ public class HttpDestination extends ContainerLifeCycle implements Destination,
return exchanges.remove(exchange); return exchanges.remove(exchange);
} }
@Override
public void close()
{
abort(new AsynchronousCloseException());
if (LOG.isDebugEnabled())
LOG.debug("Closed {}", this);
connectionPool.close();
requestTimeouts.destroy();
}
public void release(Connection connection) public void release(Connection connection)
{ {
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
@ -547,7 +534,7 @@ public class HttpDestination extends ContainerLifeCycle implements Destination,
{ {
if (getHttpClient().getDestinationIdleTimeout() <= 0L) if (getHttpClient().getDestinationIdleTimeout() <= 0L)
return -1; return -1;
try (AutoLock l = staleLock.lock()) try (AutoLock ignored = staleLock.lock())
{ {
return NanoTime.millisSince(activeNanoTime); return NanoTime.millisSince(activeNanoTime);
} }
@ -556,7 +543,7 @@ public class HttpDestination extends ContainerLifeCycle implements Destination,
@ManagedAttribute("Whether this destinations is stale") @ManagedAttribute("Whether this destinations is stale")
public boolean isStale() public boolean isStale()
{ {
try (AutoLock l = staleLock.lock()) try (AutoLock ignored = staleLock.lock())
{ {
return this.stale; return this.stale;
} }

View File

@ -11,13 +11,13 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client; package org.eclipse.jetty.client.internal;
import java.util.List; import java.util.List;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.Request;
import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.Response;
import org.eclipse.jetty.client.api.Result; import org.eclipse.jetty.client.Result;
import org.eclipse.jetty.io.CyclicTimeouts; import org.eclipse.jetty.io.CyclicTimeouts;
import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.thread.AutoLock; import org.eclipse.jetty.util.thread.AutoLock;

View File

@ -11,19 +11,18 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client; package org.eclipse.jetty.client.internal;
import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.ContentDecoder;
import org.eclipse.jetty.client.api.Result; import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.ProtocolHandler;
import org.eclipse.jetty.client.Response;
import org.eclipse.jetty.client.Result;
import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpStatus;
@ -131,7 +130,7 @@ public abstract class HttpReceiver
* Subclasses must have set the response status code on the {@link Response} object of the {@link HttpExchange} * Subclasses must have set the response status code on the {@link Response} object of the {@link HttpExchange}
* prior invoking this method. * prior invoking this method.
* <p> * <p>
* This method takes case of notifying {@link org.eclipse.jetty.client.api.Response.BeginListener}s. * This method takes case of notifying {@link Response.BeginListener}s.
* *
* @param exchange the HTTP exchange * @param exchange the HTTP exchange
*/ */
@ -176,7 +175,7 @@ public abstract class HttpReceiver
* Subclasses must not have added the header to the {@link Response} object of the {@link HttpExchange} * Subclasses must not have added the header to the {@link Response} object of the {@link HttpExchange}
* prior invoking this method. * prior invoking this method.
* <p> * <p>
* This method takes case of notifying {@link org.eclipse.jetty.client.api.Response.HeaderListener}s and storing cookies. * This method takes case of notifying {@link Response.HeaderListener}s and storing cookies.
* *
* @param exchange the HTTP exchange * @param exchange the HTTP exchange
* @param field the response HTTP field * @param field the response HTTP field
@ -223,27 +222,13 @@ public abstract class HttpReceiver
protected void storeCookie(URI uri, HttpField field) protected void storeCookie(URI uri, HttpField field)
{ {
try getHttpDestination().getHttpClient().putCookie(uri, field);
{
String value = field.getValue();
if (value != null)
{
Map<String, List<String>> header = new HashMap<>(1);
header.put(field.getHeader().asString(), Collections.singletonList(value));
getHttpDestination().getHttpClient().getCookieManager().put(uri, header);
}
}
catch (IOException x)
{
if (LOG.isDebugEnabled())
LOG.debug("Unable to store cookies {} from {}", field, uri, x);
}
} }
/** /**
* Method to be invoked after all response HTTP headers are available. * Method to be invoked after all response HTTP headers are available.
* <p> * <p>
* This method takes care of notifying {@link org.eclipse.jetty.client.api.Response.HeadersListener}s. * This method takes care of notifying {@link Response.HeadersListener}s.
* *
* @param exchange the HTTP exchange * @param exchange the HTTP exchange
*/ */
@ -331,8 +316,8 @@ public abstract class HttpReceiver
/** /**
* Method to be invoked when the response is successful. * Method to be invoked when the response is successful.
* <p> * <p>
* This method takes care of notifying {@link org.eclipse.jetty.client.api.Response.SuccessListener}s and possibly * This method takes care of notifying {@link Response.SuccessListener}s and possibly
* {@link org.eclipse.jetty.client.api.Response.CompleteListener}s (if the exchange is completed). * {@link Response.CompleteListener}s (if the exchange is completed).
* *
* @param exchange the HTTP exchange * @param exchange the HTTP exchange
* @param afterSuccessTask an optional task to invoke afterwards * @param afterSuccessTask an optional task to invoke afterwards
@ -376,7 +361,7 @@ public abstract class HttpReceiver
/** /**
* Method to be invoked when the response is failed. * Method to be invoked when the response is failed.
* <p> * <p>
* This method takes care of notifying {@link org.eclipse.jetty.client.api.Response.FailureListener}s. * This method takes care of notifying {@link Response.FailureListener}s.
* *
* @param failure the response failure * @param failure the response failure
*/ */

View File

@ -11,7 +11,7 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client; package org.eclipse.jetty.client.internal;
import java.io.IOException; import java.io.IOException;
import java.net.HttpCookie; import java.net.HttpCookie;
@ -35,17 +35,19 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.Destination;
import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.FutureResponseListener;
import org.eclipse.jetty.client.api.Result; import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.util.FutureResponseListener; import org.eclipse.jetty.client.Origin;
import org.eclipse.jetty.client.util.PathRequestContent; import org.eclipse.jetty.client.PathRequestContent;
import org.eclipse.jetty.client.Request;
import org.eclipse.jetty.client.Response;
import org.eclipse.jetty.client.Result;
import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
@ -84,11 +86,10 @@ public class HttpRequest implements Request
private List<RequestListener> requestListeners; private List<RequestListener> requestListeners;
private BiFunction<Request, Request, Response.CompleteListener> pushHandler; private BiFunction<Request, Request, Response.CompleteListener> pushHandler;
private Supplier<HttpFields> trailers; private Supplier<HttpFields> trailers;
private String upgradeProtocol;
private Object tag; private Object tag;
private boolean normalized; private boolean normalized;
protected HttpRequest(HttpClient client, HttpConversation conversation, URI uri) public HttpRequest(HttpClient client, HttpConversation conversation, URI uri)
{ {
this.client = client; this.client = client;
this.conversation = conversation; this.conversation = conversation;
@ -100,7 +101,7 @@ public class HttpRequest implements Request
extractParams(query); extractParams(query);
followRedirects(client.isFollowRedirects()); followRedirects(client.isFollowRedirects());
HttpField acceptEncodingField = client.getAcceptEncodingField(); HttpField acceptEncodingField = client.getContentDecoderFactories().getAcceptEncodingField();
if (acceptEncodingField != null) if (acceptEncodingField != null)
headers.put(acceptEncodingField); headers.put(acceptEncodingField);
HttpField userAgentField = client.getUserAgentField(); HttpField userAgentField = client.getUserAgentField();
@ -627,12 +628,6 @@ public class HttpRequest implements Request
return this; return this;
} }
public HttpRequest upgradeProtocol(String upgradeProtocol)
{
this.upgradeProtocol = upgradeProtocol;
return this;
}
@Override @Override
public Content getBody() public Content getBody()
{ {
@ -740,19 +735,15 @@ public class HttpRequest implements Request
@Override @Override
public void send(Response.CompleteListener listener) public void send(Response.CompleteListener listener)
{ {
sendAsync(client::send, listener); Destination destination = client.resolveDestination(this);
destination.send(this, listener);
} }
void sendAsync(HttpDestination destination, Response.CompleteListener listener) void sendAsync(HttpDestination destination, Response.CompleteListener listener)
{
sendAsync(destination::send, listener);
}
private void sendAsync(BiConsumer<HttpRequest, List<Response.ResponseListener>> sender, Response.CompleteListener listener)
{ {
if (listener != null) if (listener != null)
responseListeners.add(listener); responseListeners.add(listener);
sender.accept(this, responseListeners); destination.send(this, responseListeners);
} }
void sent() void sent()
@ -769,7 +760,7 @@ public class HttpRequest implements Request
* @return The nanoTime at which the timeout expires or {@link Long#MAX_VALUE} if there is no timeout. * @return The nanoTime at which the timeout expires or {@link Long#MAX_VALUE} if there is no timeout.
* @see #timeout(long, TimeUnit) * @see #timeout(long, TimeUnit)
*/ */
long getTimeoutNanoTime() public long getTimeoutNanoTime()
{ {
return timeoutNanoTime; return timeoutNanoTime;
} }
@ -790,11 +781,6 @@ public class HttpRequest implements Request
return trailers; return trailers;
} }
public String getUpgradeProtocol()
{
return upgradeProtocol;
}
@Override @Override
public CompletableFuture<Boolean> abort(Throwable cause) public CompletableFuture<Boolean> abort(Throwable cause)
{ {

View File

@ -11,15 +11,15 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client; package org.eclipse.jetty.client.internal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.Request;
import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.Response;
import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.HttpVersion;

View File

@ -11,7 +11,7 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client; package org.eclipse.jetty.client.internal;
import java.net.URI; import java.net.URI;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -19,8 +19,8 @@ import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.Request;
import org.eclipse.jetty.client.api.Result; import org.eclipse.jetty.client.Result;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpHeaderValue; import org.eclipse.jetty.http.HttpHeaderValue;
import org.eclipse.jetty.io.Content; import org.eclipse.jetty.io.Content;

View File

@ -11,9 +11,9 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client; package org.eclipse.jetty.client.internal;
import org.eclipse.jetty.client.api.Connection; import org.eclipse.jetty.client.Connection;
public interface IConnection extends Connection public interface IConnection extends Connection
{ {

View File

@ -11,12 +11,13 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client; package org.eclipse.jetty.client.internal;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.List; import java.util.List;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.Request;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;

View File

@ -11,7 +11,7 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client; package org.eclipse.jetty.client.internal;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Iterator; import java.util.Iterator;
@ -19,10 +19,10 @@ import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.Request;
import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.Response;
import org.eclipse.jetty.client.api.Result; import org.eclipse.jetty.client.Result;
import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.io.Content; import org.eclipse.jetty.io.Content;
import org.eclipse.jetty.io.content.ByteBufferContentSource; import org.eclipse.jetty.io.content.ByteBufferContentSource;

View File

@ -11,7 +11,7 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client; package org.eclipse.jetty.client.internal;
public class SendFailure public class SendFailure
{ {

View File

@ -11,8 +11,17 @@
// ======================================================================== // ========================================================================
// //
/** package org.eclipse.jetty.client.internal;
* Jetty Client : API Classes
*/
package org.eclipse.jetty.client.api;
import java.net.URI;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.Origin;
public class TunnelRequest extends HttpRequest
{
public TunnelRequest(HttpClient client, Origin.Address address)
{
super(client, new HttpConversation(), URI.create("http://" + address.asString()));
}
}

View File

@ -1,45 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
/**
* Jetty Client : Implementation and Core Classes
*
* This package provides APIs, utility classes and an implementation of an asynchronous HTTP client.
* <p>
* The core class is {@link org.eclipse.jetty.client.HttpClient}, which acts as a central configuration object (for example
* for {@link org.eclipse.jetty.client.HttpClient#setIdleTimeout(long) idle timeouts}, {@link org.eclipse.jetty.client.HttpClient#setMaxConnectionsPerDestination(int)
* max connections per destination}, etc.) and as a factory for {@link org.eclipse.jetty.client.api.Request} objects.
* <p>
* The HTTP protocol is based on the request/response paradigm, a unit that in this implementation is called
* <em>exchange</em> and is represented by {@link org.eclipse.jetty.client.HttpExchange}.
* An initial request may trigger a sequence of exchanges with one or more servers, called a <em>conversation</em>
* and represented by {@link org.eclipse.jetty.client.HttpConversation}. A typical example of a conversation is a redirect, where
* upon a request for a resource URI, the server replies with a redirect (for example with the 303 status code)
* to another URI. This conversation is made of a first exchange made of the original request and its 303 response,
* and of a second exchange made of the request for the new URI and its 200 response.
* <p>
* {@link org.eclipse.jetty.client.HttpClient} holds a number of {@link org.eclipse.jetty.client.api.Destination destinations}, which in turn hold a number of
* pooled {@link org.eclipse.jetty.client.api.Connection connections}.
* <p>
* When a request is sent, its exchange is associated to a connection, either taken from an idle queue or created
* anew, and when both the request and response are completed, the exchange is disassociated from the connection.
* Conversations may span multiple connections on different destinations, and therefore are maintained at the
* {@link org.eclipse.jetty.client.HttpClient} level.
* <p>
* Applications may decide to send the request and wait for the response in a blocking way, using
* {@link org.eclipse.jetty.client.api.Request#send()}.
* Alternatively, application may ask to be notified of response events asynchronously, using
* {@link org.eclipse.jetty.client.api.Request#send(org.eclipse.jetty.client.api.Response.CompleteListener)}.
*/
package org.eclipse.jetty.client;

View File

@ -11,12 +11,12 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client.http; package org.eclipse.jetty.client.transport;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.eclipse.jetty.client.dynamic.HttpClientTransportDynamic; import org.eclipse.jetty.client.transport.internal.HttpConnectionOverHTTP;
import org.eclipse.jetty.io.ClientConnectionFactory; import org.eclipse.jetty.io.ClientConnectionFactory;
import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EndPoint;

View File

@ -11,7 +11,7 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client.dynamic; package org.eclipse.jetty.client.transport;
import java.io.IOException; import java.io.IOException;
import java.net.SocketAddress; import java.net.SocketAddress;
@ -27,13 +27,14 @@ import java.util.stream.Stream;
import org.eclipse.jetty.alpn.client.ALPNClientConnection; import org.eclipse.jetty.alpn.client.ALPNClientConnection;
import org.eclipse.jetty.alpn.client.ALPNClientConnectionFactory; import org.eclipse.jetty.alpn.client.ALPNClientConnectionFactory;
import org.eclipse.jetty.client.AbstractConnectorHttpClientTransport; import org.eclipse.jetty.client.AbstractConnectorHttpClientTransport;
import org.eclipse.jetty.client.Destination;
import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.HttpClientTransport; import org.eclipse.jetty.client.HttpClientTransport;
import org.eclipse.jetty.client.HttpDestination;
import org.eclipse.jetty.client.HttpRequest;
import org.eclipse.jetty.client.MultiplexConnectionPool; import org.eclipse.jetty.client.MultiplexConnectionPool;
import org.eclipse.jetty.client.Origin; import org.eclipse.jetty.client.Origin;
import org.eclipse.jetty.client.http.HttpClientConnectionFactory; import org.eclipse.jetty.client.Request;
import org.eclipse.jetty.client.internal.HttpDestination;
import org.eclipse.jetty.client.internal.HttpRequest;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.io.ClientConnectionFactory; import org.eclipse.jetty.io.ClientConnectionFactory;
@ -76,7 +77,7 @@ import org.slf4j.LoggerFactory;
* Therefore a destination is identified by a {@link org.eclipse.jetty.client.Origin} and * Therefore a destination is identified by a {@link org.eclipse.jetty.client.Origin} and
* applications can customize the creation of the origin (for example depending on request protocol * applications can customize the creation of the origin (for example depending on request protocol
* version, or request headers, or request attributes, or even request path) by overriding * version, or request headers, or request attributes, or even request path) by overriding
* {@link HttpClientTransport#newOrigin(HttpRequest)}.</p> * {@link HttpClientTransport#newOrigin(Request)}.</p>
*/ */
public class HttpClientTransportDynamic extends AbstractConnectorHttpClientTransport public class HttpClientTransportDynamic extends AbstractConnectorHttpClientTransport
{ {
@ -117,7 +118,7 @@ public class HttpClientTransportDynamic extends AbstractConnectorHttpClientTrans
.collect(Collectors.toList()); .collect(Collectors.toList());
Arrays.stream(factoryInfos).forEach(this::addBean); Arrays.stream(factoryInfos).forEach(this::addBean);
setConnectionPoolFactory(destination -> setConnectionPoolFactory(destination ->
new MultiplexConnectionPool(destination, destination.getHttpClient().getMaxConnectionsPerDestination(), destination, 1)); new MultiplexConnectionPool(destination, destination.getHttpClient().getMaxConnectionsPerDestination(), 1));
} }
private static ClientConnector findClientConnector(ClientConnectionFactory.Info[] infos) private static ClientConnector findClientConnector(ClientConnectionFactory.Info[] infos)
@ -129,13 +130,13 @@ public class HttpClientTransportDynamic extends AbstractConnectorHttpClientTrans
} }
@Override @Override
public Origin newOrigin(HttpRequest request) public Origin newOrigin(Request request)
{ {
boolean secure = HttpClient.isSchemeSecure(request.getScheme()); boolean secure = HttpClient.isSchemeSecure(request.getScheme());
String http1 = "http/1.1"; String http1 = "http/1.1";
String http2 = secure ? "h2" : "h2c"; String http2 = secure ? "h2" : "h2c";
List<String> protocols = List.of(); List<String> protocols = List.of();
if (request.isVersionExplicit()) if (((HttpRequest)request).isVersionExplicit())
{ {
HttpVersion version = request.getVersion(); HttpVersion version = request.getVersion();
String desired = version == HttpVersion.HTTP_2 ? http2 : http1; String desired = version == HttpVersion.HTTP_2 ? http2 : http1;
@ -175,7 +176,7 @@ public class HttpClientTransportDynamic extends AbstractConnectorHttpClientTrans
} }
@Override @Override
public HttpDestination newHttpDestination(Origin origin) public Destination newDestination(Origin origin)
{ {
SocketAddress address = origin.getAddress().getSocketAddress(); SocketAddress address = origin.getAddress().getSocketAddress();
return new HttpDestination(getHttpClient(), origin, getClientConnector().isIntrinsicallySecure(address)); return new HttpDestination(getHttpClient(), origin, getClientConnector().isIntrinsicallySecure(address));

View File

@ -11,7 +11,7 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client.http; package org.eclipse.jetty.client.transport;
import java.io.IOException; import java.io.IOException;
import java.net.SocketAddress; import java.net.SocketAddress;
@ -19,10 +19,11 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import org.eclipse.jetty.client.AbstractConnectorHttpClientTransport; import org.eclipse.jetty.client.AbstractConnectorHttpClientTransport;
import org.eclipse.jetty.client.Destination;
import org.eclipse.jetty.client.DuplexConnectionPool; import org.eclipse.jetty.client.DuplexConnectionPool;
import org.eclipse.jetty.client.HttpDestination;
import org.eclipse.jetty.client.HttpRequest;
import org.eclipse.jetty.client.Origin; import org.eclipse.jetty.client.Origin;
import org.eclipse.jetty.client.Request;
import org.eclipse.jetty.client.internal.HttpDestination;
import org.eclipse.jetty.io.ClientConnectionFactory; import org.eclipse.jetty.io.ClientConnectionFactory;
import org.eclipse.jetty.io.ClientConnector; import org.eclipse.jetty.io.ClientConnector;
import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EndPoint;
@ -56,17 +57,17 @@ public class HttpClientTransportOverHTTP extends AbstractConnectorHttpClientTran
public HttpClientTransportOverHTTP(ClientConnector connector) public HttpClientTransportOverHTTP(ClientConnector connector)
{ {
super(connector); super(connector);
setConnectionPoolFactory(destination -> new DuplexConnectionPool(destination, getHttpClient().getMaxConnectionsPerDestination(), destination)); setConnectionPoolFactory(destination -> new DuplexConnectionPool(destination, getHttpClient().getMaxConnectionsPerDestination()));
} }
@Override @Override
public Origin newOrigin(HttpRequest request) public Origin newOrigin(Request request)
{ {
return getHttpClient().createOrigin(request, HTTP11); return getHttpClient().createOrigin(request, HTTP11);
} }
@Override @Override
public HttpDestination newHttpDestination(Origin origin) public Destination newDestination(Origin origin)
{ {
SocketAddress address = origin.getAddress().getSocketAddress(); SocketAddress address = origin.getAddress().getSocketAddress();
return new HttpDestination(getHttpClient(), origin, getClientConnector().isIntrinsicallySecure(address)); return new HttpDestination(getHttpClient(), origin, getClientConnector().isIntrinsicallySecure(address));

View File

@ -11,14 +11,14 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client.http; package org.eclipse.jetty.client.transport.internal;
import java.util.concurrent.atomic.LongAdder; import java.util.concurrent.atomic.LongAdder;
import org.eclipse.jetty.client.HttpChannel; import org.eclipse.jetty.client.Response;
import org.eclipse.jetty.client.HttpExchange; import org.eclipse.jetty.client.Result;
import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.internal.HttpChannel;
import org.eclipse.jetty.client.api.Result; import org.eclipse.jetty.client.internal.HttpExchange;
import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpHeaderValue; import org.eclipse.jetty.http.HttpHeaderValue;

View File

@ -11,7 +11,7 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client.http; package org.eclipse.jetty.client.transport.internal;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousCloseException; import java.nio.channels.AsynchronousCloseException;
@ -24,20 +24,20 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.LongAdder; import java.util.concurrent.atomic.LongAdder;
import org.eclipse.jetty.client.HttpChannel; import org.eclipse.jetty.client.Connection;
import org.eclipse.jetty.client.HttpClientTransport; import org.eclipse.jetty.client.HttpClientTransport;
import org.eclipse.jetty.client.HttpConnection;
import org.eclipse.jetty.client.HttpConversation;
import org.eclipse.jetty.client.HttpDestination;
import org.eclipse.jetty.client.HttpExchange;
import org.eclipse.jetty.client.HttpProxy;
import org.eclipse.jetty.client.HttpRequest;
import org.eclipse.jetty.client.HttpUpgrader; import org.eclipse.jetty.client.HttpUpgrader;
import org.eclipse.jetty.client.IConnection; import org.eclipse.jetty.client.Request;
import org.eclipse.jetty.client.SendFailure; import org.eclipse.jetty.client.Response;
import org.eclipse.jetty.client.api.Connection; import org.eclipse.jetty.client.internal.HttpChannel;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.internal.HttpConnection;
import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.internal.HttpConversation;
import org.eclipse.jetty.client.internal.HttpDestination;
import org.eclipse.jetty.client.internal.HttpExchange;
import org.eclipse.jetty.client.internal.HttpRequest;
import org.eclipse.jetty.client.internal.IConnection;
import org.eclipse.jetty.client.internal.SendFailure;
import org.eclipse.jetty.client.internal.TunnelRequest;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.io.AbstractConnection; import org.eclipse.jetty.io.AbstractConnection;
@ -204,7 +204,7 @@ public class HttpConnectionOverHTTP extends AbstractConnection implements IConne
void onResponseHeaders(HttpExchange exchange) void onResponseHeaders(HttpExchange exchange)
{ {
HttpRequest request = exchange.getRequest(); HttpRequest request = exchange.getRequest();
if (request instanceof HttpProxy.TunnelRequest) if (request instanceof TunnelRequest)
{ {
// Restore idle timeout // Restore idle timeout
getEndPoint().setIdleTimeout(idleTimeout); getEndPoint().setIdleTimeout(idleTimeout);
@ -309,7 +309,7 @@ public class HttpConnectionOverHTTP extends AbstractConnection implements IConne
{ {
super.normalizeRequest(request); super.normalizeRequest(request);
if (request instanceof HttpProxy.TunnelRequest) if (request instanceof TunnelRequest)
{ {
// Override the idle timeout in case it is shorter than the connect timeout. // Override the idle timeout in case it is shorter than the connect timeout.
request.idleTimeout(2 * getHttpClient().getConnectTimeout(), TimeUnit.MILLISECONDS); request.idleTimeout(2 * getHttpClient().getConnectTimeout(), TimeUnit.MILLISECONDS);
@ -319,9 +319,10 @@ public class HttpConnectionOverHTTP extends AbstractConnection implements IConne
HttpUpgrader upgrader = (HttpUpgrader)conversation.getAttribute(HttpUpgrader.class.getName()); HttpUpgrader upgrader = (HttpUpgrader)conversation.getAttribute(HttpUpgrader.class.getName());
if (upgrader == null) if (upgrader == null)
{ {
if (request instanceof HttpUpgrader.Factory) HttpUpgrader.Factory upgraderFactory = (HttpUpgrader.Factory)request.getAttributes().get(HttpUpgrader.Factory.class.getName());
if (upgraderFactory != null)
{ {
upgrader = ((HttpUpgrader.Factory)request).newHttpUpgrader(HttpVersion.HTTP_1_1); upgrader = upgraderFactory.newHttpUpgrader(HttpVersion.HTTP_1_1);
conversation.setAttribute(HttpUpgrader.class.getName(), upgrader); conversation.setAttribute(HttpUpgrader.class.getName(), upgrader);
upgrader.prepare(request); upgrader.prepare(request);
} }

View File

@ -11,7 +11,7 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client.http; package org.eclipse.jetty.client.transport.internal;
import java.io.EOFException; import java.io.EOFException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -19,10 +19,11 @@ import java.util.concurrent.atomic.LongAdder;
import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.HttpClientTransport; import org.eclipse.jetty.client.HttpClientTransport;
import org.eclipse.jetty.client.HttpExchange;
import org.eclipse.jetty.client.HttpReceiver;
import org.eclipse.jetty.client.HttpResponse;
import org.eclipse.jetty.client.HttpResponseException; import org.eclipse.jetty.client.HttpResponseException;
import org.eclipse.jetty.client.internal.HttpExchange;
import org.eclipse.jetty.client.internal.HttpReceiver;
import org.eclipse.jetty.client.internal.HttpResponse;
import org.eclipse.jetty.client.transport.HttpClientTransportOverHTTP;
import org.eclipse.jetty.http.BadMessageException; import org.eclipse.jetty.http.BadMessageException;
import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpMethod;

View File

@ -11,15 +11,15 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client.http; package org.eclipse.jetty.client.transport.internal;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.HttpExchange;
import org.eclipse.jetty.client.HttpRequest;
import org.eclipse.jetty.client.HttpRequestException; import org.eclipse.jetty.client.HttpRequestException;
import org.eclipse.jetty.client.HttpSender; import org.eclipse.jetty.client.internal.HttpExchange;
import org.eclipse.jetty.client.internal.HttpRequest;
import org.eclipse.jetty.client.internal.HttpSender;
import org.eclipse.jetty.http.HttpGenerator; import org.eclipse.jetty.http.HttpGenerator;
import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http.MetaData;

View File

@ -11,21 +11,23 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.client.http; package org.eclipse.jetty.client.transport.internal;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.eclipse.jetty.client.Destination;
import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.HttpClientTransport; import org.eclipse.jetty.client.HttpClientTransport;
import org.eclipse.jetty.client.HttpDestination;
import org.eclipse.jetty.client.HttpRequest;
import org.eclipse.jetty.client.HttpResponse;
import org.eclipse.jetty.client.HttpResponseException; import org.eclipse.jetty.client.HttpResponseException;
import org.eclipse.jetty.client.HttpUpgrader; import org.eclipse.jetty.client.HttpUpgrader;
import org.eclipse.jetty.client.Origin; import org.eclipse.jetty.client.Origin;
import org.eclipse.jetty.client.dynamic.HttpClientTransportDynamic; import org.eclipse.jetty.client.Request;
import org.eclipse.jetty.client.Response;
import org.eclipse.jetty.client.internal.HttpDestination;
import org.eclipse.jetty.client.internal.HttpResponse;
import org.eclipse.jetty.client.transport.HttpClientTransportDynamic;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Callback;
@ -54,12 +56,12 @@ public class ProtocolHttpUpgrader implements HttpUpgrader
} }
@Override @Override
public void prepare(HttpRequest request) public void prepare(Request request)
{ {
} }
@Override @Override
public void upgrade(HttpResponse response, EndPoint endPoint, Callback callback) public void upgrade(Response response, EndPoint endPoint, Callback callback)
{ {
if (response.getHeaders().contains(HttpHeader.UPGRADE, protocol)) if (response.getHeaders().contains(HttpHeader.UPGRADE, protocol))
{ {
@ -71,7 +73,7 @@ public class ProtocolHttpUpgrader implements HttpUpgrader
Origin origin = destination.getOrigin(); Origin origin = destination.getOrigin();
Origin newOrigin = new Origin(origin.getScheme(), origin.getAddress(), origin.getTag(), new Origin.Protocol(List.of(protocol), false)); Origin newOrigin = new Origin(origin.getScheme(), origin.getAddress(), origin.getTag(), new Origin.Protocol(List.of(protocol), false));
HttpDestination newDestination = httpClient.resolveDestination(newOrigin); Destination newDestination = httpClient.resolveDestination(newOrigin);
Map<String, Object> context = new HashMap<>(); Map<String, Object> context = new HashMap<>();
context.put(HttpClientTransport.HTTP_DESTINATION_CONTEXT_KEY, newDestination); context.put(HttpClientTransport.HTTP_DESTINATION_CONTEXT_KEY, newDestination);

View File

@ -1,18 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
/**
* Jetty Client : Utility Classes
*/
package org.eclipse.jetty.client.util;

View File

@ -18,7 +18,7 @@ import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP; import org.eclipse.jetty.client.transport.HttpClientTransportOverHTTP;
import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.io.ClientConnector; import org.eclipse.jetty.io.ClientConnector;
import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Handler;

View File

@ -18,10 +18,9 @@ import java.nio.ByteBuffer;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.client.internal.HttpDestination;
import org.eclipse.jetty.client.http.HttpConnectionOverHTTP; import org.eclipse.jetty.client.internal.HttpResponse;
import org.eclipse.jetty.client.util.AsyncRequestContent; import org.eclipse.jetty.client.transport.internal.HttpConnectionOverHTTP;
import org.eclipse.jetty.client.util.StringRequestContent;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpHeaderValue; import org.eclipse.jetty.http.HttpHeaderValue;
import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpStatus;

View File

@ -13,8 +13,6 @@
package org.eclipse.jetty.client; package org.eclipse.jetty.client;
import org.eclipse.jetty.client.api.Connection;
public class ConnectionPoolHelper public class ConnectionPoolHelper
{ {
public static Connection acquire(AbstractConnectionPool connectionPool, boolean create) public static Connection acquire(AbstractConnectionPool connectionPool, boolean create)

View File

@ -17,8 +17,7 @@ import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.client.transport.HttpClientTransportOverHTTP;
import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.io.Content; import org.eclipse.jetty.io.Content;
@ -76,7 +75,7 @@ public class ConnectionPoolMaxUsageTest
String host = "localhost"; String host = "localhost";
int port = connector.getLocalPort(); int port = connector.getLocalPort();
HttpDestination destination = httpClient.resolveDestination(new Origin("http", host, port, null, HttpClientTransportOverHTTP.HTTP11)); Destination destination = httpClient.resolveDestination(new Origin("http", host, port, null, HttpClientTransportOverHTTP.HTTP11));
AbstractConnectionPool connectionPool = (AbstractConnectionPool)destination.getConnectionPool(); AbstractConnectionPool connectionPool = (AbstractConnectionPool)destination.getConnectionPool();
int maxUsage = 3; int maxUsage = 3;
connectionPool.setMaxUsage(maxUsage); connectionPool.setMaxUsage(maxUsage);
@ -119,7 +118,7 @@ public class ConnectionPoolMaxUsageTest
String host = "localhost"; String host = "localhost";
int port = connector.getLocalPort(); int port = connector.getLocalPort();
HttpDestination destination = httpClient.resolveDestination(new Origin("http", host, port, null, HttpClientTransportOverHTTP.HTTP11)); Destination destination = httpClient.resolveDestination(new Origin("http", host, port, null, HttpClientTransportOverHTTP.HTTP11));
AbstractConnectionPool connectionPool = (AbstractConnectionPool)destination.getConnectionPool(); AbstractConnectionPool connectionPool = (AbstractConnectionPool)destination.getConnectionPool();
int maxUsage = 3; int maxUsage = 3;
connectionPool.setMaxUsage(maxUsage); connectionPool.setMaxUsage(maxUsage);

View File

@ -25,13 +25,8 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.eclipse.jetty.client.api.Connection; import org.eclipse.jetty.client.internal.HttpDestination;
import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.client.transport.HttpClientTransportOverHTTP;
import org.eclipse.jetty.client.api.Destination;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
import org.eclipse.jetty.client.util.BytesRequestContent;
import org.eclipse.jetty.client.util.FutureResponseListener;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpHeaderValue; import org.eclipse.jetty.http.HttpHeaderValue;
import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpMethod;
@ -65,16 +60,16 @@ public class ConnectionPoolTest
{ {
private static final Logger LOG = LoggerFactory.getLogger(ConnectionPoolTest.class); private static final Logger LOG = LoggerFactory.getLogger(ConnectionPoolTest.class);
private static final ConnectionPoolFactory DUPLEX = new ConnectionPoolFactory("duplex", destination -> new DuplexConnectionPool(destination, destination.getHttpClient().getMaxConnectionsPerDestination(), destination)); private static final ConnectionPoolFactory DUPLEX = new ConnectionPoolFactory("duplex", destination -> new DuplexConnectionPool(destination, destination.getHttpClient().getMaxConnectionsPerDestination()));
private static final ConnectionPoolFactory MULTIPLEX = new ConnectionPoolFactory("multiplex", destination -> new MultiplexConnectionPool(destination, destination.getHttpClient().getMaxConnectionsPerDestination(), destination, 1)); private static final ConnectionPoolFactory MULTIPLEX = new ConnectionPoolFactory("multiplex", destination -> new MultiplexConnectionPool(destination, destination.getHttpClient().getMaxConnectionsPerDestination(), 1));
private static final ConnectionPoolFactory RANDOM = new ConnectionPoolFactory("random", destination -> new RandomConnectionPool(destination, destination.getHttpClient().getMaxConnectionsPerDestination(), destination, 1)); private static final ConnectionPoolFactory RANDOM = new ConnectionPoolFactory("random", destination -> new RandomConnectionPool(destination, destination.getHttpClient().getMaxConnectionsPerDestination(), 1));
private static final ConnectionPoolFactory DUPLEX_MAX_DURATION = new ConnectionPoolFactory("duplex-maxDuration", destination -> private static final ConnectionPoolFactory DUPLEX_MAX_DURATION = new ConnectionPoolFactory("duplex-maxDuration", destination ->
{ {
DuplexConnectionPool pool = new DuplexConnectionPool(destination, destination.getHttpClient().getMaxConnectionsPerDestination(), destination); DuplexConnectionPool pool = new DuplexConnectionPool(destination, destination.getHttpClient().getMaxConnectionsPerDestination());
pool.setMaxDuration(10); pool.setMaxDuration(10);
return pool; return pool;
}); });
private static final ConnectionPoolFactory ROUND_ROBIN = new ConnectionPoolFactory("round-robin", destination -> new RoundRobinConnectionPool(destination, destination.getHttpClient().getMaxConnectionsPerDestination(), destination)); private static final ConnectionPoolFactory ROUND_ROBIN = new ConnectionPoolFactory("round-robin", destination -> new RoundRobinConnectionPool(destination, destination.getHttpClient().getMaxConnectionsPerDestination()));
public static Stream<ConnectionPoolFactory> pools() public static Stream<ConnectionPoolFactory> pools()
{ {
@ -487,7 +482,7 @@ public class ConnectionPoolTest
ConnectionPoolFactory factory = new ConnectionPoolFactory("duplex-maxDuration", destination -> ConnectionPoolFactory factory = new ConnectionPoolFactory("duplex-maxDuration", destination ->
{ {
// Constrain the max pool size to 1. // Constrain the max pool size to 1.
DuplexConnectionPool pool = new DuplexConnectionPool(destination, maxConnections, destination) DuplexConnectionPool pool = new DuplexConnectionPool(destination, maxConnections)
{ {
@Override @Override
protected void onCreated(Connection connection) protected void onCreated(Connection connection)
@ -541,7 +536,7 @@ public class ConnectionPoolTest
AtomicInteger poolRemoveCounter = new AtomicInteger(); AtomicInteger poolRemoveCounter = new AtomicInteger();
ConnectionPoolFactory factory = new ConnectionPoolFactory("duplex-maxDuration", destination -> ConnectionPoolFactory factory = new ConnectionPoolFactory("duplex-maxDuration", destination ->
{ {
DuplexConnectionPool pool = new DuplexConnectionPool(destination, destination.getHttpClient().getMaxConnectionsPerDestination(), destination) DuplexConnectionPool pool = new DuplexConnectionPool(destination, destination.getHttpClient().getMaxConnectionsPerDestination())
{ {
@Override @Override
protected void onCreated(Connection connection) protected void onCreated(Connection connection)
@ -652,7 +647,7 @@ public class ConnectionPoolTest
client.setIdleTimeout(idleTimeout); client.setIdleTimeout(idleTimeout);
// Trigger the creation of a destination, that will create the connection pool. // Trigger the creation of a destination, that will create the connection pool.
HttpDestination destination = client.resolveDestination(new Origin("http", "localhost", connector.getLocalPort())); Destination destination = client.resolveDestination(new Origin("http", "localhost", connector.getLocalPort()));
AbstractConnectionPool connectionPool = (AbstractConnectionPool)destination.getConnectionPool(); AbstractConnectionPool connectionPool = (AbstractConnectionPool)destination.getConnectionPool();
if (DUPLEX_MAX_DURATION == factory) if (DUPLEX_MAX_DURATION == factory)
assertThat(connectionPool.getConnectionCount(), lessThanOrEqualTo(1)); // The connections can expire upon release. assertThat(connectionPool.getConnectionCount(), lessThanOrEqualTo(1)); // The connections can expire upon release.

View File

@ -17,7 +17,6 @@ import java.nio.ByteBuffer;
import java.util.Random; import java.util.Random;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.io.Content; import org.eclipse.jetty.io.Content;
import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Handler;

View File

@ -20,10 +20,7 @@ import java.util.concurrent.TimeUnit;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.awaitility.Awaitility; import org.awaitility.Awaitility;
import org.eclipse.jetty.client.api.Connection; import org.eclipse.jetty.client.internal.HttpDestination;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Destination;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpHeaderValue; import org.eclipse.jetty.http.HttpHeaderValue;
import org.eclipse.jetty.util.NanoTime; import org.eclipse.jetty.util.NanoTime;
@ -48,7 +45,8 @@ public class DuplexHttpDestinationTest extends AbstractHttpClientServerTest
{ {
start(scenario, new EmptyServerHandler()); start(scenario, new EmptyServerHandler());
try (HttpDestination destination = new HttpDestination(client, new Origin("http", "localhost", connector.getLocalPort()), false)) HttpDestination destination = new HttpDestination(client, new Origin("http", "localhost", connector.getLocalPort()), false);
try
{ {
destination.start(); destination.start();
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool(); DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
@ -60,6 +58,10 @@ public class DuplexHttpDestinationTest extends AbstractHttpClientServerTest
} }
assertNotNull(connection); assertNotNull(connection);
} }
finally
{
destination.stop();
}
} }
@ParameterizedTest @ParameterizedTest
@ -68,7 +70,8 @@ public class DuplexHttpDestinationTest extends AbstractHttpClientServerTest
{ {
start(scenario, new EmptyServerHandler()); start(scenario, new EmptyServerHandler());
try (HttpDestination destination = new HttpDestination(client, new Origin("http", "localhost", connector.getLocalPort()), false)) HttpDestination destination = new HttpDestination(client, new Origin("http", "localhost", connector.getLocalPort()), false);
try
{ {
destination.start(); destination.start();
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool(); DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
@ -84,6 +87,10 @@ public class DuplexHttpDestinationTest extends AbstractHttpClientServerTest
} }
assertNotNull(connection); assertNotNull(connection);
} }
finally
{
destination.stop();
}
} }
@ParameterizedTest @ParameterizedTest
@ -92,7 +99,8 @@ public class DuplexHttpDestinationTest extends AbstractHttpClientServerTest
{ {
start(scenario, new EmptyServerHandler()); start(scenario, new EmptyServerHandler());
try (HttpDestination destination = new HttpDestination(client, new Origin("http", "localhost", connector.getLocalPort()), false)) HttpDestination destination = new HttpDestination(client, new Origin("http", "localhost", connector.getLocalPort()), false);
try
{ {
destination.start(); destination.start();
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool(); DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
@ -111,6 +119,10 @@ public class DuplexHttpDestinationTest extends AbstractHttpClientServerTest
assertSame(connection1, connection2); assertSame(connection1, connection2);
} }
} }
finally
{
destination.stop();
}
} }
@ParameterizedTest @ParameterizedTest
@ -121,12 +133,12 @@ public class DuplexHttpDestinationTest extends AbstractHttpClientServerTest
CountDownLatch idleLatch = new CountDownLatch(1); CountDownLatch idleLatch = new CountDownLatch(1);
CountDownLatch latch = new CountDownLatch(1); CountDownLatch latch = new CountDownLatch(1);
try (HttpDestination destination = new HttpDestination(client, new Origin("http", "localhost", connector.getLocalPort()), false) HttpDestination destination = new HttpDestination(client, new Origin("http", "localhost", connector.getLocalPort()), false)
{ {
@Override @Override
protected ConnectionPool newConnectionPool(HttpClient client) protected ConnectionPool newConnectionPool(HttpClient client)
{ {
return new DuplexConnectionPool(this, client.getMaxConnectionsPerDestination(), this) return new DuplexConnectionPool(this, client.getMaxConnectionsPerDestination())
{ {
@Override @Override
protected void onCreated(Connection connection) protected void onCreated(Connection connection)
@ -144,7 +156,8 @@ public class DuplexHttpDestinationTest extends AbstractHttpClientServerTest
} }
}; };
} }
}) };
try
{ {
destination.start(); destination.start();
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool(); DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
@ -175,6 +188,10 @@ public class DuplexHttpDestinationTest extends AbstractHttpClientServerTest
connection = peekIdleConnection(connectionPool, 5, TimeUnit.SECONDS); connection = peekIdleConnection(connectionPool, 5, TimeUnit.SECONDS);
assertNotNull(connection); assertNotNull(connection);
} }
finally
{
destination.stop();
}
} }
@ParameterizedTest @ParameterizedTest
@ -183,7 +200,8 @@ public class DuplexHttpDestinationTest extends AbstractHttpClientServerTest
{ {
start(scenario, new EmptyServerHandler()); start(scenario, new EmptyServerHandler());
try (HttpDestination destination = new HttpDestination(client, new Origin("http", "localhost", connector.getLocalPort()), false)) HttpDestination destination = new HttpDestination(client, new Origin("http", "localhost", connector.getLocalPort()), false);
try
{ {
destination.start(); destination.start();
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool(); DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
@ -209,6 +227,10 @@ public class DuplexHttpDestinationTest extends AbstractHttpClientServerTest
Connection connection2 = connectionPool.acquire(true); Connection connection2 = connectionPool.acquire(true);
assertSame(connection1, connection2, "After release"); assertSame(connection1, connection2, "After release");
} }
finally
{
destination.stop();
}
} }
@ParameterizedTest @ParameterizedTest
@ -220,7 +242,8 @@ public class DuplexHttpDestinationTest extends AbstractHttpClientServerTest
long idleTimeout = 1000; long idleTimeout = 1000;
startClient(scenario, httpClient -> httpClient.setIdleTimeout(idleTimeout)); startClient(scenario, httpClient -> httpClient.setIdleTimeout(idleTimeout));
try (HttpDestination destination = new HttpDestination(client, new Origin("http", "localhost", connector.getLocalPort()), false)) HttpDestination destination = new HttpDestination(client, new Origin("http", "localhost", connector.getLocalPort()), false);
try
{ {
destination.start(); destination.start();
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool(); DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
@ -241,6 +264,10 @@ public class DuplexHttpDestinationTest extends AbstractHttpClientServerTest
assertNull(connection1); assertNull(connection1);
} }
} }
finally
{
destination.stop();
}
} }
@ParameterizedTest @ParameterizedTest

View File

@ -17,9 +17,6 @@ import java.net.Socket;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.client.api.Result;
import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpScheme;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;

View File

@ -17,7 +17,7 @@ import java.security.cert.CertificateException;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.SSLHandshakeException;
import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP; import org.eclipse.jetty.client.transport.HttpClientTransportOverHTTP;
import org.eclipse.jetty.io.ClientConnector; import org.eclipse.jetty.io.ClientConnector;
import org.eclipse.jetty.io.Content; import org.eclipse.jetty.io.Content;
import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Handler;

View File

@ -15,11 +15,7 @@ package org.eclipse.jetty.client;
import java.net.URI; import java.net.URI;
import org.eclipse.jetty.client.api.Authentication; import org.eclipse.jetty.client.internal.HttpAuthenticationStore;
import org.eclipse.jetty.client.api.AuthenticationStore;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.util.BasicAuthentication;
import org.eclipse.jetty.client.util.DigestAuthentication;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;

View File

@ -24,11 +24,6 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.client.api.Result;
import org.eclipse.jetty.client.util.FutureResponseListener;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;

View File

@ -15,8 +15,6 @@ package org.eclipse.jetty.client;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.server.Response; import org.eclipse.jetty.server.Response;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ArgumentsSource; import org.junit.jupiter.params.provider.ArgumentsSource;

Some files were not shown because too many files have changed in this diff Show More