Merged branch 'jetty-9.3.x' into 'master'.

This commit is contained in:
Simone Bordet 2016-04-01 19:50:26 +02:00
commit 68a465d7a3
5 changed files with 175 additions and 77 deletions

View File

@ -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);

View File

@ -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 = "" +

View File

@ -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)
{

View File

@ -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

View File

@ -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