Merged branch 'jetty-9.3.x' into 'master'.
This commit is contained in:
commit
68a465d7a3
|
@ -35,6 +35,7 @@ import org.eclipse.jetty.http.HttpField;
|
|||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpHeaderValue;
|
||||
import org.eclipse.jetty.http.HttpScheme;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
@ -103,7 +104,7 @@ public abstract class HttpConnection implements Connection
|
|||
|
||||
URI uri = request.getURI();
|
||||
|
||||
if (proxy != null && !HttpClient.isSchemeSecure(request.getScheme()) && uri != null)
|
||||
if (proxy instanceof HttpProxy && !HttpClient.isSchemeSecure(request.getScheme()) && uri != null)
|
||||
{
|
||||
path = uri.toString();
|
||||
request.path(path);
|
||||
|
|
|
@ -26,8 +26,6 @@ import java.nio.charset.StandardCharsets;
|
|||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.client.api.Response;
|
||||
import org.eclipse.jetty.client.api.Result;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
|
@ -69,17 +67,16 @@ public class Socks4ProxyTest
|
|||
byte ip4 = 13;
|
||||
String serverHost = ip1 + "." + ip2 + "." + ip3 + "." + ip4;
|
||||
int serverPort = proxyPort + 1; // Any port will do
|
||||
String method = "GET";
|
||||
String path = "/path";
|
||||
client.newRequest(serverHost, serverPort)
|
||||
.path("/path")
|
||||
.method(method)
|
||||
.path(path)
|
||||
.timeout(5, TimeUnit.SECONDS)
|
||||
.send(new Response.CompleteListener()
|
||||
.send(result ->
|
||||
{
|
||||
@Override
|
||||
public void onComplete(Result result)
|
||||
{
|
||||
if (result.isSucceeded())
|
||||
latch.countDown();
|
||||
}
|
||||
if (result.isSucceeded())
|
||||
latch.countDown();
|
||||
});
|
||||
|
||||
SocketChannel channel = server.accept();
|
||||
|
@ -100,11 +97,11 @@ public class Socks4ProxyTest
|
|||
// Socks4 response.
|
||||
channel.write(ByteBuffer.wrap(new byte[]{0, 0x5A, 0, 0, 0, 0, 0, 0}));
|
||||
|
||||
buffer = ByteBuffer.allocate(3);
|
||||
buffer = ByteBuffer.allocate(method.length() + 1 + path.length());
|
||||
read = channel.read(buffer);
|
||||
Assert.assertEquals(3, read);
|
||||
Assert.assertEquals(buffer.capacity(), read);
|
||||
buffer.flip();
|
||||
Assert.assertEquals("GET", StandardCharsets.UTF_8.decode(buffer).toString());
|
||||
Assert.assertEquals(method + " " + path, StandardCharsets.UTF_8.decode(buffer).toString());
|
||||
|
||||
// Response
|
||||
String response = "" +
|
||||
|
@ -129,19 +126,17 @@ public class Socks4ProxyTest
|
|||
|
||||
String serverHost = "127.0.0.13"; // Test expects an IP address.
|
||||
int serverPort = proxyPort + 1; // Any port will do
|
||||
String method = "GET";
|
||||
client.newRequest(serverHost, serverPort)
|
||||
.method(method)
|
||||
.path("/path")
|
||||
.timeout(5, TimeUnit.SECONDS)
|
||||
.send(new Response.CompleteListener()
|
||||
.send(result ->
|
||||
{
|
||||
@Override
|
||||
public void onComplete(Result result)
|
||||
{
|
||||
if (result.isSucceeded())
|
||||
latch.countDown();
|
||||
else
|
||||
result.getFailure().printStackTrace();
|
||||
}
|
||||
if (result.isSucceeded())
|
||||
latch.countDown();
|
||||
else
|
||||
result.getFailure().printStackTrace();
|
||||
});
|
||||
|
||||
SocketChannel channel = server.accept();
|
||||
|
@ -161,11 +156,11 @@ public class Socks4ProxyTest
|
|||
|
||||
channel.write(ByteBuffer.wrap(chunk2));
|
||||
|
||||
buffer = ByteBuffer.allocate(3);
|
||||
buffer = ByteBuffer.allocate(method.length());
|
||||
read = channel.read(buffer);
|
||||
Assert.assertEquals(3, read);
|
||||
Assert.assertEquals(buffer.capacity(), read);
|
||||
buffer.flip();
|
||||
Assert.assertEquals("GET", StandardCharsets.UTF_8.decode(buffer).toString());
|
||||
Assert.assertEquals(method, StandardCharsets.UTF_8.decode(buffer).toString());
|
||||
|
||||
// Response
|
||||
String response = "" +
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
package org.eclipse.jetty.http2.client.http;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.eclipse.jetty.client.HttpContent;
|
||||
import org.eclipse.jetty.client.HttpExchange;
|
||||
import org.eclipse.jetty.client.HttpSender;
|
||||
|
@ -47,8 +49,9 @@ public class HttpSenderOverHTTP2 extends HttpSender
|
|||
@Override
|
||||
protected void sendHeaders(HttpExchange exchange, final HttpContent content, final Callback callback)
|
||||
{
|
||||
final Request request = exchange.getRequest();
|
||||
HttpURI uri = new HttpURI(request.getScheme(), request.getHost(), request.getPort(), request.getPath(), null, request.getQuery(), null);
|
||||
Request request = exchange.getRequest();
|
||||
String path = relativize(request.getPath());
|
||||
HttpURI uri = new HttpURI(request.getScheme(), request.getHost(), request.getPort(), path, null, request.getQuery(), null);
|
||||
MetaData.Request metaData = new MetaData.Request(request.getMethod(), uri, HttpVersion.HTTP_2, request.getHeaders());
|
||||
HeadersFrame headersFrame = new HeadersFrame(metaData, null, !content.hasContent());
|
||||
HttpChannelOverHTTP2 channel = getHttpChannel();
|
||||
|
@ -84,6 +87,24 @@ public class HttpSenderOverHTTP2 extends HttpSender
|
|||
channel.getSession().newStream(headersFrame, promise, channel.getStreamListener());
|
||||
}
|
||||
|
||||
private String relativize(String path)
|
||||
{
|
||||
try
|
||||
{
|
||||
String result = path;
|
||||
URI uri = URI.create(result);
|
||||
if (uri.isAbsolute())
|
||||
result = uri.getPath();
|
||||
return result.isEmpty() ? "/" : result;
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Could not relativize " + path);
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendContent(HttpExchange exchange, HttpContent content, Callback callback)
|
||||
{
|
||||
|
|
|
@ -33,6 +33,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.HttpProxy;
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
|
@ -260,6 +261,58 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest
|
|||
Assert.assertEquals(lastStream.get(), stream.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAbsoluteFormTarget() throws Exception
|
||||
{
|
||||
String path = "/path";
|
||||
String query = "a=b";
|
||||
start(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
Assert.assertEquals(path, request.getRequestURI());
|
||||
Assert.assertEquals(query, request.getQueryString());
|
||||
}
|
||||
});
|
||||
|
||||
ContentResponse response = client.newRequest("localhost", connector.getLocalPort())
|
||||
.path("http://localhost:" + connector.getLocalPort() + path + "?" + query)
|
||||
.timeout(5, TimeUnit.SECONDS)
|
||||
.send();
|
||||
|
||||
Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestViaForwardHttpProxy() throws Exception
|
||||
{
|
||||
String path = "/path";
|
||||
String query = "a=b";
|
||||
start(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
Assert.assertEquals(path, request.getRequestURI());
|
||||
Assert.assertEquals(query, request.getQueryString());
|
||||
}
|
||||
});
|
||||
|
||||
int proxyPort = connector.getLocalPort();
|
||||
client.getProxyConfiguration().getProxies().add(new HttpProxy("localhost", proxyPort));
|
||||
|
||||
int serverPort = proxyPort + 1; // Any port will do, just not the same as the proxy.
|
||||
ContentResponse response = client.newRequest("localhost", serverPort)
|
||||
.path(path + "?" + query)
|
||||
.timeout(5, TimeUnit.SECONDS)
|
||||
.send();
|
||||
|
||||
Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
public void testExternalServer() throws Exception
|
||||
|
|
|
@ -21,11 +21,13 @@ package org.eclipse.jetty.http2.server;
|
|||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.http.BadMessageException;
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpGenerator;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpHeaderValue;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.http.MetaData;
|
||||
import org.eclipse.jetty.http.PreEncodedHttpField;
|
||||
import org.eclipse.jetty.http2.IStream;
|
||||
|
@ -70,67 +72,93 @@ public class HttpChannelOverHTTP2 extends HttpChannel
|
|||
|
||||
public Runnable onRequest(HeadersFrame frame)
|
||||
{
|
||||
MetaData.Request request = (MetaData.Request)frame.getMetaData();
|
||||
HttpFields fields = request.getFields();
|
||||
|
||||
// HTTP/2 sends the Host header as the :authority
|
||||
// pseudo-header, so we need to synthesize a Host header.
|
||||
if (!fields.contains(HttpHeader.HOST))
|
||||
try
|
||||
{
|
||||
String authority = request.getURI().getAuthority();
|
||||
if (authority != null)
|
||||
MetaData.Request request = (MetaData.Request)frame.getMetaData();
|
||||
HttpFields fields = request.getFields();
|
||||
|
||||
// HTTP/2 sends the Host header as the :authority
|
||||
// pseudo-header, so we need to synthesize a Host header.
|
||||
if (!fields.contains(HttpHeader.HOST))
|
||||
{
|
||||
// Lower-case to be consistent with other HTTP/2 headers.
|
||||
fields.put("host", authority);
|
||||
String authority = request.getURI().getAuthority();
|
||||
if (authority != null)
|
||||
{
|
||||
// Lower-case to be consistent with other HTTP/2 headers.
|
||||
fields.put("host", authority);
|
||||
}
|
||||
}
|
||||
|
||||
_expect100Continue = fields.contains(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString());
|
||||
|
||||
HttpFields response = getResponse().getHttpFields();
|
||||
if (getHttpConfiguration().getSendServerVersion())
|
||||
response.add(SERVER_VERSION);
|
||||
if (getHttpConfiguration().getSendXPoweredBy())
|
||||
response.add(POWERED_BY);
|
||||
|
||||
onRequest(request);
|
||||
|
||||
boolean endStream = frame.isEndStream();
|
||||
if (endStream)
|
||||
onRequestComplete();
|
||||
|
||||
_delayedUntilContent = getHttpConfiguration().isDelayDispatchUntilContent() &&
|
||||
!endStream && !_expect100Continue;
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
Stream stream = getStream();
|
||||
LOG.debug("HTTP2 Request #{}/{}, delayed={}:{}{} {} {}{}{}",
|
||||
stream.getId(), Integer.toHexString(stream.getSession().hashCode()),
|
||||
_delayedUntilContent, System.lineSeparator(),
|
||||
request.getMethod(), request.getURI(), request.getVersion(),
|
||||
System.lineSeparator(), fields);
|
||||
}
|
||||
|
||||
return _delayedUntilContent ? null : this;
|
||||
}
|
||||
|
||||
_expect100Continue = fields.contains(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString());
|
||||
|
||||
HttpFields response = getResponse().getHttpFields();
|
||||
if (getHttpConfiguration().getSendServerVersion())
|
||||
response.add(SERVER_VERSION);
|
||||
if (getHttpConfiguration().getSendXPoweredBy())
|
||||
response.add(POWERED_BY);
|
||||
|
||||
onRequest(request);
|
||||
|
||||
boolean endStream = frame.isEndStream();
|
||||
if (endStream)
|
||||
onRequestComplete();
|
||||
|
||||
_delayedUntilContent = getHttpConfiguration().isDelayDispatchUntilContent() &&
|
||||
!endStream && !_expect100Continue;
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
catch (BadMessageException x)
|
||||
{
|
||||
Stream stream = getStream();
|
||||
LOG.debug("HTTP2 Request #{}/{}, delayed={}:{}{} {} {}{}{}",
|
||||
stream.getId(), Integer.toHexString(stream.getSession().hashCode()),
|
||||
_delayedUntilContent, System.lineSeparator(),
|
||||
request.getMethod(), request.getURI(), request.getVersion(),
|
||||
System.lineSeparator(), fields);
|
||||
onBadMessage(x.getCode(), x.getReason());
|
||||
return null;
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
onBadMessage(HttpStatus.INTERNAL_SERVER_ERROR_500, null);
|
||||
return null;
|
||||
}
|
||||
|
||||
return _delayedUntilContent ? null : this;
|
||||
}
|
||||
|
||||
public Runnable onPushRequest(MetaData.Request request)
|
||||
{
|
||||
onRequest(request);
|
||||
getRequest().setAttribute("org.eclipse.jetty.pushed", Boolean.TRUE);
|
||||
onRequestComplete();
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
try
|
||||
{
|
||||
Stream stream = getStream();
|
||||
LOG.debug("HTTP2 PUSH Request #{}/{}:{}{} {} {}{}{}",
|
||||
stream.getId(), Integer.toHexString(stream.getSession().hashCode()), System.lineSeparator(),
|
||||
request.getMethod(), request.getURI(), request.getVersion(),
|
||||
System.lineSeparator(), request.getFields());
|
||||
}
|
||||
onRequest(request);
|
||||
getRequest().setAttribute("org.eclipse.jetty.pushed", Boolean.TRUE);
|
||||
onRequestComplete();
|
||||
|
||||
return this;
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
Stream stream = getStream();
|
||||
LOG.debug("HTTP2 PUSH Request #{}/{}:{}{} {} {}{}{}",
|
||||
stream.getId(), Integer.toHexString(stream.getSession().hashCode()), System.lineSeparator(),
|
||||
request.getMethod(), request.getURI(), request.getVersion(),
|
||||
System.lineSeparator(), request.getFields());
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
catch (BadMessageException x)
|
||||
{
|
||||
onBadMessage(x.getCode(), x.getReason());
|
||||
return null;
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
onBadMessage(HttpStatus.INTERNAL_SERVER_ERROR_500, null);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in New Issue