diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestSecurityAnnotationConversions.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestSecurityAnnotationConversions.java index b3975b1c4cb..3ff372e22ee 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestSecurityAnnotationConversions.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestSecurityAnnotationConversions.java @@ -173,7 +173,7 @@ public class TestSecurityAnnotationConversions public void testMethodAnnotation() throws Exception { //ServletSecurity annotation with HttpConstraint of TransportGuarantee.CONFIDENTIAL, and a list of rolesAllowed, and - //a HttpMethodConstraint for GET method that permits all and has TransportGuarantee.NONE (ie is default) + //an HttpMethodConstraint for GET method that permits all and has TransportGuarantee.NONE (ie is default) WebAppContext wac = makeWebAppContext(Method1Servlet.class.getCanonicalName(), "method1Servlet", new String[]{ "/foo/*", "*.foo" diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClientTransport.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClientTransport.java index b75469f86cf..35b12c0c3f1 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClientTransport.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClientTransport.java @@ -28,7 +28,7 @@ import org.eclipse.jetty.io.ClientConnectionFactory; * in order to plug-in a different transport for {@link HttpClient}. *
* While the {@link HttpClient} APIs define the HTTP semantic (request, response, headers, etc.) - * how a HTTP exchange is carried over the network depends on implementations of this class. + * how an HTTP exchange is carried over the network depends on implementations of this class. *
* The default implementation uses the HTTP protocol to carry over the network the HTTP exchange, * but the HTTP exchange may also be carried using the FCGI protocol, the HTTP/2 protocol or, diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java index 4487033e5f6..17c8d3ab1bd 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpContent.java @@ -32,7 +32,7 @@ import org.eclipse.jetty.util.log.Logger; /** * {@link HttpContent} is a stateful, linear representation of the request content provided * by a {@link ContentProvider} that can be traversed one-way to obtain content buffers to - * send to a HTTP server. + * send to an HTTP server. *
* {@link HttpContent} offers the notion of a one-way cursor to traverse the content. * The cursor starts in a virtual "before" position and can be advanced using {@link #advance()} diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java index 1fba1fdf247..991768f1121 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java @@ -51,7 +51,7 @@ import org.eclipse.jetty.util.log.Logger; *
{@link Request} represents a HTTP request, and offers a fluent interface to customize + *
{@link Request} represents an HTTP request, and offers a fluent interface to customize * various attributes such as the path, the headers, the content, etc.
*You can create {@link Request} objects via {@link HttpClient#newRequest(String)} and * you can send them using either {@link #send()} for a blocking semantic, or diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java index a5874fbcad1..99d37164ddf 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/api/Response.java @@ -29,7 +29,7 @@ import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.util.Callback; /** - *
{@link Response} represents a HTTP response and offers methods to retrieve status code, HTTP version + *
{@link Response} represents an HTTP response and offers methods to retrieve status code, HTTP version * and headers.
*{@link Response} objects are passed as parameters to {@link Response.Listener} callbacks, or as * future result of {@link Request#send()}.
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java index 1666a60278e..15e239eee06 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java @@ -161,7 +161,7 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res } /** - * Parses a HTTP response in the receivers buffer. + * Parses an HTTP response in the receivers buffer. * * @return true to indicate that parsing should be interrupted (and will be resumed by another thread). */ diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HostnameVerificationTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HostnameVerificationTest.java index 63b9ea6b77d..9ce3ab9955e 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HostnameVerificationTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HostnameVerificationTest.java @@ -100,7 +100,7 @@ public class HostnameVerificationTest /** * This test is supposed to verify that hostname verification works as described in: * http://www.ietf.org/rfc/rfc2818.txt section 3.1. It uses a certificate with a common name different to localhost - * and sends a request to localhost. This should fail with a SSLHandshakeException. + * and sends a request to localhost. This should fail with an SSLHandshakeException. * * @throws Exception on test failure */ diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpConnectionLifecycleTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpConnectionLifecycleTest.java index 9d22bd0ee9e..3c4b362a324 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpConnectionLifecycleTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpConnectionLifecycleTest.java @@ -494,7 +494,7 @@ public class HttpConnectionLifecycleTest extends AbstractHttpClientServerTest .scheme(scenario.getScheme()) .onResponseBegin(response1 -> { - // Simulate a HTTP 1.0 response has been received. + // Simulate an HTTP 1.0 response has been received. ((HttpResponse)response1).version(HttpVersion.HTTP_1_0); }) .send(); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesServerTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesServerTest.java index 96a9fdc7bfc..7ea3318b796 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesServerTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesServerTest.java @@ -1803,7 +1803,7 @@ public class SslBytesServerTest extends SslBytesTest assertTrue(latch.await(idleTimeout * 2, TimeUnit.MILLISECONDS)); - // Be sure that the server sent a SSL close alert + // Be sure that the server sent an SSL close alert TLSRecord record = proxy.readFromServer(); assertNotNull(record); assertEquals(TLSRecord.Type.ALERT, record.getType()); diff --git a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Continuation.java b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Continuation.java index c0104dbeecb..c5edaf09993 100644 --- a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Continuation.java +++ b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Continuation.java @@ -26,7 +26,7 @@ import javax.servlet.ServletResponseWrapper; /** * Continuation. *- * A continuation is a mechanism by which a HTTP Request can be suspended and + * A continuation is a mechanism by which an HTTP Request can be suspended and * restarted after a timeout or an asynchronous event has occurred. *
* The continuation mechanism is a portable mechanism that will work
diff --git a/jetty-deploy/src/test/resources/jetty-http.xml b/jetty-deploy/src/test/resources/jetty-http.xml
index 57a4fb5567b..43ed57d5425 100644
--- a/jetty-deploy/src/test/resources/jetty-http.xml
+++ b/jetty-deploy/src/test/resources/jetty-http.xml
@@ -1,10 +1,10 @@
-
+
- * This servlet accepts a HTTP request and transforms it into a FastCGI request
+ * This servlet accepts an HTTP request and transforms it into a FastCGI request
* that is sent to the FastCGI server specified in the {@code proxyTo}
* init-param.
*
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java
index 2379bcef99e..4b6128182fc 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java
@@ -21,7 +21,7 @@ package org.eclipse.jetty.http;
import org.eclipse.jetty.util.HostPort;
/**
- * A HttpField holding a preparsed Host and port number
+ * An HttpField holding a preparsed Host and port number
*
* @see HostPort
*/
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java
index 5f12147772f..05a2783dfdb 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java
@@ -23,7 +23,7 @@ import java.util.Objects;
import org.eclipse.jetty.util.StringUtil;
/**
- * A HTTP Field
+ * An HTTP Field
*/
public class HttpField
{
@@ -37,7 +37,10 @@ public class HttpField
public HttpField(HttpHeader header, String name, String value)
{
_header = header;
- _name = name;
+ if (_header != null && name == null)
+ _name = _header.asString();
+ else
+ _name = Objects.requireNonNull(name);
_value = value;
}
@@ -325,8 +328,6 @@ public class HttpField
return false;
if (!_name.equalsIgnoreCase(field.getName()))
return false;
- if (_value == null && field.getValue() != null)
- return false;
return Objects.equals(_value, field.getValue());
}
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpMethod.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpMethod.java
index 741be954df5..016f3dcbbee 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpMethod.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpMethod.java
@@ -48,7 +48,7 @@ public enum HttpMethod
* @param bytes Array containing ISO-8859-1 characters
* @param position The first valid index
* @param limit The first non valid index
- * @return A HttpMethod if a match or null if no easy match.
+ * @return An HttpMethod if a match or null if no easy match.
*/
public static HttpMethod lookAheadGet(byte[] bytes, final int position, int limit)
{
@@ -110,7 +110,7 @@ public enum HttpMethod
* Optimized lookup to find a method name and trailing space in a byte array.
*
* @param buffer buffer containing ISO-8859-1 characters, it is not modified.
- * @return A HttpMethod if a match or null if no easy match.
+ * @return An HttpMethod if a match or null if no easy match.
*/
public static HttpMethod lookAheadGet(ByteBuffer buffer)
{
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java
index 7ebd682f667..435579c9df0 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java
@@ -477,7 +477,7 @@ public class HttpParser
return t;
}
- /* Quick lookahead for the start state looking for a request method or a HTTP version,
+ /* Quick lookahead for the start state looking for a request method or an HTTP version,
* otherwise skip white space until something else to parse.
*/
private boolean quickStart(ByteBuffer buffer)
@@ -1873,14 +1873,14 @@ public class HttpParser
boolean messageComplete();
/**
- * This is the method called by parser when a HTTP Header name and value is found
+ * This is the method called by parser when an HTTP Header name and value is found
*
* @param field The field parsed
*/
void parsedHeader(HttpField field);
/**
- * This is the method called by parser when a HTTP Trailer name and value is found
+ * This is the method called by parser when an HTTP Trailer name and value is found
*
* @param field The field parsed
*/
@@ -1890,7 +1890,7 @@ public class HttpParser
/**
* Called to signal that an EOF was received unexpectedly
- * during the parsing of a HTTP message
+ * during the parsing of an HTTP message
*/
void earlyEOF();
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java
index 5f5fec2636a..4fb2a36989e 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java
@@ -31,7 +31,7 @@ import org.eclipse.jetty.util.UrlEncoded;
/**
* Http URI.
- * Parse a HTTP URI from a string or byte array. Given a URI
+ * Parse an HTTP URI from a string or byte array. Given a URI
* A HttpField that will be cached and used many times can be created as
+ * An HttpField that will be cached and used many times can be created as
* a {@link PreEncodedHttpField}, which will use the {@link HttpFieldPreEncoder}
* instances discovered by the {@link ServiceLoader} to pre-encode the header
* for each version of HTTP in use. This will save garbage
diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java
index bb8a71e4012..2a5394e6ed0 100644
--- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java
+++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java
@@ -30,6 +30,8 @@ import java.util.NoSuchElementException;
import org.eclipse.jetty.util.BufferUtil;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
@@ -666,6 +668,41 @@ public class HttpFieldsTest
assertFalse(header.containsKey("n11"));
}
+ @ParameterizedTest
+ @ValueSource(strings = {"Host", "host", "HOST", "HoSt", "Connection", "CONNECTION", "connection", "CoNnEcTiOn"})
+ public void testContainsKeyTrue(String keyName)
+ {
+ HttpFields fields = new HttpFields();
+ fields.put("Host", "localhost");
+ HttpField namelessField = new HttpField(HttpHeader.CONNECTION, null, "bogus");
+ fields.put(namelessField);
+
+ assertTrue(fields.containsKey(keyName), "containsKey('" + keyName + "')");
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"Content-Type", "Content-Length", "X-Bogus", ""})
+ public void testContainsKeyFalse(String keyName)
+ {
+ HttpFields fields = new HttpFields();
+ fields.add("Host", "localhost");
+ HttpField namelessField = new HttpField(HttpHeader.CONNECTION, null, "bogus");
+ fields.put(namelessField);
+
+ assertFalse(fields.containsKey(keyName), "containsKey('" + keyName + "')");
+ }
+
+ @Test
+ public void testPreventNullField()
+ {
+ HttpFields fields = new HttpFields();
+ assertThrows(NullPointerException.class, () ->
+ {
+ HttpField nullNullField = new HttpField(null, null, "bogus");
+ fields.put(nullNullField);
+ });
+ }
+
@Test
public void testIteration() throws Exception
{
diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpTester.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpTester.java
index 27d494e3649..eee24e824be 100644
--- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpTester.java
+++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpTester.java
@@ -32,7 +32,7 @@ import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/**
- * A HTTP Testing helper class.
+ * An HTTP Testing helper class.
*
* Example usage:
* The SPI interface for implementing a HTTP/2 session. The SPI interface for implementing an HTTP/2 session. This class extends {@link Session} by adding the methods required to
* implement the HTTP/2 session functionalities. The SPI interface for implementing a HTTP/2 stream. The SPI interface for implementing an HTTP/2 stream. This class extends {@link Stream} by adding the methods required to
* implement the HTTP/2 stream functionalities. A {@link Session} represents the client-side endpoint of a HTTP/2 connection to a single origin server. A {@link Session} represents the client-side endpoint of an HTTP/2 connection to a single origin server. Once a {@link Session} has been obtained, it can be used to open HTTP/2 streams: A {@link Listener} is the passive counterpart of a {@link Session} and
- * receives events happening on a HTTP/2 connection.http://user@host:port/path/info;param?query#fragment
* this class will split it into the following undecoded optional elements:
*
diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java
index 132733ee8c2..b5be288a82b 100644
--- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java
+++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java
@@ -27,7 +27,6 @@ import java.util.Map;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -46,6 +45,7 @@ import org.eclipse.jetty.http2.frames.DataFrame;
import org.eclipse.jetty.http2.frames.GoAwayFrame;
import org.eclipse.jetty.http2.frames.HeadersFrame;
import org.eclipse.jetty.http2.frames.SettingsFrame;
+import org.eclipse.jetty.http2.parser.RateControl;
import org.eclipse.jetty.http2.parser.ServerParser;
import org.eclipse.jetty.http2.server.RawHTTP2ServerConnectionFactory;
import org.eclipse.jetty.server.Connector;
@@ -152,7 +152,7 @@ public class HTTP2Test extends AbstractTest
start(new HttpServlet()
{
@Override
- protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+ protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException
{
resp.getOutputStream().write(content);
}
@@ -200,7 +200,7 @@ public class HTTP2Test extends AbstractTest
start(new EmptyHttpServlet()
{
@Override
- protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException
{
IO.copy(request.getInputStream(), response.getOutputStream());
}
@@ -244,7 +244,7 @@ public class HTTP2Test extends AbstractTest
start(new HttpServlet()
{
@Override
- protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException
{
int download = request.getIntHeader(downloadBytes);
byte[] content = new byte[download];
@@ -287,7 +287,7 @@ public class HTTP2Test extends AbstractTest
start(new HttpServlet()
{
@Override
- protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ protected void service(HttpServletRequest request, HttpServletResponse response)
{
response.setStatus(status);
}
@@ -322,7 +322,7 @@ public class HTTP2Test extends AbstractTest
start(new HttpServlet()
{
@Override
- protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ protected void service(HttpServletRequest request, HttpServletResponse response)
{
assertEquals(host, request.getServerName());
assertEquals(port, request.getServerPort());
@@ -747,7 +747,7 @@ public class HTTP2Test extends AbstractTest
RawHTTP2ServerConnectionFactory connectionFactory = new RawHTTP2ServerConnectionFactory(new HttpConfiguration(), serverListener)
{
@Override
- protected ServerParser newServerParser(Connector connector, ServerParser.Listener listener)
+ protected ServerParser newServerParser(Connector connector, ServerParser.Listener listener, RateControl rateControl)
{
return super.newServerParser(connector, new ServerParser.Listener.Wrapper(listener)
{
@@ -757,7 +757,7 @@ public class HTTP2Test extends AbstractTest
super.onGoAway(frame);
goAwayLatch.countDown();
}
- });
+ }, rateControl);
}
};
prepareServer(connectionFactory);
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/BufferingFlowControlStrategy.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/BufferingFlowControlStrategy.java
index a5a57fa2666..7eff31981e2 100644
--- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/BufferingFlowControlStrategy.java
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/BufferingFlowControlStrategy.java
@@ -170,7 +170,7 @@ public class BufferingFlowControlStrategy extends AbstractFlowControlStrategy
// and here we keep track of its max value.
// Updating the max session recv window is done here
- // so that if a peer decides to send an unilateral
+ // so that if a peer decides to send a unilateral
// window update to enlarge the session window,
// without the corresponding data consumption, here
// we can track it.
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ErrorCode.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ErrorCode.java
index ac36211f847..4269bc67d1f 100644
--- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ErrorCode.java
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ErrorCode.java
@@ -40,7 +40,7 @@ public enum ErrorCode
*/
INTERNAL_ERROR(2),
/**
- * Indicates a HTTP/2 flow control violation.
+ * Indicates an HTTP/2 flow control violation.
*/
FLOW_CONTROL_ERROR(3),
/**
@@ -68,7 +68,7 @@ public enum ErrorCode
*/
COMPRESSION_ERROR(9),
/**
- * Indicates that the connection established by a HTTP CONNECT was abnormally closed.
+ * Indicates that the connection established by an HTTP CONNECT was abnormally closed.
*/
HTTP_CONNECT_ERROR(10),
/**
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java
index 770f1d07f28..a8fb651121a 100644
--- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java
@@ -57,6 +57,7 @@ import org.eclipse.jetty.util.AtomicBiInteger;
import org.eclipse.jetty.util.Atomics;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.CountingCallback;
+import org.eclipse.jetty.util.MathUtils;
import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.Retainable;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
@@ -460,47 +461,33 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
int windowDelta = frame.getWindowDelta();
if (streamId > 0)
{
- if (windowDelta == 0)
+ IStream stream = getStream(streamId);
+ if (stream != null)
{
- reset(new ResetFrame(streamId, ErrorCode.PROTOCOL_ERROR.code), Callback.NOOP);
- }
- else
- {
- IStream stream = getStream(streamId);
- if (stream != null)
+ int streamSendWindow = stream.updateSendWindow(0);
+ if (MathUtils.sumOverflows(streamSendWindow, windowDelta))
{
- int streamSendWindow = stream.updateSendWindow(0);
- if (sumOverflows(streamSendWindow, windowDelta))
- {
- reset(new ResetFrame(streamId, ErrorCode.FLOW_CONTROL_ERROR.code), Callback.NOOP);
- }
- else
- {
- stream.process(frame, Callback.NOOP);
- onWindowUpdate(stream, frame);
- }
+ reset(new ResetFrame(streamId, ErrorCode.FLOW_CONTROL_ERROR.code), Callback.NOOP);
}
else
{
- if (!isRemoteStreamClosed(streamId))
- onConnectionFailure(ErrorCode.PROTOCOL_ERROR.code, "unexpected_window_update_frame");
+ stream.process(frame, Callback.NOOP);
+ onWindowUpdate(stream, frame);
}
}
+ else
+ {
+ if (!isRemoteStreamClosed(streamId))
+ onConnectionFailure(ErrorCode.PROTOCOL_ERROR.code, "unexpected_window_update_frame");
+ }
}
else
{
- if (windowDelta == 0)
- {
- onConnectionFailure(ErrorCode.PROTOCOL_ERROR.code, "invalid_window_update_frame");
- }
+ int sessionSendWindow = updateSendWindow(0);
+ if (MathUtils.sumOverflows(sessionSendWindow, windowDelta))
+ onConnectionFailure(ErrorCode.FLOW_CONTROL_ERROR.code, "invalid_flow_control_window");
else
- {
- int sessionSendWindow = updateSendWindow(0);
- if (sumOverflows(sessionSendWindow, windowDelta))
- onConnectionFailure(ErrorCode.FLOW_CONTROL_ERROR.code, "invalid_flow_control_window");
- else
- onWindowUpdate(null, frame);
- }
+ onWindowUpdate(null, frame);
}
}
@@ -515,19 +502,6 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
callback.succeeded();
}
- private boolean sumOverflows(int a, int b)
- {
- try
- {
- Math.addExact(a, b);
- return false;
- }
- catch (ArithmeticException x)
- {
- return true;
- }
- }
-
@Override
public void onConnectionFailure(int error, String reason)
{
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java
index 2e198fa5931..3df57d39b29 100644
--- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java
@@ -30,7 +30,7 @@ import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Promise;
/**
- *
* Session session = ...;
@@ -127,7 +127,7 @@ public interface Session
/**
*
Callback method invoked when a new stream is being created upon - * receiving a HEADERS frame representing a HTTP request.
+ * receiving a HEADERS frame representing an HTTP request. *Applications should implement this method to process HTTP requests, - * typically providing a HTTP response via + * typically providing an HTTP response via * {@link Stream#headers(HeadersFrame, Callback)}.
*Applications can detect whether request DATA frames will be arriving * by testing {@link HeadersFrame#isEndStream()}. If the application is diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java index 681c0870ff1..bb413d8d953 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java @@ -29,8 +29,8 @@ import org.eclipse.jetty.util.Promise; *
A {@link Stream} represents a bidirectional exchange of data on top of a {@link Session}.
*Differently from socket streams, where the input and output streams are permanently associated * with the socket (and hence with the connection that the socket represents), there can be multiple - * HTTP/2 streams present concurrent for a HTTP/2 session.
- *A {@link Stream} maps to a HTTP request/response cycle, and after the request/response cycle is + * HTTP/2 streams present concurrent for an HTTP/2 session.
+ *A {@link Stream} maps to an HTTP request/response cycle, and after the request/response cycle is * completed, the stream is closed and removed from the session.
*Like {@link Session}, {@link Stream} is the active part and by calling its API applications * can generate events on the stream; conversely, {@link Stream.Listener} is the passive part, and @@ -51,7 +51,7 @@ public interface Stream Session getSession(); /** - *
Sends the given HEADERS {@code frame} representing a HTTP response.
+ *Sends the given HEADERS {@code frame} representing an HTTP response.
* * @param frame the HEADERS frame to send * @param callback the callback that gets notified when the frame has been sent @@ -131,7 +131,7 @@ public interface Stream /** *A {@link Stream.Listener} is the passive counterpart of a {@link Stream} and receives - * events happening on a HTTP/2 stream.
+ * events happening on an HTTP/2 stream. * * @see Stream */ diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/ContinuationFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/ContinuationFrame.java new file mode 100644 index 00000000000..39d69310ce8 --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/ContinuationFrame.java @@ -0,0 +1,48 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.frames; + +public class ContinuationFrame extends Frame +{ + private final int streamId; + private final boolean endHeaders; + + public ContinuationFrame(int streamId, boolean endHeaders) + { + super(FrameType.CONTINUATION); + this.streamId = streamId; + this.endHeaders = endHeaders; + } + + public int getStreamId() + { + return streamId; + } + + public boolean isEndHeaders() + { + return endHeaders; + } + + @Override + public String toString() + { + return String.format("%s#%d{end=%b}", super.toString(), getStreamId(), isEndHeaders()); + } +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/UnknownFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/UnknownFrame.java new file mode 100644 index 00000000000..ffd88682b2a --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/UnknownFrame.java @@ -0,0 +1,36 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.frames; + +public class UnknownFrame extends Frame +{ + private final int frameType; + + public UnknownFrame(int frameType) + { + super(null); + this.frameType = frameType; + } + + @Override + public String toString() + { + return String.format("%s,t=%d", super.toString(), frameType); + } +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java index 82d18f96a84..01c6d29e570 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/BodyParser.java @@ -96,6 +96,11 @@ public abstract class BodyParser return headerParser.getLength(); } + protected int getFrameType() + { + return headerParser.getFrameType(); + } + protected void notifyData(DataFrame frame) { try @@ -223,9 +228,10 @@ public abstract class BodyParser } } - protected void streamFailure(int streamId, int error, String reason) + protected boolean streamFailure(int streamId, int error, String reason) { notifyStreamFailure(streamId, error, reason); + return false; } private void notifyStreamFailure(int streamId, int error, String reason) @@ -239,4 +245,9 @@ public abstract class BodyParser LOG.info("Failure while notifying listener " + listener, x); } } + + protected boolean rateControlOnEvent(Object o) + { + return headerParser.getRateControl().onEvent(o); + } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ContinuationBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ContinuationBodyParser.java index 65e47d1c827..fc2e03e97a0 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ContinuationBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ContinuationBodyParser.java @@ -23,6 +23,7 @@ import java.nio.ByteBuffer; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.ErrorCode; import org.eclipse.jetty.http2.Flags; +import org.eclipse.jetty.http2.frames.ContinuationFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; public class ContinuationBodyParser extends BodyParser @@ -43,7 +44,15 @@ public class ContinuationBodyParser extends BodyParser protected void emptyBody(ByteBuffer buffer) { if (hasFlag(Flags.END_HEADERS)) - onHeaders(); + { + onHeaders(buffer); + } + else + { + ContinuationFrame frame = new ContinuationFrame(getStreamId(), hasFlag(Flags.END_HEADERS)); + if (!rateControlOnEvent(frame)) + connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_continuation_frame_rate"); + } } @Override @@ -81,7 +90,7 @@ public class ContinuationBodyParser extends BodyParser headerBlockFragments.storeFragment(buffer, length, last); reset(); if (last) - return onHeaders(); + return onHeaders(buffer); return true; } } @@ -94,15 +103,20 @@ public class ContinuationBodyParser extends BodyParser return false; } - private boolean onHeaders() + private boolean onHeaders(ByteBuffer buffer) { ByteBuffer headerBlock = headerBlockFragments.complete(); MetaData metaData = headerBlockParser.parse(headerBlock, headerBlock.remaining()); + if (metaData == null) + return true; if (metaData == HeaderBlockParser.SESSION_FAILURE) return false; - if (metaData == null || metaData == HeaderBlockParser.STREAM_FAILURE) - return true; HeadersFrame frame = new HeadersFrame(getStreamId(), metaData, headerBlockFragments.getPriorityFrame(), headerBlockFragments.isEndStream()); + if (metaData == HeaderBlockParser.STREAM_FAILURE) + { + if (!rateControlOnEvent(frame)) + return connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_continuation_frame_rate"); + } notifyHeaders(frame); return true; } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java index ac9e7bab991..be0ede0a5cb 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/DataBodyParser.java @@ -48,9 +48,17 @@ public class DataBodyParser extends BodyParser protected void emptyBody(ByteBuffer buffer) { if (isPadding()) + { connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_data_frame"); + } else - onData(BufferUtil.EMPTY_BUFFER, false, 0); + { + DataFrame frame = new DataFrame(getStreamId(), BufferUtil.EMPTY_BUFFER, isEndStream()); + if (!isEndStream() && !rateControlOnEvent(frame)) + connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_data_frame_rate"); + else + onData(frame); + } } @Override @@ -134,7 +142,11 @@ public class DataBodyParser extends BodyParser private void onData(ByteBuffer buffer, boolean fragment, int padding) { - DataFrame frame = new DataFrame(getStreamId(), buffer, !fragment && isEndStream(), padding); + onData(new DataFrame(getStreamId(), buffer, !fragment && isEndStream(), padding)); + } + + private void onData(DataFrame frame) + { notifyData(frame); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java index 0e4d2dc5e9e..e735d9ada3e 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderParser.java @@ -30,14 +30,24 @@ import org.eclipse.jetty.http2.frames.FrameType; */ public class HeaderParser { + private final RateControl rateControl; private State state = State.LENGTH; private int cursor; - private int length; private int type; private int flags; private int streamId; + public HeaderParser(RateControl rateControl) + { + this.rateControl = rateControl; + } + + public RateControl getRateControl() + { + return rateControl; + } + protected void reset() { state = State.LENGTH; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java index febdefb6c25..3054d5ee439 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java @@ -61,17 +61,23 @@ public class HeadersBodyParser extends BodyParser @Override protected void emptyBody(ByteBuffer buffer) { - if (hasFlag(Flags.END_HEADERS)) + if (hasFlag(Flags.PRIORITY)) + { + connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_headers_priority_frame"); + } + else if (hasFlag(Flags.END_HEADERS)) { MetaData metaData = headerBlockParser.parse(BufferUtil.EMPTY_BUFFER, 0); - onHeaders(0, 0, false, metaData); + HeadersFrame frame = new HeadersFrame(getStreamId(), metaData, null, isEndStream()); + if (!rateControlOnEvent(frame)) + connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_headers_frame_rate"); + else + onHeaders(frame); } else { headerBlockFragments.setStreamId(getStreamId()); headerBlockFragments.setEndStream(isEndStream()); - if (hasFlag(Flags.PRIORITY)) - connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_headers_priority_frame"); } } @@ -179,7 +185,15 @@ public class HeadersBodyParser extends BodyParser state = State.PADDING; loop = paddingLength == 0; if (metaData != HeaderBlockParser.STREAM_FAILURE) + { onHeaders(parentStreamId, weight, exclusive, metaData); + } + else + { + HeadersFrame frame = new HeadersFrame(getStreamId(), metaData, null, isEndStream()); + if (!rateControlOnEvent(frame)) + connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_headers_frame_rate"); + } } } else @@ -230,6 +244,11 @@ public class HeadersBodyParser extends BodyParser if (hasFlag(Flags.PRIORITY)) priorityFrame = new PriorityFrame(getStreamId(), parentStreamId, weight, exclusive); HeadersFrame frame = new HeadersFrame(getStreamId(), metaData, priorityFrame, isEndStream()); + onHeaders(frame); + } + + private void onHeaders(HeadersFrame frame) + { notifyHeaders(frame); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java index 15920bebcdd..7545b6fe159 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java @@ -54,18 +54,22 @@ public class Parser private final HpackDecoder hpackDecoder; private final BodyParser[] bodyParsers; private UnknownBodyParser unknownBodyParser; - private int maxFrameLength; + private int maxFrameLength = Frame.DEFAULT_MAX_LENGTH; private int maxSettingsKeys = SettingsFrame.DEFAULT_MAX_KEYS; private boolean continuation; private State state = State.HEADER; public Parser(ByteBufferPool byteBufferPool, Listener listener, int maxDynamicTableSize, int maxHeaderSize) + { + this(byteBufferPool, listener, maxDynamicTableSize, maxHeaderSize, RateControl.NO_RATE_CONTROL); + } + + public Parser(ByteBufferPool byteBufferPool, Listener listener, int maxDynamicTableSize, int maxHeaderSize, RateControl rateControl) { this.byteBufferPool = byteBufferPool; this.listener = listener; - this.headerParser = new HeaderParser(); + this.headerParser = new HeaderParser(rateControl == null ? RateControl.NO_RATE_CONTROL : rateControl); this.hpackDecoder = new HpackDecoder(maxDynamicTableSize, maxHeaderSize); - this.maxFrameLength = Frame.DEFAULT_MAX_LENGTH; this.bodyParsers = new BodyParser[FrameType.values().length]; } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java index 8cee350e91e..e56e573236e 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PingBodyParser.java @@ -66,7 +66,7 @@ public class PingBodyParser extends BodyParser if (buffer.remaining() >= 8) { buffer.get(payload); - return onPing(payload); + return onPing(buffer, payload); } else { @@ -80,7 +80,7 @@ public class PingBodyParser extends BodyParser payload[8 - cursor] = buffer.get(); --cursor; if (cursor == 0) - return onPing(payload); + return onPing(buffer, payload); break; } default: @@ -92,9 +92,11 @@ public class PingBodyParser extends BodyParser return false; } - private boolean onPing(byte[] payload) + private boolean onPing(ByteBuffer buffer, byte[] payload) { PingFrame frame = new PingFrame(payload, hasFlag(Flags.ACK)); + if (!rateControlOnEvent(frame)) + return connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_ping_frame_rate"); reset(); notifyPing(frame); return true; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java index 3a6058878a4..741bba433a7 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PrefaceParser.java @@ -42,7 +42,7 @@ public class PrefaceParser *Advances this parser after the {@link PrefaceFrame#PREFACE_PREAMBLE_BYTES}.
*This allows the HTTP/1.1 parser to parse the preamble of the preface, * which is a legal HTTP/1.1 request, and this parser will parse the remaining - * bytes, that are not parseable by a HTTP/1.1 parser.
+ * bytes, that are not parseable by an HTTP/1.1 parser. */ protected void directUpgrade() { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java index a9d11398987..914e9387b30 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PriorityBodyParser.java @@ -103,7 +103,7 @@ public class PriorityBodyParser extends BodyParser if (getStreamId() == parentStreamId) return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_priority_frame"); int weight = (buffer.get() & 0xFF) + 1; - return onPriority(parentStreamId, weight, exclusive); + return onPriority(buffer, parentStreamId, weight, exclusive); } default: { @@ -114,9 +114,11 @@ public class PriorityBodyParser extends BodyParser return false; } - private boolean onPriority(int parentStreamId, int weight, boolean exclusive) + private boolean onPriority(ByteBuffer buffer, int parentStreamId, int weight, boolean exclusive) { PriorityFrame frame = new PriorityFrame(getStreamId(), parentStreamId, weight, exclusive); + if (!rateControlOnEvent(frame)) + return connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_priority_frame_rate"); reset(); notifyPriority(frame); return true; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/RateControl.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/RateControl.java new file mode 100644 index 00000000000..be8f82a7cf2 --- /dev/null +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/RateControl.java @@ -0,0 +1,39 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.parser; + +/** + * Controls rate of events via {@link #onEvent(Object)}. + */ +public interface RateControl +{ + public static final RateControl NO_RATE_CONTROL = event -> true; + + /** + *Applications should call this method when they want to signal an + * event that is subject to rate control.
+ *Implementations should return true if the event does not exceed + * the desired rate, or false to signal that the event exceeded the + * desired rate.
+ * + * @param event the event subject to rate control. + * @return true IFF the rate is within limits + */ + public boolean onEvent(Object event); +} diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java index 49d40f8fd58..067e263cd33 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java @@ -37,9 +37,9 @@ public class ServerParser extends Parser private State state = State.PREFACE; private boolean notifyPreface = true; - public ServerParser(ByteBufferPool byteBufferPool, Listener listener, int maxDynamicTableSize, int maxHeaderSize) + public ServerParser(ByteBufferPool byteBufferPool, Listener listener, int maxDynamicTableSize, int maxHeaderSize, RateControl rateControl) { - super(byteBufferPool, listener, maxDynamicTableSize, maxHeaderSize); + super(byteBufferPool, listener, maxDynamicTableSize, maxHeaderSize, rateControl); this.listener = listener; this.prefaceParser = new PrefaceParser(listener); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java index 741dd95981d..b58fa8a8b51 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java @@ -19,6 +19,7 @@ package org.eclipse.jetty.http2.parser; import java.nio.ByteBuffer; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; @@ -72,7 +73,12 @@ public class SettingsBodyParser extends BodyParser @Override protected void emptyBody(ByteBuffer buffer) { - onSettings(buffer, new HashMap<>()); + boolean isReply = hasFlag(Flags.ACK); + SettingsFrame frame = new SettingsFrame(Collections.emptyMap(), isReply); + if (!isReply && !rateControlOnEvent(frame)) + connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_settings_frame_rate"); + else + onSettings(frame); } @Override @@ -200,6 +206,11 @@ public class SettingsBodyParser extends BodyParser return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_settings_max_frame_size"); SettingsFrame frame = new SettingsFrame(settings, hasFlag(Flags.ACK)); + return onSettings(frame); + } + + private boolean onSettings(SettingsFrame frame) + { reset(); notifySettings(frame); return true; @@ -207,40 +218,25 @@ public class SettingsBodyParser extends BodyParser public static SettingsFrame parseBody(final ByteBuffer buffer) { - final int bodyLength = buffer.remaining(); - final AtomicReferenceAn implementation of {@link RateControl} that limits the number of + * events within a time period.
+ *Events are kept in a queue and for each event the queue is first + * drained of the old events outside the time window, and then the new + * event is added to the queue. The size of the queue is maintained + * separately in an AtomicInteger and if it exceeds the max + * number of events then {@link #onEvent(Object)} returns {@code false}.
+ */ +public class WindowRateControl implements RateControl +{ + private final QueueIf used in combination with a {@link HttpConnectionFactory} as the
* default protocol, this factory can support the non-standard direct
- * update mechanism, where a HTTP1 request of the form "PRI * HTTP/2.0"
- * is used to trigger a switch to a HTTP2 connection. This approach
+ * update mechanism, where an HTTP1 request of the form "PRI * HTTP/2.0"
+ * is used to trigger a switch to an HTTP2 connection. This approach
* allows a single port to accept either HTTP/1 or HTTP/2 direct
* connections.
*/
diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java
index 331696417d2..f8dfdbf7d36 100644
--- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java
+++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java
@@ -64,7 +64,7 @@ import org.eclipse.jetty.util.TypeUtil;
public class HTTP2ServerConnection extends HTTP2Connection implements Connection.UpgradeTo
{
/**
- * @param protocol A HTTP2 protocol variant
+ * @param protocol An HTTP2 protocol variant
* @return True if the protocol version is supported
*/
public static boolean isSupportedProtocol(String protocol)
diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2CServerTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2CServerTest.java
index ed1fd6e948a..48552abebac 100644
--- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2CServerTest.java
+++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2CServerTest.java
@@ -188,7 +188,7 @@ public class HTTP2CServerTest extends AbstractServerTest
assertThat(content, containsString("Hello from Jetty using HTTP/1.1"));
assertThat(content, containsString("uri=/one"));
- // Send a HTTP/2 request.
+ // Send an HTTP/2 request.
headersRef.set(null);
dataRef.set(null);
latchRef.set(new CountDownLatch(2));
@@ -319,7 +319,7 @@ public class HTTP2CServerTest extends AbstractServerTest
connector.setDefaultProtocol(connectionFactory.getProtocol());
connector.start();
- // Now send a HTTP/2 direct request, which
+ // Now send an HTTP/2 direct request, which
// will have the PRI * HTTP/2.0 preface.
byteBufferPool = new MappedByteBufferPool();
@@ -336,7 +336,7 @@ public class HTTP2CServerTest extends AbstractServerTest
output.write(BufferUtil.toArray(buffer));
}
- // We sent a HTTP/2 preface, but the server has no "h2c" connection
+ // We sent an HTTP/2 preface, but the server has no "h2c" connection
// factory so it does not know how to handle this request.
InputStream input = client.getInputStream();
diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-http.xml b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-http.xml
index 4e571ac750a..412e644a2e2 100644
--- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-http.xml
+++ b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-http.xml
@@ -1,10 +1,10 @@
-
+
Upon receiving a HTTP request, the server tries to authenticate the client + *
Upon receiving an HTTP request, the server tries to authenticate the client * calling {@link #login(String, Object, ServletRequest)} where the GSS APIs are used to * verify client tokens and (perhaps after a few round-trips) a {@code GSSContext} is * established.
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java b/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java index 6a50ecd8c29..e6224c102cb 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java @@ -806,7 +806,7 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr { //an exact method name if (!hasOmissions) - //a http-method does not have http-method-omission to cover the other method names + //an http-method does not have http-method-omission to cover the other method names uncoveredPaths.add(path); } } diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SessionAuthentication.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SessionAuthentication.java index 1a672615e96..1a6de7a1874 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SessionAuthentication.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/SessionAuthentication.java @@ -39,7 +39,7 @@ import org.eclipse.jetty.util.log.Logger; * * When a user has been successfully authenticated with some types * of Authenticator, the Authenticator stashes a SessionAuthentication - * into a HttpSession to remember that the user is authenticated. + * into an HttpSession to remember that the user is authenticated. */ public class SessionAuthentication extends AbstractUserAuthentication implements Serializable, HttpSessionActivationListener, HttpSessionBindingListener diff --git a/jetty-security/src/test/java/org/eclipse/jetty/security/ConstraintTest.java b/jetty-security/src/test/java/org/eclipse/jetty/security/ConstraintTest.java index 67140ff6d70..ffefdea617e 100644 --- a/jetty-security/src/test/java/org/eclipse/jetty/security/ConstraintTest.java +++ b/jetty-security/src/test/java/org/eclipse/jetty/security/ConstraintTest.java @@ -423,7 +423,7 @@ public class ConstraintTest assertEquals(1, uncoveredPaths.size()); assertThat("/user/*", is(in(uncoveredPaths))); - //Test an explicitly named method with a http-method-omission to cover all other methods + //Test an explicitly named method with an http-method-omission to cover all other methods Constraint constraint2a = new Constraint(); constraint2a.setAuthenticate(true); constraint2a.setName("forbid constraint"); @@ -437,7 +437,7 @@ public class ConstraintTest assertNotNull(uncoveredPaths); assertEquals(0, uncoveredPaths.size()); - //Test a http-method-omission only + //Test an http-method-omission only Constraint constraint3 = new Constraint(); constraint3.setAuthenticate(true); constraint3.setName("omit constraint"); diff --git a/jetty-server/src/main/config/etc/jetty-http.xml b/jetty-server/src/main/config/etc/jetty-http.xml index 13b74d5be96..e93bb68dfc1 100644 --- a/jetty-server/src/main/config/etc/jetty-http.xml +++ b/jetty-server/src/main/config/etc/jetty-http.xml @@ -1,10 +1,10 @@ - +Listener for {@link HttpChannel} events.
*HttpChannel will emit events for the various phases it goes through while - * processing a HTTP request and response.
+ * processing an HTTP request and response. *Implementations of this interface may listen to those events to track * timing and/or other values such as request URI, etc.
*The events parameters, especially the {@link Request} object, may be diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java index b4e88f029ee..3d12c04f1eb 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java @@ -44,7 +44,7 @@ import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; /** - * A HttpChannel customized to be transported over the HTTP/1 protocol + * An HttpChannel customized to be transported over the HTTP/1 protocol */ public class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandler, HttpParser.ComplianceHandler { @@ -411,7 +411,7 @@ public class HttpChannelOverHttp extends HttpChannel implements HttpParser.Reque } /** - *
Attempts to perform a HTTP/1.1 upgrade.
+ *Attempts to perform an HTTP/1.1 upgrade.
*The upgrade looks up a {@link ConnectionFactory.Upgrading} from the connector * matching the protocol specified in the {@code Upgrade} header.
*The upgrade may succeed, be ignored (which can allow a later handler to implement) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java index 9aa9b62fcc8..e5bd93fde16 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java @@ -39,7 +39,7 @@ import org.eclipse.jetty.util.log.Logger; /** * HTTP Configuration. *
This class is a holder of HTTP configuration for use by the - * {@link HttpChannel} class. Typically a HTTPConfiguration instance + * {@link HttpChannel} class. Typically an HTTPConfiguration instance * is instantiated and passed to a {@link ConnectionFactory} that can * create HTTP channels (e.g. HTTP, AJP or FCGI).
*The configuration held by this class is not for the wire protocol, @@ -184,19 +184,19 @@ public class HttpConfiguration implements Dumpable return _outputAggregationSize; } - @ManagedAttribute("The maximum allowed size in bytes for a HTTP request header") + @ManagedAttribute("The maximum allowed size in bytes for an HTTP request header") public int getRequestHeaderSize() { return _requestHeaderSize; } - @ManagedAttribute("The maximum allowed size in bytes for a HTTP response header") + @ManagedAttribute("The maximum allowed size in bytes for an HTTP response header") public int getResponseHeaderSize() { return _responseHeaderSize; } - @ManagedAttribute("The maximum allowed size in bytes for a HTTP header field cache") + @ManagedAttribute("The maximum allowed size in bytes for an HTTP header field cache") public int getHeaderCacheSize() { return _headerCacheSize; @@ -221,20 +221,20 @@ public class HttpConfiguration implements Dumpable } /** - *
The max idle time is applied to a HTTP request for IO operations and + *
The max idle time is applied to an HTTP request for IO operations and * delayed dispatch.
* * @return the max idle time in ms or if == 0 implies an infinite timeout, <0 * implies no HTTP channel timeout and the connection timeout is used instead. */ - @ManagedAttribute("The idle timeout in ms for I/O operations during the handling of a HTTP request") + @ManagedAttribute("The idle timeout in ms for I/O operations during the handling of an HTTP request") public long getIdleTimeout() { return _idleTimeout; } /** - *The max idle time is applied to a HTTP request for IO operations and + *
The max idle time is applied to an HTTP request for IO operations and * delayed dispatch.
* * @param timeoutMs the max idle time in ms or if == 0 implies an infinite timeout, <0 diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/OptionalSslConnectionFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/OptionalSslConnectionFactory.java index 71b40c0fa82..41118eb081d 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/OptionalSslConnectionFactory.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/OptionalSslConnectionFactory.java @@ -95,7 +95,7 @@ public class OptionalSslConnectionFactory extends AbstractConnectionFactory int byte2 = buffer.get(1) & 0xFF; if (byte1 == 'G' && byte2 == 'E') { - // Plain text HTTP to a HTTPS port, + // Plain text HTTP to an HTTPS port, // write a minimal response. String body = "\r\n" + diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceContentFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceContentFactory.java index 95a9d83e533..b6d58845de1 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceContentFactory.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceContentFactory.java @@ -32,7 +32,7 @@ import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.ResourceFactory; /** - * A HttpContent.Factory for transient content (not cached). The HttpContent's created by + * An HttpContent.Factory for transient content (not cached). The HttpContent's created by * this factory are not intended to be cached, so memory limits for individual * HttpOutput streams are enforced. */ diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java index 04870c50949..1ef97d7286e 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java @@ -410,7 +410,7 @@ public class Response implements HttpServletResponse /** * Sends a 102-Processing response. - * If the connection is a HTTP connection, the version is 1.1 and the + * If the connection is an HTTP connection, the version is 1.1 and the * request has a Expect header starting with 102, then a 102 response is * sent. This indicates that the request still be processed and real response * can still be sent. This method is called by sendError if it is passed 102. diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ServletRequestHttpWrapper.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ServletRequestHttpWrapper.java index c754a656694..87c6b753317 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ServletRequestHttpWrapper.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ServletRequestHttpWrapper.java @@ -35,7 +35,7 @@ import javax.servlet.http.Part; /** * ServletRequestHttpWrapper * - * Class to tunnel a ServletRequest via a HttpServletRequest + * Class to tunnel a ServletRequest via an HttpServletRequest */ public class ServletRequestHttpWrapper extends ServletRequestWrapper implements HttpServletRequest { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ServletResponseHttpWrapper.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ServletResponseHttpWrapper.java index e3499962918..ff01136cc9c 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ServletResponseHttpWrapper.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ServletResponseHttpWrapper.java @@ -28,7 +28,7 @@ import javax.servlet.http.HttpServletResponse; /** * ServletResponseHttpWrapper * - * Wrapper to tunnel a ServletResponse via a HttpServletResponse + * Wrapper to tunnel a ServletResponse via an HttpServletResponse */ public class ServletResponseHttpWrapper extends ServletResponseWrapper implements HttpServletResponse { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java index 14700779b34..c46b31e342c 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java @@ -50,7 +50,7 @@ import org.eclipse.jetty.util.log.Logger; * Handler for Error pages * An ErrorHandler is registered with {@link ContextHandler#setErrorHandler(ErrorHandler)} or * {@link Server#setErrorHandler(ErrorHandler)}. - * It is called by the HttpResponse.sendError method to write a error page via {@link #handle(String, Request, HttpServletRequest, HttpServletResponse)} + * It is called by the HttpResponse.sendError method to write an error page via {@link #handle(String, Request, HttpServletRequest, HttpServletResponse)} * or via {@link #badMessageError(int, String, HttpFields)} for bad requests for which a dispatch cannot be done. */ public class ErrorHandler extends AbstractHandler @@ -467,7 +467,7 @@ public class ErrorHandler extends AbstractHandler /** * Bad Message Error body - *Generate a error response body to be sent for a bad message. + *
Generate an error response body to be sent for a bad message. * In this case there is something wrong with the request, so either * a request cannot be built, or it is not safe to build a request. * This method allows for a simple error page body to be returned diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ShutdownHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ShutdownHandler.java index ed5affa51c9..4665db27c89 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ShutdownHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ShutdownHandler.java @@ -38,7 +38,7 @@ import org.eclipse.jetty.util.log.Logger; * A handler that shuts the server down on a valid request. Used to do "soft" restarts from Java. * If _exitJvm is set to true a hard System.exit() call is being made. * If _sendShutdownAtStart is set to true, starting the server will try to shut down an existing server at the same port. - * If _sendShutdownAtStart is set to true, make a http call to + * If _sendShutdownAtStart is set to true, make an http call to * "http://localhost:" + port + "/shutdown?token=" + shutdownCookie * in order to shut down the server. * @@ -100,7 +100,7 @@ public class ShutdownHandler extends HandlerWrapper /** * @param shutdownToken a secret password to avoid unauthorized shutdown attempts * @param exitJVM If true, when the shutdown is executed, the handler class System.exit() - * @param sendShutdownAtStart If true, a shutdown is sent as a HTTP post + * @param sendShutdownAtStart If true, a shutdown is sent as an HTTP post * during startup, which will shutdown any previously running instances of * this server with an identically configured ShutdownHandler */ diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHttpInputInterceptor.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHttpInputInterceptor.java index 9fedb2b3938..c099e09abfd 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHttpInputInterceptor.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHttpInputInterceptor.java @@ -27,7 +27,7 @@ import org.eclipse.jetty.server.HttpInput.Content; import org.eclipse.jetty.util.component.Destroyable; /** - * A HttpInput Interceptor that inflates GZIP encoded request content. + * An HttpInput Interceptor that inflates GZIP encoded request content. */ public class GzipHttpInputInterceptor implements HttpInput.Interceptor, Destroyable { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/Session.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/Session.java index a14d5f5ab53..76d146b2ea3 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/Session.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/Session.java @@ -42,7 +42,7 @@ import org.eclipse.jetty.util.thread.Locker.Lock; /** * Session * - * A heavy-weight Session object representing a HttpSession. Session objects + * A heavy-weight Session object representing an HttpSession. Session objects * relating to a context are kept in a {@link SessionCache}. The purpose of the * SessionCache is to keep the working set of Session objects in memory so that * they may be accessed quickly, and facilitate the sharing of a Session object diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java index 89857621904..7c958c465eb 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java @@ -555,7 +555,7 @@ public class SessionHandler extends ScopedHandler /** * @return same as SessionCookieConfig.getSecure(). If true, session * cookies are ALWAYS marked as secure. If false, a session cookie is - * ONLY marked as secure if _secureRequestOnly == true and it is a HTTPS request. + * ONLY marked as secure if _secureRequestOnly == true and it is an HTTPS request. */ @ManagedAttribute("if true, secure cookie flag is set on session cookies") public boolean getSecureCookies() diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ForwardedRequestCustomizerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ForwardedRequestCustomizerTest.java index 03f4e9077e6..df8166b19a5 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ForwardedRequestCustomizerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ForwardedRequestCustomizerTest.java @@ -348,6 +348,18 @@ public class ForwardedRequestCustomizerTest .requestURL("http://myhost:2222/") .remoteAddr("[1:2:3:4:5:6:7:8]").remotePort(0) ), + Arguments.of(new Request("X-Forwarded-For and X-Forwarded-Port (multiple times combined)") + .headers( + "GET / HTTP/1.1", + "Host: myhost", + "X-Forwarded-Port: 2222, 3333", + "X-Forwarded-For: 1:2:3:4:5:6:7:8, 7:7:7:7:7:7:7:7" + ), + new Expectations() + .scheme("http").serverName("myhost").serverPort(2222) + .requestURL("http://myhost:2222/") + .remoteAddr("[1:2:3:4:5:6:7:8]").remotePort(0) + ), Arguments.of(new Request("X-Forwarded-Port") .headers( "GET / HTTP/1.1", diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/OptionalSslConnectionTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/OptionalSslConnectionTest.java index 267f00b977f..5164a007ceb 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/OptionalSslConnectionTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/OptionalSslConnectionTest.java @@ -111,7 +111,7 @@ public class OptionalSslConnectionTest assertEquals(HttpStatus.OK_200, response.getStatus()); } - // Then try a SSL connection. + // Then try an SSL connection. SslContextFactory sslContextFactory = new SslContextFactory.Client(true); sslContextFactory.start(); try (Socket ssl = sslContextFactory.newSslSocket()) diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ThreadStarvationTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ThreadStarvationTest.java index a145c2c2782..15b31826bf5 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ThreadStarvationTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ThreadStarvationTest.java @@ -362,7 +362,7 @@ public class ThreadStarvationTest byte[] content = new byte[BUFFER_SIZE]; { - // Using a character that will not show up in a HTTP response header + // Using a character that will not show up in an HTTP response header Arrays.fill(content, (byte)'!'); } diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/RequestURITest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/RequestURITest.java index adbb8abd27f..2f0195fa494 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/RequestURITest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/RequestURITest.java @@ -196,7 +196,7 @@ public class RequestURITest // Read the response. String response = readResponse(client); - // TODO: is HTTP/1.1 response appropriate for a HTTP/1.0 request? + // TODO: is HTTP/1.1 response appropriate for an HTTP/1.0 request? assertThat(response, Matchers.containsString("HTTP/1.1 200 OK")); assertThat(response, Matchers.containsString("RequestURI: " + expectedReqUri)); assertThat(response, Matchers.containsString("QueryString: " + expectedQuery)); diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java index d15f57dc3cc..45aa1b99637 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java @@ -489,7 +489,7 @@ public class DoSFilter implements Filter /** * Invoked when the request handling exceeds {@link #getMaxRequestMs()}. *
- * By default, a HTTP 503 response is returned and the handling thread is interrupted.
+ * By default, an HTTP 503 response is returned and the handling thread is interrupted.
*
* @param request the current request
* @param response the current response
diff --git a/jetty-unixsocket/src/main/config/modules/unixsocket-http.mod b/jetty-unixsocket/src/main/config/modules/unixsocket-http.mod
index e8f17427237..8d33f657fef 100644
--- a/jetty-unixsocket/src/main/config/modules/unixsocket-http.mod
+++ b/jetty-unixsocket/src/main/config/modules/unixsocket-http.mod
@@ -1,7 +1,7 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[description]
-Adds a HTTP protocol support to the Unix Domain Socket connector.
+Adds an HTTP protocol support to the Unix Domain Socket connector.
It should be used when a proxy is forwarding either HTTP or decrypted
HTTPS traffic to the connector and may be used with the
unix-socket-http2c modules to upgrade to HTTP/2.
diff --git a/jetty-unixsocket/src/main/config/modules/unixsocket-http2c.mod b/jetty-unixsocket/src/main/config/modules/unixsocket-http2c.mod
index 7de5cb019fb..f351a7a8849 100644
--- a/jetty-unixsocket/src/main/config/modules/unixsocket-http2c.mod
+++ b/jetty-unixsocket/src/main/config/modules/unixsocket-http2c.mod
@@ -1,7 +1,7 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[description]
-Adds a HTTP2C connetion factory to the Unix Domain Socket Connector
+Adds an HTTP2C connetion factory to the Unix Domain Socket Connector
It can be used when either the proxy forwards direct
HTTP/2C (unecrypted) or decrypted HTTP/2 traffic.
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/MathUtils.java b/jetty-util/src/main/java/org/eclipse/jetty/util/MathUtils.java
new file mode 100644
index 00000000000..6c522299b21
--- /dev/null
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/MathUtils.java
@@ -0,0 +1,46 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.util;
+
+public class MathUtils
+{
+ private MathUtils()
+ {
+ }
+
+ /**
+ * Returns whether the sum of the arguments overflows an {@code int}.
+ *
+ * @param a the first value
+ * @param b the second value
+ * @return whether the sum of the arguments overflows an {@code int}
+ */
+ public static boolean sumOverflows(int a, int b)
+ {
+ try
+ {
+ Math.addExact(a, b);
+ return false;
+ }
+ catch (ArithmeticException x)
+ {
+ return true;
+ }
+ }
+}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java
index b59b015fdfc..5cebbb37bf5 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java
@@ -367,7 +367,7 @@ public abstract class Resource implements ResourceFactory, Closeable
/**
* URL representing the resource.
*
- * @return an URL representing the given resource
+ * @return a URL representing the given resource
* @deprecated use {{@link #getURI()}.toURL() instead.
*/
@Deprecated
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/URLResource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/URLResource.java
index cc4916cac76..66c6734df8b 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/URLResource.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/URLResource.java
@@ -151,7 +151,7 @@ public class URLResource extends Resource
}
/**
- * Returns an URL representing the given resource
+ * Returns a URL representing the given resource
*/
@Override
public URL getURL()
diff --git a/jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/client/ClientCloseTest.java b/jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/client/ClientCloseTest.java
index 48bf207a93c..1c2bebb22ee 100644
--- a/jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/client/ClientCloseTest.java
+++ b/jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/client/ClientCloseTest.java
@@ -42,6 +42,7 @@ import org.eclipse.jetty.websocket.api.CloseException;
import org.eclipse.jetty.websocket.api.MessageTooLargeException;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.StatusCode;
+import org.eclipse.jetty.websocket.api.WebSocketException;
import org.eclipse.jetty.websocket.api.WebSocketFrameListener;
import org.eclipse.jetty.websocket.api.WebSocketListener;
import org.eclipse.jetty.websocket.api.extensions.Frame;
@@ -49,6 +50,8 @@ import org.eclipse.jetty.websocket.api.util.WSURI;
import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.eclipse.jetty.websocket.common.CloseInfo;
import org.eclipse.jetty.websocket.common.OpCode;
+import org.eclipse.jetty.websocket.common.WebSocketSession;
+import org.eclipse.jetty.websocket.common.WebSocketSessionListener;
import org.eclipse.jetty.websocket.server.NativeWebSocketServletContainerInitializer;
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
@@ -65,6 +68,8 @@ import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -350,6 +355,50 @@ public class ClientCloseTest
}
}
+ @Test
+ public void testStopWhileOpening() throws Exception
+ {
+ client.setMaxIdleTimeout(3000);
+ URI wsUri = WSURI.toWebsocket(server.getURI().resolve("/ws"));
+
+ CountDownLatch created = new CountDownLatch(1);
+ client.addSessionListener(new WebSocketSessionListener()
+ {
+ @Override
+ public void onSessionCreated(WebSocketSession session)
+ {
+ created.countDown();
+ try
+ {
+ Thread.sleep(2000);
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ });
+
+ // Client Request Upgrade
+ CloseTrackingEndpoint clientSocket = new CloseTrackingEndpoint();
+ client.connect(clientSocket, wsUri);
+
+ // wait for session to be created so that the session is added to session tracker but not opened
+ assertTrue(created.await(5, SECONDS));
+
+ // client lifecycle stop
+ assertDoesNotThrow(() -> client.stop());
+
+ // received shutdown error notification
+ assertTrue(clientSocket.errorLatch.await(1, SECONDS));
+ Throwable error = clientSocket.error.get();
+ assertThat(error, instanceOf(WebSocketException.class));
+ assertThat(error.getMessage(), is("Shutdown"));
+
+ // onOpen was never called
+ assertFalse(clientSocket.openLatch.await(1, SECONDS));
+ }
+
@Test
public void testWriteException() throws Exception
{
diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/util/WSURI.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/util/WSURI.java
index e48a2de056b..f8840f032da 100644
--- a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/util/WSURI.java
+++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/util/WSURI.java
@@ -25,7 +25,7 @@ import java.util.Objects;
// @checkstyle-disable-check : AbbreviationAsWordInNameCheck
/**
- * Utility methods for converting a {@link URI} between a HTTP(S) and WS(S) URI.
+ * Utility methods for converting a {@link URI} between an HTTP(S) and WS(S) URI.
*/
public final class WSURI
{
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/AbstractWebSocketConnection.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/AbstractWebSocketConnection.java
index fa100fe8ef3..003627a6b04 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/AbstractWebSocketConnection.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/AbstractWebSocketConnection.java
@@ -43,6 +43,7 @@ import org.eclipse.jetty.websocket.api.BatchMode;
import org.eclipse.jetty.websocket.api.CloseException;
import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.api.SuspendToken;
+import org.eclipse.jetty.websocket.api.WebSocketException;
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
import org.eclipse.jetty.websocket.api.WriteCallback;
import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
@@ -298,16 +299,24 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
{
if (connectionState.disconnected())
{
- /* Use prior Fatal Close Info if present, otherwise
- * because if could be from a failed close handshake where
- * the local initiated, but the remote never responded.
- */
- CloseInfo closeInfo = fatalCloseInfo;
- if (closeInfo == null)
+ if (connectionState.wasOpened())
{
- closeInfo = new CloseInfo(StatusCode.ABNORMAL, "Disconnected");
+ /* Use prior Fatal Close Info if present, otherwise
+ * because if could be from a failed close handshake where
+ * the local initiated, but the remote never responded.
+ */
+ CloseInfo closeInfo = fatalCloseInfo;
+ if (closeInfo == null)
+ {
+ closeInfo = new CloseInfo(StatusCode.ABNORMAL, "Disconnected");
+ }
+ session.callApplicationOnClose(closeInfo);
}
- session.callApplicationOnClose(closeInfo);
+ else
+ {
+ session.callApplicationOnError(new WebSocketException("Shutdown"));
+ }
+
if (LOG.isDebugEnabled())
{
LOG.debug("{} disconnect()", policy.getBehavior());
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/ConnectionState.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/ConnectionState.java
index 286ea8deea9..90a85117cca 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/ConnectionState.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/ConnectionState.java
@@ -18,6 +18,7 @@
package org.eclipse.jetty.websocket.common.io;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
/**
@@ -29,6 +30,7 @@ import java.util.concurrent.atomic.AtomicReference;
public class ConnectionState
{
private final AtomicReference