Issue #417 (HttpClient: review support for OPTIONS *)
Implemented support for OPTIONS * HTTP/1.1 requests.
This commit is contained in:
parent
8cefb38788
commit
e6c2c81bea
|
@ -117,12 +117,12 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler
|
|||
|
||||
Authentication authentication = null;
|
||||
Authentication.HeaderInfo headerInfo = null;
|
||||
URI uri = getAuthenticationURI(request);
|
||||
if (uri != null)
|
||||
URI authURI = getAuthenticationURI(request);
|
||||
if (authURI != null)
|
||||
{
|
||||
for (Authentication.HeaderInfo element : headerInfos)
|
||||
{
|
||||
authentication = client.getAuthenticationStore().findAuthentication(element.getType(), uri, element.getRealm());
|
||||
authentication = client.getAuthenticationStore().findAuthentication(element.getType(), authURI, element.getRealm());
|
||||
if (authentication != null)
|
||||
{
|
||||
headerInfo = element;
|
||||
|
@ -151,7 +151,21 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler
|
|||
|
||||
conversation.setAttribute(authenticationAttribute, true);
|
||||
|
||||
Request newRequest = client.copyRequest(request, request.getURI());
|
||||
URI requestURI = request.getURI();
|
||||
String path = null;
|
||||
if (requestURI == null)
|
||||
{
|
||||
String uri = request.getScheme() + "://" + request.getHost();
|
||||
int port = request.getPort();
|
||||
if (port > 0)
|
||||
uri += ":" + port;
|
||||
requestURI = URI.create(uri);
|
||||
path = request.getPath();
|
||||
}
|
||||
Request newRequest = client.copyRequest(request, requestURI);
|
||||
if (path != null)
|
||||
newRequest.path(path);
|
||||
|
||||
authnResult.apply(newRequest);
|
||||
// Copy existing, explicitly set, authorization headers.
|
||||
copyIfAbsent(request, newRequest, HttpHeader.AUTHORIZATION);
|
||||
|
|
|
@ -408,9 +408,9 @@ public class HttpClient extends ContainerLifeCycle
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a new request with the specified URI.
|
||||
* Creates a new request with the specified absolute URI in string format.
|
||||
*
|
||||
* @param uri the URI to request
|
||||
* @param uri the request absolute URI
|
||||
* @return the request just created
|
||||
*/
|
||||
public Request newRequest(String uri)
|
||||
|
@ -419,9 +419,9 @@ public class HttpClient extends ContainerLifeCycle
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a new request with the specified URI.
|
||||
* Creates a new request with the specified absolute URI.
|
||||
*
|
||||
* @param uri the URI to request
|
||||
* @param uri the request absolute URI
|
||||
* @return the request just created
|
||||
*/
|
||||
public Request newRequest(URI uri)
|
||||
|
|
|
@ -102,9 +102,12 @@ public abstract class HttpConnection implements Connection
|
|||
path = "/";
|
||||
request.path(path);
|
||||
}
|
||||
if (proxy != null && !HttpMethod.CONNECT.is(method))
|
||||
|
||||
URI uri = request.getURI();
|
||||
|
||||
if (proxy != null && !HttpMethod.CONNECT.is(method) && uri != null)
|
||||
{
|
||||
path = request.getURI().toString();
|
||||
path = uri.toString();
|
||||
request.path(path);
|
||||
}
|
||||
|
||||
|
@ -144,7 +147,6 @@ public abstract class HttpConnection implements Connection
|
|||
CookieStore cookieStore = getHttpClient().getCookieStore();
|
||||
if (cookieStore != null)
|
||||
{
|
||||
URI uri = request.getURI();
|
||||
StringBuilder cookies = null;
|
||||
if (uri != null)
|
||||
cookies = convertCookies(cookieStore.get(uri), null);
|
||||
|
@ -155,7 +157,7 @@ public abstract class HttpConnection implements Connection
|
|||
|
||||
// Authentication
|
||||
applyAuthentication(request, proxy != null ? proxy.getURI() : null);
|
||||
applyAuthentication(request, request.getURI());
|
||||
applyAuthentication(request, uri);
|
||||
}
|
||||
|
||||
private StringBuilder convertCookies(List<HttpCookie> cookies, StringBuilder builder)
|
||||
|
|
|
@ -184,7 +184,9 @@ public abstract class HttpReceiver
|
|||
case SET_COOKIE:
|
||||
case SET_COOKIE2:
|
||||
{
|
||||
storeCookie(exchange.getRequest().getURI(), field);
|
||||
URI uri = exchange.getRequest().getURI();
|
||||
if (uri != null)
|
||||
storeCookie(uri, field);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -229,7 +229,18 @@ public class HttpRedirector
|
|||
private Request redirect(Request request, Response response, Response.CompleteListener listener, URI newURI)
|
||||
{
|
||||
if (!newURI.isAbsolute())
|
||||
newURI = request.getURI().resolve(newURI);
|
||||
{
|
||||
URI requestURI = request.getURI();
|
||||
if (requestURI == null)
|
||||
{
|
||||
String uri = request.getScheme() + "://" + request.getHost();
|
||||
int port = request.getPort();
|
||||
if (port > 0)
|
||||
uri += ":" + port;
|
||||
requestURI = URI.create(uri);
|
||||
}
|
||||
newURI = requestURI.resolve(newURI);
|
||||
}
|
||||
|
||||
int status = response.getStatus();
|
||||
switch (status)
|
||||
|
|
|
@ -92,6 +92,7 @@ public class HttpRequest implements Request
|
|||
path = uri.getRawPath();
|
||||
query = uri.getRawQuery();
|
||||
extractParams(query);
|
||||
|
||||
followRedirects(client.isFollowRedirects());
|
||||
idleTimeout = client.getIdleTimeout();
|
||||
HttpField acceptEncodingField = client.getAcceptEncodingField();
|
||||
|
@ -797,12 +798,15 @@ public class HttpRequest implements Request
|
|||
{
|
||||
try
|
||||
{
|
||||
// Handle specially the "OPTIONS *" case, since it is possible to create a URI from "*" (!).
|
||||
if ("*".equals(uri))
|
||||
return null;
|
||||
return new URI(uri);
|
||||
}
|
||||
catch (URISyntaxException x)
|
||||
{
|
||||
// The "path" of a HTTP request may not be a URI,
|
||||
// for example for CONNECT 127.0.0.1:8080 or OPTIONS *.
|
||||
// for example for CONNECT 127.0.0.1:8080.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -208,7 +208,8 @@ public class DigestAuthentication extends AbstractAuthentication
|
|||
String A1 = user + ":" + realm + ":" + password;
|
||||
String hashA1 = toHexString(digester.digest(A1.getBytes(StandardCharsets.ISO_8859_1)));
|
||||
|
||||
String A2 = request.getMethod() + ":" + request.getURI();
|
||||
URI uri = request.getURI();
|
||||
String A2 = request.getMethod() + ":" + uri;
|
||||
if ("auth-int".equals(qop))
|
||||
A2 += ":" + toHexString(digester.digest(content));
|
||||
String hashA2 = toHexString(digester.digest(A2.getBytes(StandardCharsets.ISO_8859_1)));
|
||||
|
@ -237,7 +238,7 @@ public class DigestAuthentication extends AbstractAuthentication
|
|||
if (opaque != null)
|
||||
value.append(", opaque=\"").append(opaque).append("\"");
|
||||
value.append(", algorithm=\"").append(algorithm).append("\"");
|
||||
value.append(", uri=\"").append(request.getURI()).append("\"");
|
||||
value.append(", uri=\"").append(uri).append("\"");
|
||||
if (qop != null)
|
||||
{
|
||||
value.append(", qop=\"").append(qop).append("\"");
|
||||
|
|
|
@ -29,6 +29,7 @@ import javax.servlet.http.HttpServletResponse;
|
|||
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.util.Fields;
|
||||
|
@ -472,4 +473,35 @@ public class HttpClientURITest extends AbstractHttpClientServerTest
|
|||
|
||||
Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAsteriskFormTarget() throws Exception
|
||||
{
|
||||
start(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
Assert.assertEquals("*", target);
|
||||
Assert.assertEquals("*", request.getPathInfo());
|
||||
}
|
||||
});
|
||||
|
||||
Request request = client.newRequest("localhost", connector.getLocalPort())
|
||||
.method(HttpMethod.OPTIONS)
|
||||
.scheme(scheme)
|
||||
.path("*")
|
||||
.timeout(5, TimeUnit.SECONDS);
|
||||
|
||||
Assert.assertEquals("*", request.getPath());
|
||||
Assert.assertNull(request.getQuery());
|
||||
Fields params = request.getParams();
|
||||
Assert.assertEquals(0, params.getSize());
|
||||
Assert.assertNull(request.getURI());
|
||||
|
||||
ContentResponse response = request.send();
|
||||
|
||||
Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,9 +64,9 @@ public class HttpSenderOverFCGI extends HttpSender
|
|||
|
||||
// FastCGI headers based on the URI
|
||||
URI uri = request.getURI();
|
||||
String path = uri.getRawPath();
|
||||
String path = uri == null ? request.getPath() : uri.getRawPath();
|
||||
fcgiHeaders.put(FCGI.Headers.DOCUMENT_URI, path);
|
||||
String query = uri.getRawQuery();
|
||||
String query = uri == null ? null : uri.getRawQuery();
|
||||
fcgiHeaders.put(FCGI.Headers.QUERY_STRING, query == null ? "" : query);
|
||||
|
||||
// FastCGI headers based on HTTP headers
|
||||
|
|
|
@ -188,8 +188,8 @@ public class FastCGIProxyServlet extends AsyncProxyServlet.Transparent
|
|||
fastCGIHeaders.put(FCGI.Headers.HTTPS, "on");
|
||||
|
||||
URI proxyRequestURI = proxyRequest.getURI();
|
||||
String rawPath = proxyRequestURI.getRawPath();
|
||||
String rawQuery = proxyRequestURI.getRawQuery();
|
||||
String rawPath = proxyRequestURI == null ? proxyRequest.getPath() : proxyRequestURI.getRawPath();
|
||||
String rawQuery = proxyRequestURI == null ? null : proxyRequestURI.getRawQuery();
|
||||
|
||||
String requestURI = (String)proxyRequest.getAttributes().get(REQUEST_URI_ATTRIBUTE);
|
||||
if (requestURI == null)
|
||||
|
|
|
@ -192,22 +192,27 @@ public abstract class AbstractTest
|
|||
return http2Client;
|
||||
}
|
||||
|
||||
protected String newURI()
|
||||
protected String getScheme()
|
||||
{
|
||||
switch (transport)
|
||||
{
|
||||
case HTTP:
|
||||
case H2C:
|
||||
case FCGI:
|
||||
return "http://localhost:" + connector.getLocalPort();
|
||||
return "http";
|
||||
case HTTPS:
|
||||
case H2:
|
||||
return "https://localhost:" + connector.getLocalPort();
|
||||
return "https";
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
protected String newURI()
|
||||
{
|
||||
return getScheme() + "://localhost:" + connector.getLocalPort();
|
||||
}
|
||||
|
||||
@After
|
||||
public void stop() throws Exception
|
||||
{
|
||||
|
|
|
@ -316,6 +316,60 @@ public class HttpClientTest extends AbstractTest
|
|||
.send();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOPTIONS() throws Exception
|
||||
{
|
||||
start(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
Assert.assertTrue(HttpMethod.OPTIONS.is(request.getMethod()));
|
||||
Assert.assertEquals("*", target);
|
||||
Assert.assertEquals("*", request.getPathInfo());
|
||||
}
|
||||
});
|
||||
|
||||
ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
|
||||
.scheme(getScheme())
|
||||
.method(HttpMethod.OPTIONS)
|
||||
.path("*")
|
||||
.timeout(5, TimeUnit.SECONDS)
|
||||
.send();
|
||||
|
||||
Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOPTIONSWithRelativeRedirect() throws Exception
|
||||
{
|
||||
start(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
if ("*".equals(target))
|
||||
{
|
||||
// Be nasty and send a relative redirect.
|
||||
// Code 303 will change the method to GET.
|
||||
response.setStatus(HttpStatus.SEE_OTHER_303);
|
||||
response.setHeader("Location", "/");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
|
||||
.scheme(getScheme())
|
||||
.method(HttpMethod.OPTIONS)
|
||||
.path("*")
|
||||
.timeout(5, TimeUnit.SECONDS)
|
||||
.send();
|
||||
|
||||
Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
}
|
||||
|
||||
private void sleep(long time) throws IOException
|
||||
{
|
||||
try
|
||||
|
|
Loading…
Reference in New Issue