440106 - Improve ProtocolHandler APIs.
Introduced ProtocolHandlers, the container for ProtocolHandler instances, which now have also a name.
This commit is contained in:
parent
6263972d1e
commit
48dd4d8b56
|
@ -27,19 +27,27 @@ import org.eclipse.jetty.client.util.BufferingResponseListener;
|
||||||
import org.eclipse.jetty.http.HttpHeader;
|
import org.eclipse.jetty.http.HttpHeader;
|
||||||
import org.eclipse.jetty.http.HttpHeaderValue;
|
import org.eclipse.jetty.http.HttpHeaderValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>A protocol handler that handles the 100 response code.</p>
|
||||||
|
*/
|
||||||
public class ContinueProtocolHandler implements ProtocolHandler
|
public class ContinueProtocolHandler implements ProtocolHandler
|
||||||
{
|
{
|
||||||
|
public static final String NAME = "continue";
|
||||||
private static final String ATTRIBUTE = ContinueProtocolHandler.class.getName() + ".100continue";
|
private static final String ATTRIBUTE = ContinueProtocolHandler.class.getName() + ".100continue";
|
||||||
|
|
||||||
private final HttpClient client;
|
|
||||||
private final ResponseNotifier notifier;
|
private final ResponseNotifier notifier;
|
||||||
|
|
||||||
public ContinueProtocolHandler(HttpClient client)
|
public ContinueProtocolHandler()
|
||||||
{
|
{
|
||||||
this.client = client;
|
|
||||||
this.notifier = new ResponseNotifier();
|
this.notifier = new ResponseNotifier();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return NAME;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean accept(Request request, Response response)
|
public boolean accept(Request request, Response response)
|
||||||
{
|
{
|
||||||
|
|
|
@ -109,7 +109,7 @@ public class HttpClient extends ContainerLifeCycle
|
||||||
private static final Logger LOG = Log.getLogger(HttpClient.class);
|
private static final Logger LOG = Log.getLogger(HttpClient.class);
|
||||||
|
|
||||||
private final ConcurrentMap<Origin, HttpDestination> destinations = new ConcurrentHashMap<>();
|
private final ConcurrentMap<Origin, HttpDestination> destinations = new ConcurrentHashMap<>();
|
||||||
private final List<ProtocolHandler> handlers = new ArrayList<>();
|
private final ProtocolHandlers handlers = new ProtocolHandlers();
|
||||||
private final List<Request.Listener> requestListeners = new ArrayList<>();
|
private final List<Request.Listener> requestListeners = new ArrayList<>();
|
||||||
private final AuthenticationStore authenticationStore = new HttpAuthenticationStore();
|
private final AuthenticationStore authenticationStore = new HttpAuthenticationStore();
|
||||||
private final Set<ContentDecoder.Factory> decoderFactories = new ContentDecoderFactorySet();
|
private final Set<ContentDecoder.Factory> decoderFactories = new ContentDecoderFactorySet();
|
||||||
|
@ -210,10 +210,10 @@ public class HttpClient extends ContainerLifeCycle
|
||||||
|
|
||||||
resolver = new SocketAddressResolver(executor, scheduler, getAddressResolutionTimeout());
|
resolver = new SocketAddressResolver(executor, scheduler, getAddressResolutionTimeout());
|
||||||
|
|
||||||
handlers.add(new ContinueProtocolHandler(this));
|
handlers.put(new ContinueProtocolHandler());
|
||||||
handlers.add(new RedirectProtocolHandler(this));
|
handlers.put(new RedirectProtocolHandler(this));
|
||||||
handlers.add(new WWWAuthenticationProtocolHandler(this));
|
handlers.put(new WWWAuthenticationProtocolHandler(this));
|
||||||
handlers.add(new ProxyAuthenticationProtocolHandler(this));
|
handlers.put(new ProxyAuthenticationProtocolHandler(this));
|
||||||
|
|
||||||
decoderFactories.add(new GZIPContentDecoder.Factory());
|
decoderFactories.add(new GZIPContentDecoder.Factory());
|
||||||
|
|
||||||
|
@ -547,22 +547,14 @@ public class HttpClient extends ContainerLifeCycle
|
||||||
return new HttpConversation();
|
return new HttpConversation();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<ProtocolHandler> getProtocolHandlers()
|
public ProtocolHandlers getProtocolHandlers()
|
||||||
{
|
{
|
||||||
return handlers;
|
return handlers;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ProtocolHandler findProtocolHandler(Request request, Response response)
|
protected ProtocolHandler findProtocolHandler(Request request, Response response)
|
||||||
{
|
{
|
||||||
// Optimized to avoid allocations of iterator instances
|
return handlers.find(request, response);
|
||||||
List<ProtocolHandler> protocolHandlers = getProtocolHandlers();
|
|
||||||
for (int i = 0; i < protocolHandlers.size(); ++i)
|
|
||||||
{
|
|
||||||
ProtocolHandler handler = protocolHandlers.get(i);
|
|
||||||
if (handler.accept(request, response))
|
|
||||||
return handler;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -21,9 +21,38 @@ package org.eclipse.jetty.client;
|
||||||
import org.eclipse.jetty.client.api.Request;
|
import org.eclipse.jetty.client.api.Request;
|
||||||
import org.eclipse.jetty.client.api.Response;
|
import org.eclipse.jetty.client.api.Response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>A protocol handler performs HTTP protocol operations on
|
||||||
|
* behalf of the application, typically like a browser would.</p>
|
||||||
|
* <p>A typical example is handling HTTP redirects. {@link HttpClient}
|
||||||
|
* could just return the redirect response to the application,
|
||||||
|
* but the application would have to implement the redirect
|
||||||
|
* functionality (while browsers do this automatically).</p>
|
||||||
|
*/
|
||||||
public interface ProtocolHandler
|
public interface ProtocolHandler
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @return a unique name among protocol handlers
|
||||||
|
*/
|
||||||
|
public String getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Inspects the given {@code request} and {@code response}
|
||||||
|
* to detect whether this protocol handler should handle them.</p>
|
||||||
|
* <p>For example, a redirect protocol handler can inspect the
|
||||||
|
* response code and return true if it is a redirect response code.</p>
|
||||||
|
* <p>This method is being called just after the response line has
|
||||||
|
* been parsed, and before the response headers are available.</p>
|
||||||
|
*
|
||||||
|
* @param request the request to accept
|
||||||
|
* @param response the response to accept
|
||||||
|
* @return true if this protocol handler can handle the given request and response
|
||||||
|
*/
|
||||||
public boolean accept(Request request, Response response);
|
public boolean accept(Request request, Response response);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return a response listener that will handle the request and response
|
||||||
|
* on behalf of the application.
|
||||||
|
*/
|
||||||
public Response.Listener getResponseListener();
|
public Response.Listener getResponseListener();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// All rights reserved. This program and the accompanying materials
|
||||||
|
// are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
// and Apache License v2.0 which accompanies this distribution.
|
||||||
|
//
|
||||||
|
// The Eclipse Public License is available at
|
||||||
|
// http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
//
|
||||||
|
// The Apache License v2.0 is available at
|
||||||
|
// http://www.opensource.org/licenses/apache2.0.php
|
||||||
|
//
|
||||||
|
// You may elect to redistribute this code under either of these licenses.
|
||||||
|
// ========================================================================
|
||||||
|
//
|
||||||
|
|
||||||
|
package org.eclipse.jetty.client;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.client.api.Request;
|
||||||
|
import org.eclipse.jetty.client.api.Response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>A container for {@link ProtocolHandler}s accessible from {@link HttpClient#getProtocolHandlers()}.</p>
|
||||||
|
*/
|
||||||
|
public class ProtocolHandlers
|
||||||
|
{
|
||||||
|
private final Map<String, ProtocolHandler> handlers = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
protected ProtocolHandlers()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Stores the given {@code protocolHandler} in this container.</p>
|
||||||
|
* <p>If a protocol handler with the same name exists, it is
|
||||||
|
* replaced by the given one, and the existing returned.</p>
|
||||||
|
*
|
||||||
|
* @param protocolHandler the protocol handler to store
|
||||||
|
* @return the existing protocol handler with the same name,
|
||||||
|
* or null if no protocol handler with that name was already stored
|
||||||
|
* @see #remove(String)
|
||||||
|
*/
|
||||||
|
public ProtocolHandler put(ProtocolHandler protocolHandler)
|
||||||
|
{
|
||||||
|
return handlers.put(protocolHandler.getName(), protocolHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the protocol handler with the given name.</p>
|
||||||
|
*
|
||||||
|
* @param name the name of the protocol handler to remove
|
||||||
|
* @return the removed protocol handler, or null if no
|
||||||
|
* protocol handler with that name was already stored
|
||||||
|
* @see #put(ProtocolHandler)
|
||||||
|
* @see #clear()
|
||||||
|
*/
|
||||||
|
public ProtocolHandler remove(String name)
|
||||||
|
{
|
||||||
|
return handlers.remove(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes all protocol handlers from this container.</p>
|
||||||
|
*/
|
||||||
|
public void clear()
|
||||||
|
{
|
||||||
|
handlers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Finds the first protocol handler that
|
||||||
|
* {@link ProtocolHandler#accept(Request, Response) accepts}
|
||||||
|
* the given request and response.</p>
|
||||||
|
*
|
||||||
|
* @param request the request to accept
|
||||||
|
* @param response the response to accept
|
||||||
|
* @return the protocol handler that accepted the request and response,
|
||||||
|
* or null if none of the protocol handlers accepted the request and response
|
||||||
|
*/
|
||||||
|
public ProtocolHandler find(Request request, Response response)
|
||||||
|
{
|
||||||
|
for (ProtocolHandler handler : handlers.values())
|
||||||
|
{
|
||||||
|
if (handler.accept(request, response))
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,8 +25,16 @@ 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>A protocol handler that handles the 401 response code
|
||||||
|
* in association with the {@code Proxy-Authenticate} header.</p>
|
||||||
|
*
|
||||||
|
* @see WWWAuthenticationProtocolHandler
|
||||||
|
*/
|
||||||
public class ProxyAuthenticationProtocolHandler extends AuthenticationProtocolHandler
|
public class ProxyAuthenticationProtocolHandler extends AuthenticationProtocolHandler
|
||||||
{
|
{
|
||||||
|
public static final String NAME = "proxy-authenticate";
|
||||||
|
|
||||||
public ProxyAuthenticationProtocolHandler(HttpClient client)
|
public ProxyAuthenticationProtocolHandler(HttpClient client)
|
||||||
{
|
{
|
||||||
this(client, DEFAULT_MAX_CONTENT_LENGTH);
|
this(client, DEFAULT_MAX_CONTENT_LENGTH);
|
||||||
|
@ -37,6 +45,12 @@ public class ProxyAuthenticationProtocolHandler extends AuthenticationProtocolHa
|
||||||
super(client, maxContentLength);
|
super(client, maxContentLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return NAME;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean accept(Request request, Response response)
|
public boolean accept(Request request, Response response)
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,8 +22,13 @@ import org.eclipse.jetty.client.api.Request;
|
||||||
import org.eclipse.jetty.client.api.Response;
|
import org.eclipse.jetty.client.api.Response;
|
||||||
import org.eclipse.jetty.client.api.Result;
|
import org.eclipse.jetty.client.api.Result;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>A protocol handler that handles redirect status codes 301, 302, 303, 307 and 308.</p>
|
||||||
|
*/
|
||||||
public class RedirectProtocolHandler extends Response.Listener.Adapter implements ProtocolHandler
|
public class RedirectProtocolHandler extends Response.Listener.Adapter implements ProtocolHandler
|
||||||
{
|
{
|
||||||
|
public static final String NAME = "redirect";
|
||||||
|
|
||||||
private final HttpRedirector redirector;
|
private final HttpRedirector redirector;
|
||||||
|
|
||||||
public RedirectProtocolHandler(HttpClient client)
|
public RedirectProtocolHandler(HttpClient client)
|
||||||
|
@ -31,6 +36,12 @@ public class RedirectProtocolHandler extends Response.Listener.Adapter implement
|
||||||
redirector = new HttpRedirector(client);
|
redirector = new HttpRedirector(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return NAME;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean accept(Request request, Response response)
|
public boolean accept(Request request, Response response)
|
||||||
{
|
{
|
||||||
|
|
|
@ -25,8 +25,16 @@ 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>A protocol handler that handles the 401 response code
|
||||||
|
* in association with the {@code WWW-Authenticate} header.</p>
|
||||||
|
*
|
||||||
|
* @see ProxyAuthenticationProtocolHandler
|
||||||
|
*/
|
||||||
public class WWWAuthenticationProtocolHandler extends AuthenticationProtocolHandler
|
public class WWWAuthenticationProtocolHandler extends AuthenticationProtocolHandler
|
||||||
{
|
{
|
||||||
|
public static final String NAME = "www-authenticate";
|
||||||
|
|
||||||
public WWWAuthenticationProtocolHandler(HttpClient client)
|
public WWWAuthenticationProtocolHandler(HttpClient client)
|
||||||
{
|
{
|
||||||
this(client, DEFAULT_MAX_CONTENT_LENGTH);
|
this(client, DEFAULT_MAX_CONTENT_LENGTH);
|
||||||
|
@ -37,6 +45,12 @@ public class WWWAuthenticationProtocolHandler extends AuthenticationProtocolHand
|
||||||
super(client, maxContentLength);
|
super(client, maxContentLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return NAME;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean accept(Request request, Response response)
|
public boolean accept(Request request, Response response)
|
||||||
{
|
{
|
||||||
|
|
|
@ -27,11 +27,8 @@ import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.ServletInputStream;
|
import javax.servlet.ServletInputStream;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
@ -405,7 +402,7 @@ public class HttpClientContinueTest extends AbstractHttpClientServerTest
|
||||||
});
|
});
|
||||||
|
|
||||||
client.getProtocolHandlers().clear();
|
client.getProtocolHandlers().clear();
|
||||||
client.getProtocolHandlers().add(new ContinueProtocolHandler(client)
|
client.getProtocolHandlers().put(new ContinueProtocolHandler()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public Response.Listener getResponseListener()
|
public Response.Listener getResponseListener()
|
||||||
|
@ -609,14 +606,7 @@ public class HttpClientContinueTest extends AbstractHttpClientServerTest
|
||||||
|
|
||||||
final DeferredContentProvider content = new DeferredContentProvider(ByteBuffer.wrap(chunk1));
|
final DeferredContentProvider content = new DeferredContentProvider(ByteBuffer.wrap(chunk1));
|
||||||
|
|
||||||
List<ProtocolHandler> protocolHandlers = client.getProtocolHandlers();
|
client.getProtocolHandlers().put(new ContinueProtocolHandler()
|
||||||
for (Iterator<ProtocolHandler> iterator = protocolHandlers.iterator(); iterator.hasNext();)
|
|
||||||
{
|
|
||||||
ProtocolHandler protocolHandler = iterator.next();
|
|
||||||
if (protocolHandler instanceof ContinueProtocolHandler)
|
|
||||||
iterator.remove();
|
|
||||||
}
|
|
||||||
protocolHandlers.add(new ContinueProtocolHandler(client)
|
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public Response.Listener getResponseListener()
|
public Response.Listener getResponseListener()
|
||||||
|
|
|
@ -25,7 +25,6 @@ import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
@ -528,7 +527,7 @@ public class HttpRequestAbortTest extends AbstractHttpClientServerTest
|
||||||
final AtomicBoolean aborted = new AtomicBoolean();
|
final AtomicBoolean aborted = new AtomicBoolean();
|
||||||
final CountDownLatch latch = new CountDownLatch(1);
|
final CountDownLatch latch = new CountDownLatch(1);
|
||||||
client.getProtocolHandlers().clear();
|
client.getProtocolHandlers().clear();
|
||||||
client.getProtocolHandlers().add(new RedirectProtocolHandler(client)
|
client.getProtocolHandlers().put(new RedirectProtocolHandler(client)
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public void onComplete(Result result)
|
public void onComplete(Result result)
|
||||||
|
|
Loading…
Reference in New Issue