Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,17 @@ public URI getURI()
return URI.create(getOrigin().asString());
}

/**
* <p>Returns whether tunneling is required to reach the given server {@link Origin}.</p>
* <p>Returns {@link true} when the server is secure, or when the server does not speak
* the same protocol as this proxy.
* An example of the latter case is sending an HTTP/2 clear-text request to the server
* via a proxy that only speaks HTTP/1.1, or an HTTP/1.1 request to a server that
* only speaks HTTP/2.</p>
*
* @param serverOrigin the server {@link Origin}
* @return true if tunneling is required to reach the server
*/
public boolean requiresTunnel(Origin serverOrigin)
{
if (HttpScheme.isSecure(serverOrigin.getScheme()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@

import java.net.URI;

import org.eclipse.jetty.client.transport.HttpDestination;
import org.eclipse.jetty.client.internal.TunnelRequest;
import org.eclipse.jetty.client.transport.HttpRequest;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpStatus;

/**
* <p>A protocol handler that handles the 401 response code
* <p>A protocol handler that handles the {@code 407} response code
* in association with the {@code Proxy-Authenticate} header.</p>
*
* @see WWWAuthenticationProtocolHandler
Expand Down Expand Up @@ -49,7 +50,14 @@ public String getName()
@Override
public boolean accept(Request request, Response response)
{
return response.getStatus() == HttpStatus.PROXY_AUTHENTICATION_REQUIRED_407;
return response.getStatus() == HttpStatus.PROXY_AUTHENTICATION_REQUIRED_407 && isSentToProxy(request);
}

private boolean isSentToProxy(Request request)
{
if (request instanceof TunnelRequest)
return true;
return ((HttpRequest)request).getHttpProxy() != null;
}

@Override
Expand All @@ -67,8 +75,7 @@ protected HttpHeader getAuthorizationHeader()
@Override
protected URI getAuthenticationURI(Request request)
{
HttpDestination destination = (HttpDestination)getHttpClient().resolveDestination(request);
ProxyConfiguration.Proxy proxy = destination.getProxy();
HttpProxy proxy = ((HttpRequest)request).getHttpProxy();
return proxy != null ? proxy.getURI() : request.getURI();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import java.net.URI;

import org.eclipse.jetty.client.internal.TunnelRequest;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpStatus;

Expand Down Expand Up @@ -48,7 +49,7 @@ public String getName()
@Override
public boolean accept(Request request, Response response)
{
return response.getStatus() == HttpStatus.UNAUTHORIZED_401;
return response.getStatus() == HttpStatus.UNAUTHORIZED_401 && !(request instanceof TunnelRequest);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,20 +160,24 @@ protected void normalizeRequest(HttpRequest request)
if (proxy instanceof HttpProxy httpProxy)
{
boolean tunnelled = httpProxy.requiresTunnel(destination.getOrigin());

// RFC 9112, section 3.2.2: when making a request to a proxy other than CONNECT,
// the client must send the target URI in absolute-form as the request target.
// In practice, this is only valid for HTTP/1.1 requests that are not tunnelled.
if (http1 && !tunnelled)
if (!tunnelled)
{
URI uri = request.getURI();
if (uri != null)
request.path(uri.toString());
// RFC 9112, section 3.2.2: when making a request to a proxy other than CONNECT,
// the client must send the target URI in absolute-form as the request target.
// In practice, this is only valid for HTTP/1.1 requests that are not tunnelled.
if (http1)
{
URI uri = request.getURI();
if (uri != null)
request.path(uri.toString());
}

request.httpProxy(httpProxy);

// Send the proxy credentials only when not tunnelled,
// otherwise proxy credentials are leaked to the server.
applyProxyAuthentication = true;
}

// Do not send proxy authentication headers when tunnelled,
// otherwise proxy credentials arrive to the server.
applyProxyAuthentication = !tunnelled;
}

// If we are HTTP 1.1, add the Host header.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.client.Destination;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.HttpProxy;
import org.eclipse.jetty.client.Origin;
import org.eclipse.jetty.client.PathRequestContent;
import org.eclipse.jetty.client.Request;
Expand Down Expand Up @@ -96,6 +97,7 @@ public class HttpRequest implements Request
private Supplier<HttpFields> trailers;
private Object tag;
private boolean normalized;
private HttpProxy httpProxy;

public HttpRequest(HttpClient client, HttpConversation conversation, URI uri)
{
Expand Down Expand Up @@ -824,6 +826,16 @@ boolean normalized()
return result;
}

public HttpProxy getHttpProxy()
{
return httpProxy;
}

void httpProxy(HttpProxy httpProxy)
{
this.httpProxy = httpProxy;
}

private String buildQuery()
{
StringBuilder result = new StringBuilder();
Expand Down
Loading