Merged branch 'jetty-9.4.x' into 'jetty-10.0.x'.
This commit is contained in:
commit
7abb9d3929
|
@ -51,6 +51,7 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
|
||||||
private RetainableByteBuffer networkBuffer;
|
private RetainableByteBuffer networkBuffer;
|
||||||
private boolean shutdown;
|
private boolean shutdown;
|
||||||
private boolean complete;
|
private boolean complete;
|
||||||
|
private boolean unsolicited;
|
||||||
|
|
||||||
public HttpReceiverOverHTTP(HttpChannelOverHTTP channel)
|
public HttpReceiverOverHTTP(HttpChannelOverHTTP channel)
|
||||||
{
|
{
|
||||||
|
@ -272,6 +273,7 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
|
||||||
public void startResponse(HttpVersion version, int status, String reason)
|
public void startResponse(HttpVersion version, int status, String reason)
|
||||||
{
|
{
|
||||||
HttpExchange exchange = getHttpExchange();
|
HttpExchange exchange = getHttpExchange();
|
||||||
|
unsolicited = exchange == null;
|
||||||
if (exchange == null)
|
if (exchange == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -287,7 +289,8 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
|
||||||
public void parsedHeader(HttpField field)
|
public void parsedHeader(HttpField field)
|
||||||
{
|
{
|
||||||
HttpExchange exchange = getHttpExchange();
|
HttpExchange exchange = getHttpExchange();
|
||||||
if (exchange == null)
|
unsolicited |= exchange == null;
|
||||||
|
if (unsolicited)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
responseHeader(exchange, field);
|
responseHeader(exchange, field);
|
||||||
|
@ -297,7 +300,8 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
|
||||||
public boolean headerComplete()
|
public boolean headerComplete()
|
||||||
{
|
{
|
||||||
HttpExchange exchange = getHttpExchange();
|
HttpExchange exchange = getHttpExchange();
|
||||||
if (exchange == null)
|
unsolicited |= exchange == null;
|
||||||
|
if (unsolicited)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Store the EndPoint is case of upgrades, tunnels, etc.
|
// Store the EndPoint is case of upgrades, tunnels, etc.
|
||||||
|
@ -309,7 +313,8 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
|
||||||
public boolean content(ByteBuffer buffer)
|
public boolean content(ByteBuffer buffer)
|
||||||
{
|
{
|
||||||
HttpExchange exchange = getHttpExchange();
|
HttpExchange exchange = getHttpExchange();
|
||||||
if (exchange == null)
|
unsolicited |= exchange == null;
|
||||||
|
if (unsolicited)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
RetainableByteBuffer networkBuffer = this.networkBuffer;
|
RetainableByteBuffer networkBuffer = this.networkBuffer;
|
||||||
|
@ -331,7 +336,8 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
|
||||||
public void parsedTrailer(HttpField trailer)
|
public void parsedTrailer(HttpField trailer)
|
||||||
{
|
{
|
||||||
HttpExchange exchange = getHttpExchange();
|
HttpExchange exchange = getHttpExchange();
|
||||||
if (exchange == null)
|
unsolicited |= exchange == null;
|
||||||
|
if (unsolicited)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
exchange.getResponse().trailer(trailer);
|
exchange.getResponse().trailer(trailer);
|
||||||
|
@ -341,8 +347,12 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
|
||||||
public boolean messageComplete()
|
public boolean messageComplete()
|
||||||
{
|
{
|
||||||
HttpExchange exchange = getHttpExchange();
|
HttpExchange exchange = getHttpExchange();
|
||||||
if (exchange == null)
|
if (exchange == null || unsolicited)
|
||||||
|
{
|
||||||
|
// We received an unsolicited response from the server.
|
||||||
|
getHttpConnection().close();
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int status = exchange.getResponse().getStatus();
|
int status = exchange.getResponse().getStatus();
|
||||||
if (status != HttpStatus.CONTINUE_100)
|
if (status != HttpStatus.CONTINUE_100)
|
||||||
|
@ -359,7 +369,7 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
|
||||||
{
|
{
|
||||||
HttpExchange exchange = getHttpExchange();
|
HttpExchange exchange = getHttpExchange();
|
||||||
HttpConnectionOverHTTP connection = getHttpConnection();
|
HttpConnectionOverHTTP connection = getHttpConnection();
|
||||||
if (exchange == null)
|
if (exchange == null || unsolicited)
|
||||||
connection.close();
|
connection.close();
|
||||||
else
|
else
|
||||||
failAndClose(new EOFException(String.valueOf(connection)));
|
failAndClose(new EOFException(String.valueOf(connection)));
|
||||||
|
@ -369,7 +379,11 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res
|
||||||
public void badMessage(BadMessageException failure)
|
public void badMessage(BadMessageException failure)
|
||||||
{
|
{
|
||||||
HttpExchange exchange = getHttpExchange();
|
HttpExchange exchange = getHttpExchange();
|
||||||
if (exchange != null)
|
if (exchange == null || unsolicited)
|
||||||
|
{
|
||||||
|
getHttpConnection().close();
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
HttpResponse response = exchange.getResponse();
|
HttpResponse response = exchange.getResponse();
|
||||||
response.status(failure.getCode()).reason(failure.getReason());
|
response.status(failure.getCode()).reason(failure.getReason());
|
||||||
|
|
|
@ -1820,6 +1820,65 @@ public class HttpClientTest extends AbstractHttpClientServerTest
|
||||||
assertArrayEquals(bytes, baos.toByteArray());
|
assertArrayEquals(bytes, baos.toByteArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@ArgumentsSource(ScenarioProvider.class)
|
||||||
|
public void testUnsolicitedResponseBytesFromServer(Scenario scenario) throws Exception
|
||||||
|
{
|
||||||
|
String response = "" +
|
||||||
|
"HTTP/1.1 408 Request Timeout\r\n" +
|
||||||
|
"Content-Length: 0\r\n" +
|
||||||
|
"Connection: close\r\n" +
|
||||||
|
"\r\n";
|
||||||
|
testUnsolicitedBytesFromServer(scenario, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@ArgumentsSource(ScenarioProvider.class)
|
||||||
|
public void testUnsolicitedInvalidBytesFromServer(Scenario scenario) throws Exception
|
||||||
|
{
|
||||||
|
String response = "ABCDEF";
|
||||||
|
testUnsolicitedBytesFromServer(scenario, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testUnsolicitedBytesFromServer(Scenario scenario, String bytesFromServer) throws Exception
|
||||||
|
{
|
||||||
|
try (ServerSocket server = new ServerSocket(0))
|
||||||
|
{
|
||||||
|
startClient(scenario, clientConnector ->
|
||||||
|
{
|
||||||
|
clientConnector.setSelectors(1);
|
||||||
|
HttpClientTransportOverHTTP transport = new HttpClientTransportOverHTTP(clientConnector);
|
||||||
|
transport.setConnectionPoolFactory(destination ->
|
||||||
|
{
|
||||||
|
ConnectionPool connectionPool = new DuplexConnectionPool(destination, 1, destination);
|
||||||
|
connectionPool.preCreateConnections(1);
|
||||||
|
return connectionPool;
|
||||||
|
});
|
||||||
|
return transport;
|
||||||
|
}, null);
|
||||||
|
|
||||||
|
String host = "localhost";
|
||||||
|
int port = server.getLocalPort();
|
||||||
|
|
||||||
|
// Resolve the destination which will pre-create a connection.
|
||||||
|
HttpDestination destination = client.resolveDestination(new Origin("http", host, port));
|
||||||
|
|
||||||
|
// Accept the connection and send an unsolicited 408.
|
||||||
|
try (Socket socket = server.accept())
|
||||||
|
{
|
||||||
|
OutputStream output = socket.getOutputStream();
|
||||||
|
output.write(bytesFromServer.getBytes(StandardCharsets.UTF_8));
|
||||||
|
output.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Give some time to the client to process the response.
|
||||||
|
Thread.sleep(1000);
|
||||||
|
|
||||||
|
AbstractConnectionPool pool = (AbstractConnectionPool)destination.getConnectionPool();
|
||||||
|
assertEquals(0, pool.getConnectionCount());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void assertCopyRequest(Request original)
|
private void assertCopyRequest(Request original)
|
||||||
{
|
{
|
||||||
Request copy = client.copyRequest((HttpRequest)original, original.getURI());
|
Request copy = client.copyRequest((HttpRequest)original, original.getURI());
|
||||||
|
|
Loading…
Reference in New Issue