Merge branch 'jetty-9.4.x' into jetty-9.4.x-3989-selector-failure
This commit is contained in:
commit
0596d6c352
|
@ -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"
|
||||
|
|
|
@ -28,7 +28,7 @@ import org.eclipse.jetty.io.ClientConnectionFactory;
|
|||
* in order to plug-in a different transport for {@link HttpClient}.
|
||||
* <p>
|
||||
* While the {@link HttpClient} APIs define the HTTP semantic (request, response, headers, etc.)
|
||||
* <em>how</em> a HTTP exchange is carried over the network depends on implementations of this class.
|
||||
* <em>how</em> an HTTP exchange is carried over the network depends on implementations of this class.
|
||||
* <p>
|
||||
* 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,
|
||||
|
|
|
@ -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.
|
||||
* <p>
|
||||
* {@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()}
|
||||
|
|
|
@ -51,7 +51,7 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
* <ol>
|
||||
* <li>{@link #responseBegin(HttpExchange)}, when the HTTP response data containing the HTTP status code
|
||||
* is available</li>
|
||||
* <li>{@link #responseHeader(HttpExchange, HttpField)}, when a HTTP field is available</li>
|
||||
* <li>{@link #responseHeader(HttpExchange, HttpField)}, when an HTTP field is available</li>
|
||||
* <li>{@link #responseHeaders(HttpExchange)}, when all HTTP headers are available</li>
|
||||
* <li>{@link #responseContent(HttpExchange, ByteBuffer, Callback)}, when HTTP content is available</li>
|
||||
* <li>{@link #responseSuccess(HttpExchange)}, when the response is successful</li>
|
||||
|
|
|
@ -82,7 +82,7 @@ public class HttpRedirector
|
|||
|
||||
/**
|
||||
* @param response the response to check for redirects
|
||||
* @return whether the response code is a HTTP redirect code
|
||||
* @return whether the response code is an HTTP redirect code
|
||||
*/
|
||||
public boolean isRedirect(Response response)
|
||||
{
|
||||
|
|
|
@ -869,7 +869,7 @@ public class HttpRequest implements Request
|
|||
}
|
||||
catch (URISyntaxException x)
|
||||
{
|
||||
// The "path" of a HTTP request may not be a URI,
|
||||
// The "path" of an HTTP request may not be a URI,
|
||||
// for example for CONNECT 127.0.0.1:8080.
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ import org.eclipse.jetty.http.HttpVersion;
|
|||
import org.eclipse.jetty.util.Fields;
|
||||
|
||||
/**
|
||||
* <p>{@link Request} represents a HTTP request, and offers a fluent interface to customize
|
||||
* <p>{@link Request} represents an HTTP request, and offers a fluent interface to customize
|
||||
* various attributes such as the path, the headers, the content, etc.</p>
|
||||
* <p>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
|
||||
|
|
|
@ -29,7 +29,7 @@ import org.eclipse.jetty.http.HttpVersion;
|
|||
import org.eclipse.jetty.util.Callback;
|
||||
|
||||
/**
|
||||
* <p>{@link Response} represents a HTTP response and offers methods to retrieve status code, HTTP version
|
||||
* <p>{@link Response} represents an HTTP response and offers methods to retrieve status code, HTTP version
|
||||
* and headers.</p>
|
||||
* <p>{@link Response} objects are passed as parameters to {@link Response.Listener} callbacks, or as
|
||||
* future result of {@link Request#send()}.</p>
|
||||
|
|
|
@ -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).
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -26,7 +26,7 @@ import javax.servlet.ServletResponseWrapper;
|
|||
/**
|
||||
* Continuation.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* The continuation mechanism is a portable mechanism that will work
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<?xml version="1.0"?><!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
|
||||
<!-- ============================================================= --><!-- Configure the Jetty Server instance with an ID "Server" --><!-- by adding a HTTP connector. --><!-- This configuration must be used in conjunction with jetty.xml --><!-- ============================================================= -->
|
||||
<!-- ============================================================= --><!-- Configure the Jetty Server instance with an ID "Server" --><!-- by adding an HTTP connector. --><!-- This configuration must be used in conjunction with jetty.xml --><!-- ============================================================= -->
|
||||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- Add a HTTP Connector. -->
|
||||
<!-- Add an HTTP Connector. -->
|
||||
<!-- Configure an o.e.j.server.ServerConnector with a single -->
|
||||
<!-- HttpConnectionFactory instance using the common httpConfig -->
|
||||
<!-- instance defined in jetty.xml -->
|
||||
|
|
|
@ -743,7 +743,7 @@ If you are using Conscrypt with Java 8, you must exclude `TLSv1.3` protocol as i
|
|||
|
||||
==== Configuring SNI
|
||||
|
||||
From Java 8, the JVM contains support for the http://en.wikipedia.org/wiki/Server_Name_Indication[Server Name Indicator (SNI)] extension, which allows a SSL connection handshake to indicate one or more DNS names that it applies to.
|
||||
From Java 8, the JVM contains support for the http://en.wikipedia.org/wiki/Server_Name_Indication[Server Name Indicator (SNI)] extension, which allows an SSL connection handshake to indicate one or more DNS names that it applies to.
|
||||
|
||||
To support this, the `SslContextFactory` is used.
|
||||
The `SslContextFactory` will look for multiple X509 certificates within the keystore, each of which may have multiple DNS names (including wildcards) associated with the http://en.wikipedia.org/wiki/SubjectAltName[Subject Alternate Name] extension.
|
||||
|
|
|
@ -32,11 +32,14 @@ _____
|
|||
.Jetty Versions
|
||||
[width="100%",cols="12%,9%,15%,6%,21%,10%,6%,21%",options="header",]
|
||||
|=======================================================================
|
||||
|Version |Year |Home |JVM |Protocols |Servlet |JSP |Status
|
||||
|Version |Year |Home |Min JVM |Protocols |Servlet |JSP |Status
|
||||
|10 |2019- |Eclipse |11 ^(1)^ |HTTP/1.1 (RFC 7230), HTTP/2 (RFC 7540), WebSocket (RFC 6455, JSR 356), FastCGI |4.0.2 |2.3 |*UNSTABLE / Alpha*
|
||||
|9.4 |2016- |Eclipse |1.8 |HTTP/1.1 (RFC 7230), HTTP/2 (RFC 7540), WebSocket (RFC 6455, JSR 356), FastCGI |3.1 |2.3 |Stable
|
||||
|9.3 |2015- |Eclipse |1.8 |HTTP/1.1 (RFC 7230), HTTP/2 (RFC 7540), WebSocket (RFC 6455, JSR 356), FastCGI |3.1 |2.3 |Stable
|
||||
|9.2 |2014-2018 |Eclipse |1.7 |HTTP/1.1 RFC2616, javax.websocket, SPDY v3 |3.1 |2.3 |Deprecated / *End of Life January 2018*
|
||||
|8 |2009-2014 |Eclipse/Codehaus |1.6 |HTTP/1.1 RFC2616, WebSocket RFC 6455, SPDY v3 |3.0 |2.2 |Deprecated / *End of Life November 2014*
|
||||
|9.3 |2015- |Eclipse |1.8 ^(2)^ |HTTP/1.1 (RFC 7230), HTTP/2 (RFC 7540), WebSocket (RFC 6455, JSR 356), FastCGI |3.1 |2.3 |Stable
|
||||
|9.2 |2014-2018 |Eclipse |1.7 ^(2)^ |HTTP/1.1 RFC2616, javax.websocket, SPDY v3 |3.1 |2.3 |Deprecated / *End of Life January 2018*
|
||||
|9.1 |2013-2014 |Eclipse |1.7 ^(2)^ |HTTP/1.1 RFC2616 |3.1 |2.3 |Deprecated / *End of Life May 2014*
|
||||
|9.0 |2013-2013 |Eclipse |1.7 ^(2)^ |HTTP/1.1 RFC2616 |3.1-beta |2.3 |Deprecated / *End of Life November 2013*
|
||||
|8 |2009-2014 |Eclipse/Codehaus |1.6 ^(2)^ |HTTP/1.1 RFC2616, WebSocket RFC 6455, SPDY v3 |3.0 |2.2 |Deprecated / *End of Life November 2014*
|
||||
|7 |2008-2014 |Eclipse/Codehaus |1.5 |HTTP/1.1 RFC2616, WebSocket RFC 6455, SPDY v3 |2.5 |2.1 |Deprecated / *End of Life November 2014*
|
||||
|6 |2006-2010 |Codehaus |1.4-1.5 |HTTP/1.1 RFC2616 |2.5 |2.0 |Deprecated / *End of Life November 2010*
|
||||
|5 |2003-2009 |Sourceforge |1.2-1.5 |HTTP/1.1 RFC2616 |2.4 |2.0 |Antique
|
||||
|
@ -45,3 +48,6 @@ _____
|
|||
|2 |1998-2000 |Mortbay |1.1 |HTTP/1.0 RFC1945 |2.1 |1.0 |Legendary
|
||||
|1 |1995-1998 |Mortbay |1.0 |HTTP/1.0 RFC1945 |- |- |Mythical
|
||||
|=======================================================================
|
||||
|
||||
1. JPMS module support is optional
|
||||
2. JDK9 and newer is not supported if using MultiRelease JAR Files, or Bytecode / Annotation scanning.
|
|
@ -44,7 +44,7 @@ import org.eclipse.jetty.util.ProcessorUtils;
|
|||
/**
|
||||
* Specific implementation of {@link org.eclipse.jetty.proxy.AsyncProxyServlet.Transparent} for FastCGI.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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
|
||||
* <code>http://user@host:port/path/info;param?query#fragment</code>
|
||||
* this class will split it into the following undecoded optional elements:<ul>
|
||||
* <li>{@link #getScheme()} - http:</li>
|
||||
|
|
|
@ -42,12 +42,12 @@ public enum HttpVersion
|
|||
}
|
||||
|
||||
/**
|
||||
* Optimised lookup to find a Http Version and whitespace in a byte array.
|
||||
* Optimised lookup to find an Http Version and whitespace in a byte array.
|
||||
*
|
||||
* @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 HttpVersion lookAheadGet(byte[] bytes, int position, int limit)
|
||||
{
|
||||
|
@ -84,10 +84,10 @@ public enum HttpVersion
|
|||
}
|
||||
|
||||
/**
|
||||
* Optimised lookup to find a HTTP Version and trailing white space in a byte array.
|
||||
* Optimised lookup to find an HTTP Version and trailing white space in a byte array.
|
||||
*
|
||||
* @param buffer buffer containing ISO-8859-1 characters
|
||||
* @return A HttpVersion if a match or null if no easy match.
|
||||
* @return An HttpVersion if a match or null if no easy match.
|
||||
*/
|
||||
public static HttpVersion lookAheadGet(ByteBuffer buffer)
|
||||
{
|
||||
|
|
|
@ -29,7 +29,7 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
|
||||
/**
|
||||
* Pre encoded HttpField.
|
||||
* <p>A HttpField that will be cached and used many times can be created as
|
||||
* <p>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
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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:
|
||||
* <pre>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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),
|
||||
/**
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -30,7 +30,7 @@ import org.eclipse.jetty.util.Callback;
|
|||
import org.eclipse.jetty.util.Promise;
|
||||
|
||||
/**
|
||||
* <p>The SPI interface for implementing a HTTP/2 session.</p>
|
||||
* <p>The SPI interface for implementing an HTTP/2 session.</p>
|
||||
* <p>This class extends {@link Session} by adding the methods required to
|
||||
* implement the HTTP/2 session functionalities.</p>
|
||||
*/
|
||||
|
|
|
@ -25,7 +25,7 @@ import org.eclipse.jetty.http2.frames.Frame;
|
|||
import org.eclipse.jetty.util.Callback;
|
||||
|
||||
/**
|
||||
* <p>The SPI interface for implementing a HTTP/2 stream.</p>
|
||||
* <p>The SPI interface for implementing an HTTP/2 stream.</p>
|
||||
* <p>This class extends {@link Stream} by adding the methods required to
|
||||
* implement the HTTP/2 stream functionalities.</p>
|
||||
*/
|
||||
|
|
|
@ -32,7 +32,7 @@ import org.eclipse.jetty.util.Callback;
|
|||
import org.eclipse.jetty.util.Promise;
|
||||
|
||||
/**
|
||||
* <p>A {@link Session} represents the client-side endpoint of a HTTP/2 connection to a single origin server.</p>
|
||||
* <p>A {@link Session} represents the client-side endpoint of an HTTP/2 connection to a single origin server.</p>
|
||||
* <p>Once a {@link Session} has been obtained, it can be used to open HTTP/2 streams:</p>
|
||||
* <pre>
|
||||
* Session session = ...;
|
||||
|
@ -127,7 +127,7 @@ public interface Session
|
|||
|
||||
/**
|
||||
* <p>A {@link Listener} is the passive counterpart of a {@link Session} and
|
||||
* receives events happening on a HTTP/2 connection.</p>
|
||||
* receives events happening on an HTTP/2 connection.</p>
|
||||
*
|
||||
* @see Session
|
||||
*/
|
||||
|
@ -151,9 +151,9 @@ public interface Session
|
|||
|
||||
/**
|
||||
* <p>Callback method invoked when a new stream is being created upon
|
||||
* receiving a HEADERS frame representing a HTTP request.</p>
|
||||
* receiving a HEADERS frame representing an HTTP request.</p>
|
||||
* <p>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)}.</p>
|
||||
* <p>Applications can detect whether request DATA frames will be arriving
|
||||
* by testing {@link HeadersFrame#isEndStream()}. If the application is
|
||||
|
|
|
@ -29,8 +29,8 @@ import org.eclipse.jetty.util.Promise;
|
|||
* <p>A {@link Stream} represents a bidirectional exchange of data on top of a {@link Session}.</p>
|
||||
* <p>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.</p>
|
||||
* <p>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.</p>
|
||||
* <p>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.</p>
|
||||
* <p>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();
|
||||
|
||||
/**
|
||||
* <p>Sends the given HEADERS {@code frame} representing a HTTP response.</p>
|
||||
* <p>Sends the given HEADERS {@code frame} representing an HTTP response.</p>
|
||||
*
|
||||
* @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
|
|||
|
||||
/**
|
||||
* <p>A {@link Stream.Listener} is the passive counterpart of a {@link Stream} and receives
|
||||
* events happening on a HTTP/2 stream.</p>
|
||||
* events happening on an HTTP/2 stream.</p>
|
||||
*
|
||||
* @see Stream
|
||||
*/
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -42,7 +42,7 @@ public class PrefaceParser
|
|||
* <p>Advances this parser after the {@link PrefaceFrame#PREFACE_PREAMBLE_BYTES}.</p>
|
||||
* <p>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.</p>
|
||||
* bytes, that are not parseable by an HTTP/1.1 parser.</p>
|
||||
*/
|
||||
protected void directUpgrade()
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
* <p>Applications should call this method when they want to signal an
|
||||
* event that is subject to rate control.</p>
|
||||
* <p>Implementations should return true if the event does not exceed
|
||||
* the desired rate, or false to signal that the event exceeded the
|
||||
* desired rate.</p>
|
||||
*
|
||||
* @param event the event subject to rate control.
|
||||
* @return true IFF the rate is within limits
|
||||
*/
|
||||
public boolean onEvent(Object event);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 AtomicReference<SettingsFrame> frameRef = new AtomicReference<>();
|
||||
SettingsBodyParser parser = new SettingsBodyParser(null, null)
|
||||
AtomicReference<SettingsFrame> frameRef = new AtomicReference<>();
|
||||
SettingsBodyParser parser = new SettingsBodyParser(new HeaderParser(RateControl.NO_RATE_CONTROL), new Parser.Listener.Adapter()
|
||||
{
|
||||
@Override
|
||||
protected int getStreamId()
|
||||
public void onSettings(SettingsFrame frame)
|
||||
{
|
||||
return 0;
|
||||
frameRef.set(frame);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getBodyLength()
|
||||
{
|
||||
return bodyLength;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onSettings(ByteBuffer buffer, Map<Integer, Integer> settings)
|
||||
{
|
||||
frameRef.set(new SettingsFrame(settings, false));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean connectionFailure(ByteBuffer buffer, int error, String reason)
|
||||
public void onConnectionFailure(int error, String reason)
|
||||
{
|
||||
frameRef.set(null);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
if (bodyLength == 0)
|
||||
parser.emptyBody(buffer);
|
||||
else
|
||||
});
|
||||
if (buffer.hasRemaining())
|
||||
parser.parse(buffer);
|
||||
else
|
||||
parser.emptyBody(buffer);
|
||||
return frameRef.get();
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,9 @@ package org.eclipse.jetty.http2.parser;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.http2.ErrorCode;
|
||||
import org.eclipse.jetty.http2.frames.UnknownFrame;
|
||||
|
||||
public class UnknownBodyParser extends BodyParser
|
||||
{
|
||||
private int cursor;
|
||||
|
@ -34,7 +37,11 @@ public class UnknownBodyParser extends BodyParser
|
|||
{
|
||||
int length = cursor == 0 ? getBodyLength() : cursor;
|
||||
cursor = consume(buffer, length);
|
||||
return cursor == 0;
|
||||
boolean parsed = cursor == 0;
|
||||
if (parsed && !rateControlOnEvent(new UnknownFrame(getFrameType())))
|
||||
return connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_unknown_frame_rate");
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
private int consume(ByteBuffer buffer, int length)
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* <p>An implementation of {@link RateControl} that limits the number of
|
||||
* events within a time period.</p>
|
||||
* <p>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}.</p>
|
||||
*/
|
||||
public class WindowRateControl implements RateControl
|
||||
{
|
||||
private final Queue<Long> events = new ConcurrentLinkedQueue<>();
|
||||
private final AtomicInteger size = new AtomicInteger();
|
||||
private final int maxEvents;
|
||||
private final long window;
|
||||
|
||||
public WindowRateControl(int maxEvents, Duration window)
|
||||
{
|
||||
this.maxEvents = maxEvents;
|
||||
this.window = window.toNanos();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onEvent(Object event)
|
||||
{
|
||||
long now = System.nanoTime();
|
||||
while (true)
|
||||
{
|
||||
Long time = events.peek();
|
||||
if (time == null)
|
||||
break;
|
||||
if (now < time)
|
||||
break;
|
||||
if (events.remove(time))
|
||||
size.decrementAndGet();
|
||||
}
|
||||
events.add(now + window);
|
||||
return size.incrementAndGet() <= maxEvents;
|
||||
}
|
||||
}
|
|
@ -61,7 +61,7 @@ public class WindowUpdateBodyParser extends BodyParser
|
|||
if (buffer.remaining() >= 4)
|
||||
{
|
||||
windowDelta = buffer.getInt() & 0x7F_FF_FF_FF;
|
||||
return onWindowUpdate(windowDelta);
|
||||
return onWindowUpdate(buffer, windowDelta);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -78,7 +78,7 @@ public class WindowUpdateBodyParser extends BodyParser
|
|||
if (cursor == 0)
|
||||
{
|
||||
windowDelta &= 0x7F_FF_FF_FF;
|
||||
return onWindowUpdate(windowDelta);
|
||||
return onWindowUpdate(buffer, windowDelta);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -91,9 +91,17 @@ public class WindowUpdateBodyParser extends BodyParser
|
|||
return false;
|
||||
}
|
||||
|
||||
private boolean onWindowUpdate(int windowDelta)
|
||||
private boolean onWindowUpdate(ByteBuffer buffer, int windowDelta)
|
||||
{
|
||||
WindowUpdateFrame frame = new WindowUpdateFrame(getStreamId(), windowDelta);
|
||||
int streamId = getStreamId();
|
||||
if (windowDelta == 0)
|
||||
{
|
||||
if (streamId == 0)
|
||||
return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_window_update_frame");
|
||||
else
|
||||
return streamFailure(streamId, ErrorCode.PROTOCOL_ERROR.code, "invalid_window_update_frame");
|
||||
}
|
||||
WindowUpdateFrame frame = new WindowUpdateFrame(streamId, windowDelta);
|
||||
reset();
|
||||
notifyWindowUpdate(frame);
|
||||
return true;
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.http.MetaData;
|
||||
import org.eclipse.jetty.http2.Flags;
|
||||
import org.eclipse.jetty.http2.hpack.HpackEncoder;
|
||||
import org.eclipse.jetty.http2.parser.Parser;
|
||||
import org.eclipse.jetty.http2.parser.WindowRateControl;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.MappedByteBufferPool;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.lessThan;
|
||||
|
||||
public class FrameFloodTest
|
||||
{
|
||||
private final ByteBufferPool byteBufferPool = new MappedByteBufferPool();
|
||||
|
||||
// Frame structure:
|
||||
// | Len0 | Len1 | Len2 | Type | Flags | StreamID0 |StreamID1 |StreamID2 |StreamID3 | Payload... |
|
||||
|
||||
private byte[] frameFrom(int length, int frameType, int flags, int streamId, byte[] payload)
|
||||
{
|
||||
byte[] result = new byte[3 + 1 + 1 + 4 + payload.length];
|
||||
result[0] = (byte)((length >>> 16) & 0xFF);
|
||||
result[1] = (byte)((length >>> 8) & 0xFF);
|
||||
result[2] = (byte)(length & 0xFF);
|
||||
result[3] = (byte)frameType;
|
||||
result[4] = (byte)flags;
|
||||
result[5] = (byte)((streamId >>> 24) & 0xFF);
|
||||
result[6] = (byte)((streamId >>> 16) & 0xFF);
|
||||
result[7] = (byte)((streamId >>> 8) & 0xFF);
|
||||
result[8] = (byte)(streamId & 0xFF);
|
||||
System.arraycopy(payload, 0, result, 9, payload.length);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDataFrameFlood()
|
||||
{
|
||||
byte[] payload = new byte[0];
|
||||
testFrameFlood(null, frameFrom(payload.length, FrameType.DATA.getType(), 0, 13, payload));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHeadersFrameFlood()
|
||||
{
|
||||
byte[] payload = new byte[0];
|
||||
testFrameFlood(null, frameFrom(payload.length, FrameType.HEADERS.getType(), Flags.END_HEADERS, 13, payload));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidHeadersFrameFlood()
|
||||
{
|
||||
// Invalid MetaData (no method, no scheme, etc).
|
||||
MetaData.Request metadata = new MetaData.Request(null, (String)null, null, null, HttpVersion.HTTP_2, null, -1);
|
||||
HpackEncoder encoder = new HpackEncoder();
|
||||
ByteBuffer buffer = ByteBuffer.allocate(1024);
|
||||
encoder.encode(buffer, metadata);
|
||||
buffer.flip();
|
||||
byte[] payload = new byte[buffer.remaining()];
|
||||
buffer.get(payload);
|
||||
testFrameFlood(null, frameFrom(payload.length, FrameType.HEADERS.getType(), Flags.END_HEADERS, 13, payload));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPriorityFrameFlood()
|
||||
{
|
||||
byte[] payload = new byte[]{0, 0, 0, 7, 0};
|
||||
testFrameFlood(null, frameFrom(payload.length, FrameType.PRIORITY.getType(), 0, 13, payload));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSettingsFrameFlood()
|
||||
{
|
||||
byte[] payload = new byte[0];
|
||||
testFrameFlood(null, frameFrom(payload.length, FrameType.SETTINGS.getType(), 0, 0, payload));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPingFrameFlood()
|
||||
{
|
||||
byte[] payload = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
testFrameFlood(null, frameFrom(payload.length, FrameType.PING.getType(), 0, 0, payload));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContinuationFrameFlood()
|
||||
{
|
||||
int streamId = 13;
|
||||
byte[] headersPayload = new byte[0];
|
||||
byte[] headersBytes = frameFrom(headersPayload.length, FrameType.HEADERS.getType(), 0, streamId, headersPayload);
|
||||
byte[] continuationPayload = new byte[0];
|
||||
testFrameFlood(headersBytes, frameFrom(continuationPayload.length, FrameType.CONTINUATION.getType(), 0, streamId, continuationPayload));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnknownFrameFlood()
|
||||
{
|
||||
byte[] payload = {0, 0, 0, 0};
|
||||
testFrameFlood(null, frameFrom(payload.length, 64, 0, 0, payload));
|
||||
}
|
||||
|
||||
private void testFrameFlood(byte[] preamble, byte[] bytes)
|
||||
{
|
||||
AtomicBoolean failed = new AtomicBoolean();
|
||||
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public void onConnectionFailure(int error, String reason)
|
||||
{
|
||||
failed.set(true);
|
||||
}
|
||||
}, 4096, 8192, new WindowRateControl(8, Duration.ofSeconds(1)));
|
||||
parser.init(UnaryOperator.identity());
|
||||
|
||||
if (preamble != null)
|
||||
{
|
||||
ByteBuffer buffer = ByteBuffer.wrap(preamble);
|
||||
while (buffer.hasRemaining())
|
||||
{
|
||||
parser.parse(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
while (!failed.get())
|
||||
{
|
||||
ByteBuffer buffer = ByteBuffer.wrap(bytes);
|
||||
while (buffer.hasRemaining())
|
||||
{
|
||||
parser.parse(buffer);
|
||||
}
|
||||
assertThat("too many frames allowed", ++count, lessThan(1024));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,6 +22,7 @@ import java.nio.ByteBuffer;
|
|||
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpTokens;
|
||||
import org.eclipse.jetty.http.MetaData;
|
||||
import org.eclipse.jetty.http2.hpack.HpackContext.Entry;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
|
@ -175,14 +176,35 @@ public class HpackDecoder
|
|||
name = Huffman.decode(buffer, length);
|
||||
else
|
||||
name = toASCIIString(buffer, length);
|
||||
for (int i = 0; i < name.length(); i++)
|
||||
check:
|
||||
for (int i = name.length(); i-- > 0;)
|
||||
{
|
||||
char c = name.charAt(i);
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
if (c > 0xff)
|
||||
{
|
||||
_builder.streamException("Uppercase header name %s", name);
|
||||
_builder.streamException("Illegal header name %s", name);
|
||||
break;
|
||||
}
|
||||
HttpTokens.Token token = HttpTokens.TOKENS[0xFF & c];
|
||||
switch (token.getType())
|
||||
{
|
||||
case ALPHA:
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
{
|
||||
_builder.streamException("Uppercase header name %s", name);
|
||||
break check;
|
||||
}
|
||||
break;
|
||||
|
||||
case COLON:
|
||||
case TCHAR:
|
||||
case DIGIT:
|
||||
break;
|
||||
|
||||
default:
|
||||
_builder.streamException("Illegal header name %s", name);
|
||||
break check;
|
||||
}
|
||||
}
|
||||
header = HttpHeader.CACHE.get(name);
|
||||
}
|
||||
|
|
|
@ -74,11 +74,13 @@ public class MetaDataBuilder
|
|||
{
|
||||
HttpHeader header = field.getHeader();
|
||||
String name = field.getName();
|
||||
if (name == null || name.length() == 0)
|
||||
throw new HpackException.SessionException("Header size 0");
|
||||
String value = field.getValue();
|
||||
int fieldSize = name.length() + (value == null ? 0 : value.length());
|
||||
_size += fieldSize + 32;
|
||||
if (_size > _maxSize)
|
||||
throw new HpackException.SessionException("Header Size %d > %d", _size, _maxSize);
|
||||
throw new HpackException.SessionException("Header size %d > %d", _size, _maxSize);
|
||||
|
||||
if (field instanceof StaticTableHttpField)
|
||||
{
|
||||
|
@ -113,7 +115,7 @@ public class MetaDataBuilder
|
|||
{
|
||||
case C_STATUS:
|
||||
if (checkPseudoHeader(header, _status))
|
||||
_status = Integer.valueOf(field.getIntValue());
|
||||
_status = field.getIntValue();
|
||||
_response = true;
|
||||
break;
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.eclipse.jetty.http.HttpHeader;
|
|||
import org.eclipse.jetty.http.HttpScheme;
|
||||
import org.eclipse.jetty.http.MetaData;
|
||||
import org.eclipse.jetty.http2.hpack.HpackException.CompressionException;
|
||||
import org.eclipse.jetty.http2.hpack.HpackException.SessionException;
|
||||
import org.eclipse.jetty.http2.hpack.HpackException.StreamException;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.hamcrest.Matchers;
|
||||
|
@ -43,6 +44,21 @@ import static org.junit.jupiter.api.Assertions.fail;
|
|||
|
||||
public class HpackDecoderTest
|
||||
{
|
||||
/*
|
||||
0 1 2 3 4 5 6 7
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| 0 | 0 | 0 | 0 | 0 |
|
||||
+---+---+-----------------------+
|
||||
| H | Name Length (7+) |
|
||||
+---+---------------------------+
|
||||
| Name String (Length octets) |
|
||||
+---+---------------------------+
|
||||
| H | Value Length (7+) |
|
||||
+---+---------------------------+
|
||||
| Value String (Length octets) |
|
||||
+-------------------------------+
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testDecodeD_3() throws Exception
|
||||
{
|
||||
|
@ -253,14 +269,14 @@ public class HpackDecoderTest
|
|||
decoder.decode(buffer);
|
||||
fail();
|
||||
}
|
||||
catch (HpackException.SessionException e)
|
||||
catch (SessionException e)
|
||||
{
|
||||
assertThat(e.getMessage(), Matchers.startsWith("Unknown index"));
|
||||
}
|
||||
}
|
||||
|
||||
/* 8.1.2.1. Pseudo-Header Fields */
|
||||
@Test()
|
||||
@Test
|
||||
public void test8_1_2_1_PsuedoHeaderFields() throws Exception
|
||||
{
|
||||
// 1:Sends a HEADERS frame that contains a unknown pseudo-header field
|
||||
|
@ -312,7 +328,7 @@ public class HpackDecoderTest
|
|||
}
|
||||
}
|
||||
|
||||
@Test()
|
||||
@Test
|
||||
public void test8_1_2_2_ConnectionSpecificHeaderFields() throws Exception
|
||||
{
|
||||
MetaDataBuilder mdb;
|
||||
|
@ -349,7 +365,7 @@ public class HpackDecoderTest
|
|||
assertNotNull(mdb.build());
|
||||
}
|
||||
|
||||
@Test()
|
||||
@Test
|
||||
public void test8_1_2_3_RequestPseudoHeaderFields() throws Exception
|
||||
{
|
||||
{
|
||||
|
@ -368,7 +384,7 @@ public class HpackDecoderTest
|
|||
mdb.emit(new HttpField(HttpHeader.C_SCHEME, "http"));
|
||||
mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost:8080"));
|
||||
mdb.emit(new HttpField(HttpHeader.C_PATH, ""));
|
||||
StreamException ex = assertThrows(StreamException.class, () -> mdb.build());
|
||||
StreamException ex = assertThrows(StreamException.class, mdb::build);
|
||||
assertThat(ex.getMessage(), Matchers.containsString("No Path"));
|
||||
}
|
||||
|
||||
|
@ -378,7 +394,7 @@ public class HpackDecoderTest
|
|||
mdb.emit(new HttpField(HttpHeader.C_SCHEME, "http"));
|
||||
mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost:8080"));
|
||||
mdb.emit(new HttpField(HttpHeader.C_PATH, "/"));
|
||||
StreamException ex = assertThrows(StreamException.class, () -> mdb.build());
|
||||
StreamException ex = assertThrows(StreamException.class, mdb::build);
|
||||
assertThat(ex.getMessage(), Matchers.containsString("No Method"));
|
||||
}
|
||||
|
||||
|
@ -388,7 +404,7 @@ public class HpackDecoderTest
|
|||
mdb.emit(new HttpField(HttpHeader.C_METHOD, "GET"));
|
||||
mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost:8080"));
|
||||
mdb.emit(new HttpField(HttpHeader.C_PATH, "/"));
|
||||
StreamException ex = assertThrows(StreamException.class, () -> mdb.build());
|
||||
StreamException ex = assertThrows(StreamException.class, mdb::build);
|
||||
assertThat(ex.getMessage(), Matchers.containsString("No Scheme"));
|
||||
}
|
||||
|
||||
|
@ -398,7 +414,7 @@ public class HpackDecoderTest
|
|||
mdb.emit(new HttpField(HttpHeader.C_METHOD, "GET"));
|
||||
mdb.emit(new HttpField(HttpHeader.C_SCHEME, "http"));
|
||||
mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost:8080"));
|
||||
StreamException ex = assertThrows(StreamException.class, () -> mdb.build());
|
||||
StreamException ex = assertThrows(StreamException.class, mdb::build);
|
||||
assertThat(ex.getMessage(), Matchers.containsString("No Path"));
|
||||
}
|
||||
|
||||
|
@ -410,7 +426,7 @@ public class HpackDecoderTest
|
|||
mdb.emit(new HttpField(HttpHeader.C_SCHEME, "http"));
|
||||
mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost:8080"));
|
||||
mdb.emit(new HttpField(HttpHeader.C_PATH, "/"));
|
||||
StreamException ex = assertThrows(StreamException.class, () -> mdb.build());
|
||||
StreamException ex = assertThrows(StreamException.class, mdb::build);
|
||||
assertThat(ex.getMessage(), Matchers.containsString("Duplicate"));
|
||||
}
|
||||
|
||||
|
@ -423,12 +439,12 @@ public class HpackDecoderTest
|
|||
mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost:8080"));
|
||||
mdb.emit(new HttpField(HttpHeader.C_PATH, "/"));
|
||||
|
||||
StreamException ex = assertThrows(StreamException.class, () -> mdb.build());
|
||||
StreamException ex = assertThrows(StreamException.class, mdb::build);
|
||||
assertThat(ex.getMessage(), Matchers.containsString("Duplicate"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test()
|
||||
@Test
|
||||
public void testHuffmanEncodedStandard() throws Exception
|
||||
{
|
||||
HpackDecoder decoder = new HpackDecoder(4096, 8192);
|
||||
|
@ -446,8 +462,8 @@ public class HpackDecoderTest
|
|||
}
|
||||
|
||||
/* 5.2.1: Sends a Huffman-encoded string literal representation with padding longer than 7 bits */
|
||||
@Test()
|
||||
public void testHuffmanEncodedExtraPadding() throws Exception
|
||||
@Test
|
||||
public void testHuffmanEncodedExtraPadding()
|
||||
{
|
||||
HpackDecoder decoder = new HpackDecoder(4096, 8192);
|
||||
|
||||
|
@ -458,8 +474,8 @@ public class HpackDecoderTest
|
|||
}
|
||||
|
||||
/* 5.2.2: Sends a Huffman-encoded string literal representation padded by zero */
|
||||
@Test()
|
||||
public void testHuffmanEncodedZeroPadding() throws Exception
|
||||
@Test
|
||||
public void testHuffmanEncodedZeroPadding()
|
||||
{
|
||||
HpackDecoder decoder = new HpackDecoder(4096, 8192);
|
||||
|
||||
|
@ -471,8 +487,8 @@ public class HpackDecoderTest
|
|||
}
|
||||
|
||||
/* 5.2.3: Sends a Huffman-encoded string literal representation containing the EOS symbol */
|
||||
@Test()
|
||||
public void testHuffmanEncodedWithEOS() throws Exception
|
||||
@Test
|
||||
public void testHuffmanEncodedWithEOS()
|
||||
{
|
||||
HpackDecoder decoder = new HpackDecoder(4096, 8192);
|
||||
|
||||
|
@ -483,8 +499,8 @@ public class HpackDecoderTest
|
|||
assertThat(ex.getMessage(), Matchers.containsString("EOS in content"));
|
||||
}
|
||||
|
||||
@Test()
|
||||
public void testHuffmanEncodedOneIncompleteOctet() throws Exception
|
||||
@Test
|
||||
public void testHuffmanEncodedOneIncompleteOctet()
|
||||
{
|
||||
HpackDecoder decoder = new HpackDecoder(4096, 8192);
|
||||
|
||||
|
@ -495,8 +511,8 @@ public class HpackDecoderTest
|
|||
assertThat(ex.getMessage(), Matchers.containsString("Bad termination"));
|
||||
}
|
||||
|
||||
@Test()
|
||||
public void testHuffmanEncodedTwoIncompleteOctet() throws Exception
|
||||
@Test
|
||||
public void testHuffmanEncodedTwoIncompleteOctet()
|
||||
{
|
||||
HpackDecoder decoder = new HpackDecoder(4096, 8192);
|
||||
|
||||
|
@ -506,4 +522,49 @@ public class HpackDecoderTest
|
|||
CompressionException ex = assertThrows(CompressionException.class, () -> decoder.decode(buffer));
|
||||
assertThat(ex.getMessage(), Matchers.containsString("Bad termination"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testZeroLengthName()
|
||||
{
|
||||
HpackDecoder decoder = new HpackDecoder(4096, 8192);
|
||||
|
||||
String encoded = "00000130";
|
||||
ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
|
||||
SessionException ex = assertThrows(SessionException.class, () -> decoder.decode(buffer));
|
||||
assertThat(ex.getMessage(), Matchers.containsString("Header size 0"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testZeroLengthValue() throws Exception
|
||||
{
|
||||
HpackDecoder decoder = new HpackDecoder(4096, 8192);
|
||||
|
||||
String encoded = "00016800";
|
||||
ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
|
||||
MetaData metaData = decoder.decode(buffer);
|
||||
assertThat(metaData.getFields().size(), is(1));
|
||||
assertThat(metaData.getFields().get("h"), is(""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpperCaseName()
|
||||
{
|
||||
HpackDecoder decoder = new HpackDecoder(4096, 8192);
|
||||
|
||||
String encoded = "0001480130";
|
||||
ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
|
||||
StreamException ex = assertThrows(StreamException.class, () -> decoder.decode(buffer));
|
||||
assertThat(ex.getMessage(), Matchers.containsString("Uppercase header"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWhiteSpaceName()
|
||||
{
|
||||
HpackDecoder decoder = new HpackDecoder(4096, 8192);
|
||||
|
||||
String encoded = "0001200130";
|
||||
ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
|
||||
StreamException ex = assertThrows(StreamException.class, () -> decoder.decode(buffer));
|
||||
assertThat(ex.getMessage(), Matchers.containsString("Illegal header"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.http2.client.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.ServerSocket;
|
||||
|
@ -38,7 +37,6 @@ import java.util.concurrent.TimeoutException;
|
|||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.UnaryOperator;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
|
@ -63,6 +61,7 @@ import org.eclipse.jetty.http2.frames.HeadersFrame;
|
|||
import org.eclipse.jetty.http2.frames.ResetFrame;
|
||||
import org.eclipse.jetty.http2.frames.SettingsFrame;
|
||||
import org.eclipse.jetty.http2.generator.Generator;
|
||||
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.io.ByteBufferPool;
|
||||
|
@ -187,7 +186,7 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest
|
|||
start(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
HttpVersion version = HttpVersion.fromString(request.getProtocol());
|
||||
|
@ -199,7 +198,7 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest
|
|||
.onRequestBegin(request ->
|
||||
{
|
||||
if (request.getVersion() != HttpVersion.HTTP_2)
|
||||
request.abort(new Exception("Not a HTTP/2 request"));
|
||||
request.abort(new Exception("Not an HTTP/2 request"));
|
||||
})
|
||||
.send();
|
||||
|
||||
|
@ -313,7 +312,7 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest
|
|||
start(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
assertEquals(path, request.getRequestURI());
|
||||
|
@ -337,7 +336,7 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest
|
|||
start(new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
assertEquals(path, request.getRequestURI());
|
||||
|
@ -501,7 +500,7 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest
|
|||
x.printStackTrace();
|
||||
}
|
||||
}
|
||||
}, 4096, 8192);
|
||||
}, 4096, 8192, RateControl.NO_RATE_CONTROL);
|
||||
parser.init(UnaryOperator.identity());
|
||||
|
||||
byte[] bytes = new byte[1024];
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
|
||||
<!-- ============================================================= --><!-- Configure a HTTP2 on the ssl connector. --><!-- ============================================================= -->
|
||||
<!-- ============================================================= --><!-- Configure an HTTP2 on the ssl connector. --><!-- ============================================================= -->
|
||||
<Configure id="sslConnector" class="org.eclipse.jetty.server.ServerConnector">
|
||||
<Call name="addConnectionFactory">
|
||||
<Arg>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
|
||||
<!-- ============================================================= --><!-- Configure a HTTP2 on the ssl connector. --><!-- ============================================================= -->
|
||||
<!-- ============================================================= --><!-- Configure an HTTP2 on the ssl connector. --><!-- ============================================================= -->
|
||||
<Configure id="httpConnector" class="org.eclipse.jetty.server.ServerConnector">
|
||||
<Call name="addConnectionFactory">
|
||||
<Arg>
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package org.eclipse.jetty.http2.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
@ -34,7 +35,9 @@ import org.eclipse.jetty.http2.api.server.ServerSessionListener;
|
|||
import org.eclipse.jetty.http2.frames.Frame;
|
||||
import org.eclipse.jetty.http2.frames.SettingsFrame;
|
||||
import org.eclipse.jetty.http2.generator.Generator;
|
||||
import org.eclipse.jetty.http2.parser.RateControl;
|
||||
import org.eclipse.jetty.http2.parser.ServerParser;
|
||||
import org.eclipse.jetty.http2.parser.WindowRateControl;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.server.AbstractConnectionFactory;
|
||||
|
@ -58,6 +61,7 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
|
|||
private int maxHeaderBlockFragment = 0;
|
||||
private int maxFrameLength = Frame.DEFAULT_MAX_LENGTH;
|
||||
private int maxSettingsKeys = SettingsFrame.DEFAULT_MAX_KEYS;
|
||||
private RateControl rateControl = new WindowRateControl(20, Duration.ofSeconds(1));
|
||||
private FlowControlStrategy.Factory flowControlStrategyFactory = () -> new BufferingFlowControlStrategy(0.5F);
|
||||
private long streamIdleTimeout;
|
||||
|
||||
|
@ -178,6 +182,16 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
|
|||
this.maxSettingsKeys = maxSettingsKeys;
|
||||
}
|
||||
|
||||
public RateControl getRateControl()
|
||||
{
|
||||
return rateControl;
|
||||
}
|
||||
|
||||
public void setRateControl(RateControl rateControl)
|
||||
{
|
||||
this.rateControl = rateControl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return -1
|
||||
* @deprecated feature removed, no replacement
|
||||
|
@ -237,7 +251,7 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
|
|||
session.setInitialSessionRecvWindow(getInitialSessionRecvWindow());
|
||||
session.setWriteThreshold(getHttpConfiguration().getOutputBufferSize());
|
||||
|
||||
ServerParser parser = newServerParser(connector, session);
|
||||
ServerParser parser = newServerParser(connector, session, getRateControl());
|
||||
parser.setMaxFrameLength(getMaxFrameLength());
|
||||
parser.setMaxSettingsKeys(getMaxSettingsKeys());
|
||||
|
||||
|
@ -249,9 +263,9 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
|
|||
|
||||
protected abstract ServerSessionListener newSessionListener(Connector connector, EndPoint endPoint);
|
||||
|
||||
protected ServerParser newServerParser(Connector connector, ServerParser.Listener listener)
|
||||
protected ServerParser newServerParser(Connector connector, ServerParser.Listener listener, RateControl rateControl)
|
||||
{
|
||||
return new ServerParser(connector.getByteBufferPool(), listener, getMaxDynamicTableSize(), getHttpConfiguration().getRequestHeaderSize());
|
||||
return new ServerParser(connector.getByteBufferPool(), listener, getMaxDynamicTableSize(), getHttpConfiguration().getRequestHeaderSize(), rateControl);
|
||||
}
|
||||
|
||||
@ManagedObject("The container of HTTP/2 sessions")
|
||||
|
|
|
@ -39,8 +39,8 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
* </p>
|
||||
* <p>If 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.
|
||||
*/
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<?xml version="1.0"?><!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
|
||||
<!-- ============================================================= --><!-- Configure the Jetty Server instance with an ID "Server" --><!-- by adding a HTTP connector. --><!-- This configuration must be used in conjunction with jetty.xml --><!-- ============================================================= -->
|
||||
<!-- ============================================================= --><!-- Configure the Jetty Server instance with an ID "Server" --><!-- by adding an HTTP connector. --><!-- This configuration must be used in conjunction with jetty.xml --><!-- ============================================================= -->
|
||||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- Add a HTTP Connector. -->
|
||||
<!-- Add an HTTP Connector. -->
|
||||
<!-- Configure an o.e.j.server.ServerConnector with a single -->
|
||||
<!-- HttpConnectionFactory instance using the common httpConfig -->
|
||||
<!-- instance defined in jetty.xml -->
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<?xml version="1.0"?><!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
|
||||
<!-- ============================================================= --><!-- Configure the Jetty Server instance with an ID "Server" --><!-- by adding a HTTP connector. --><!-- This configuration must be used in conjunction with jetty.xml --><!-- ============================================================= -->
|
||||
<!-- ============================================================= --><!-- Configure the Jetty Server instance with an ID "Server" --><!-- by adding an HTTP connector. --><!-- This configuration must be used in conjunction with jetty.xml --><!-- ============================================================= -->
|
||||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- Add a HTTP Connector. -->
|
||||
<!-- Add an HTTP Connector. -->
|
||||
<!-- Configure an o.e.j.server.ServerConnector with a single -->
|
||||
<!-- HttpConnectionFactory instance using the common httpConfig -->
|
||||
<!-- instance defined in jetty.xml -->
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<?xml version="1.0"?><!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
|
||||
<!-- ============================================================= --><!-- Configure the Jetty Server instance with an ID "Server" --><!-- by adding a HTTP connector. --><!-- This configuration must be used in conjunction with jetty.xml --><!-- ============================================================= -->
|
||||
<!-- ============================================================= --><!-- Configure the Jetty Server instance with an ID "Server" --><!-- by adding an HTTP connector. --><!-- This configuration must be used in conjunction with jetty.xml --><!-- ============================================================= -->
|
||||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- Add a HTTP Connector. -->
|
||||
<!-- Add an HTTP Connector. -->
|
||||
<!-- Configure an o.e.j.server.ServerConnector with a single -->
|
||||
<!-- HttpConnectionFactory instance using the common httpConfig -->
|
||||
<!-- instance defined in jetty.xml -->
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<?xml version="1.0"?><!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
|
||||
<!-- ============================================================= --><!-- Configure the Jetty Server instance with an ID "Server" --><!-- by adding a HTTP connector. --><!-- This configuration must be used in conjunction with jetty.xml --><!-- ============================================================= -->
|
||||
<!-- ============================================================= --><!-- Configure the Jetty Server instance with an ID "Server" --><!-- by adding an HTTP connector. --><!-- This configuration must be used in conjunction with jetty.xml --><!-- ============================================================= -->
|
||||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- Add a HTTP Connector. -->
|
||||
<!-- Add an HTTP Connector. -->
|
||||
<!-- Configure an o.e.j.server.ServerConnector with a single -->
|
||||
<!-- HttpConnectionFactory instance using the common httpConfig -->
|
||||
<!-- instance defined in jetty.xml -->
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<?xml version="1.0"?><!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
|
||||
<!-- ============================================================= --><!-- Configure the Jetty Server instance with an ID "Server" --><!-- by adding a HTTP connector. --><!-- This configuration must be used in conjunction with jetty.xml --><!-- ============================================================= -->
|
||||
<!-- ============================================================= --><!-- Configure the Jetty Server instance with an ID "Server" --><!-- by adding an HTTP connector. --><!-- This configuration must be used in conjunction with jetty.xml --><!-- ============================================================= -->
|
||||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- Add a HTTP Connector. -->
|
||||
<!-- Add an HTTP Connector. -->
|
||||
<!-- Configure an o.e.j.server.ServerConnector with a single -->
|
||||
<!-- HttpConnectionFactory instance using the common httpConfig -->
|
||||
<!-- instance defined in jetty.xml -->
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<?xml version="1.0"?><!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
|
||||
<!-- ============================================================= --><!-- Configure the Jetty Server instance with an ID "Server" --><!-- by adding a HTTP connector. --><!-- This configuration must be used in conjunction with jetty.xml --><!-- ============================================================= -->
|
||||
<!-- ============================================================= --><!-- Configure the Jetty Server instance with an ID "Server" --><!-- by adding an HTTP connector. --><!-- This configuration must be used in conjunction with jetty.xml --><!-- ============================================================= -->
|
||||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- Add a HTTP Connector. -->
|
||||
<!-- Add an HTTP Connector. -->
|
||||
<!-- Configure an o.e.j.server.ServerConnector with a single -->
|
||||
<!-- HttpConnectionFactory instance using the common httpConfig -->
|
||||
<!-- instance defined in jetty.xml -->
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<?xml version="1.0"?><!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
|
||||
<!-- ============================================================= --><!-- Configure the Jetty Server instance with an ID "Server" --><!-- by adding a HTTP connector. --><!-- This configuration must be used in conjunction with jetty.xml --><!-- ============================================================= -->
|
||||
<!-- ============================================================= --><!-- Configure the Jetty Server instance with an ID "Server" --><!-- by adding an HTTP connector. --><!-- This configuration must be used in conjunction with jetty.xml --><!-- ============================================================= -->
|
||||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- Add a HTTP Connector. -->
|
||||
<!-- Add an HTTP Connector. -->
|
||||
<!-- Configure an o.e.j.server.ServerConnector with a single -->
|
||||
<!-- HttpConnectionFactory instance using the common httpConfig -->
|
||||
<!-- instance defined in jetty.xml -->
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<?xml version="1.0"?><!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
|
||||
<!-- ============================================================= --><!-- Configure the Jetty Server instance with an ID "Server" --><!-- by adding a HTTP connector. --><!-- This configuration must be used in conjunction with jetty.xml --><!-- ============================================================= -->
|
||||
<!-- ============================================================= --><!-- Configure the Jetty Server instance with an ID "Server" --><!-- by adding an HTTP connector. --><!-- This configuration must be used in conjunction with jetty.xml --><!-- ============================================================= -->
|
||||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- Add a HTTP Connector. -->
|
||||
<!-- Add an HTTP Connector. -->
|
||||
<!-- Configure an o.e.j.server.ServerConnector with a single -->
|
||||
<!-- HttpConnectionFactory instance using the common httpConfig -->
|
||||
<!-- instance defined in jetty.xml -->
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
|
||||
<!-- ============================================================= --><!-- Configure a HTTP2 on the ssl connector. --><!-- ============================================================= -->
|
||||
<!-- ============================================================= --><!-- Configure an HTTP2 on the ssl connector. --><!-- ============================================================= -->
|
||||
<Configure id="sslConnector" class="org.eclipse.jetty.server.ServerConnector">
|
||||
<Call name="addConnectionFactory">
|
||||
<Arg>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
|
||||
<!-- ============================================================= --><!-- Configure a HTTP2 on the ssl connector. --><!-- ============================================================= -->
|
||||
<!-- ============================================================= --><!-- Configure an HTTP2 on the ssl connector. --><!-- ============================================================= -->
|
||||
<Configure id="sslConnector" class="org.eclipse.jetty.server.ServerConnector">
|
||||
<Call name="addConnectionFactory">
|
||||
<Arg>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0"?><!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
|
||||
<!-- ============================================================= --><!-- Configure a HTTPS connector. --><!-- This configuration must be used in conjunction with jetty.xml --><!-- and jetty-ssl.xml. --><!-- ============================================================= -->
|
||||
<!-- ============================================================= --><!-- Configure an HTTPS connector. --><!-- This configuration must be used in conjunction with jetty.xml --><!-- and jetty-ssl.xml. --><!-- ============================================================= -->
|
||||
<Configure id="sslConnector" class="org.eclipse.jetty.server.ServerConnector">
|
||||
|
||||
<Call name="addIfAbsentConnectionFactory">
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- Add a SSL Connector with no protocol factories -->
|
||||
<!-- Add an SSL Connector with no protocol factories -->
|
||||
<!-- =========================================================== -->
|
||||
<Call name="addConnector">
|
||||
<Arg>
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
</Call>
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<!-- To add a HTTPS SSL listener -->
|
||||
<!-- To add an HTTPS SSL listener -->
|
||||
<!-- see jetty-ssl.xml to add an ssl connector. use -->
|
||||
<!-- java -jar start.jar etc/jetty-ssl.xml -->
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
|
|
|
@ -51,7 +51,7 @@ import org.ietf.jgss.Oid;
|
|||
* of the {@link #getServiceName() service name} and the {@link #getHostName() host name},
|
||||
* for example {@code HTTP/wonder.com}, using a {@code keyTab} file as the service principal
|
||||
* credentials.</p>
|
||||
* <p>Upon receiving a HTTP request, the server tries to authenticate the client
|
||||
* <p>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.</p>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<?xml version="1.0"?><!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
|
||||
<!-- ============================================================= --><!-- Configure the Jetty Server instance with an ID "Server" --><!-- by adding a HTTP connector. --><!-- This configuration must be used in conjunction with jetty.xml --><!-- ============================================================= -->
|
||||
<!-- ============================================================= --><!-- Configure the Jetty Server instance with an ID "Server" --><!-- by adding an HTTP connector. --><!-- This configuration must be used in conjunction with jetty.xml --><!-- ============================================================= -->
|
||||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- Add a HTTP Connector. -->
|
||||
<!-- Add an HTTP Connector. -->
|
||||
<!-- Configure an o.e.j.server.ServerConnector with a single -->
|
||||
<!-- HttpConnectionFactory instance using the common httpConfig -->
|
||||
<!-- instance defined in jetty.xml -->
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0"?><!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
|
||||
<!-- ============================================================= --><!-- Configure a HTTPS connector. --><!-- This configuration must be used in conjunction with jetty.xml --><!-- and jetty-ssl.xml. --><!-- ============================================================= -->
|
||||
<!-- ============================================================= --><!-- Configure an HTTPS connector. --><!-- This configuration must be used in conjunction with jetty.xml --><!-- and jetty-ssl.xml. --><!-- ============================================================= -->
|
||||
<Configure id="sslConnector" class="org.eclipse.jetty.server.ServerConnector">
|
||||
|
||||
<Call name="addIfAbsentConnectionFactory">
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- Add a SSL Connector with no protocol factories -->
|
||||
<!-- Add an SSL Connector with no protocol factories -->
|
||||
<!-- =========================================================== -->
|
||||
<Call name="addConnector">
|
||||
<Arg>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[description]
|
||||
Enables a HTTP connector on the server.
|
||||
Enables an HTTP connector on the server.
|
||||
By default HTTP/1 is support, but HTTP2C can
|
||||
be added to the connector with the http2c module.
|
||||
|
||||
|
|
|
@ -116,7 +116,7 @@ import org.eclipse.jetty.util.thread.ThreadPoolBudget;
|
|||
* {@link ConnectionFactory}s may also create temporary {@link org.eclipse.jetty.io.Connection} instances that will exchange bytes
|
||||
* over the connection to determine what is the next protocol to use. For example the ALPN protocol is an extension
|
||||
* of SSL to allow a protocol to be specified during the SSL handshake. ALPN is used by the HTTP/2 protocol to
|
||||
* negotiate the protocol that the client and server will speak. Thus to accept a HTTP/2 connection, the
|
||||
* negotiate the protocol that the client and server will speak. Thus to accept an HTTP/2 connection, the
|
||||
* connector will be configured with {@link ConnectionFactory}s for "SSL-ALPN", "h2", "http/1.1"
|
||||
* with the default protocol being "SSL-ALPN". Thus a newly accepted connection uses "SSL-ALPN", which specifies a
|
||||
* SSLConnectionFactory with "ALPN" as the next protocol. Thus an SSL connection instance is created chained to an ALPN
|
||||
|
|
|
@ -35,11 +35,11 @@ import org.eclipse.jetty.io.EndPoint;
|
|||
* A ConnectionFactory has a protocol name that represents the protocol of the Connections
|
||||
* created. Example of protocol names include:
|
||||
* <dl>
|
||||
* <dt>http</dt><dd>Creates a HTTP connection that can handle multiple versions of HTTP from 0.9 to 1.1</dd>
|
||||
* <dt>h2</dt><dd>Creates a HTTP/2 connection that handles the HTTP/2 protocol</dd>
|
||||
* <dt>http</dt><dd>Creates an HTTP connection that can handle multiple versions of HTTP from 0.9 to 1.1</dd>
|
||||
* <dt>h2</dt><dd>Creates an HTTP/2 connection that handles the HTTP/2 protocol</dd>
|
||||
* <dt>SSL-XYZ</dt><dd>Create an SSL connection chained to a connection obtained from a connection factory
|
||||
* with a protocol "XYZ".</dd>
|
||||
* <dt>SSL-http</dt><dd>Create an SSL connection chained to a HTTP connection (aka https)</dd>
|
||||
* <dt>SSL-http</dt><dd>Create an SSL connection chained to an HTTP connection (aka https)</dd>
|
||||
* <dt>SSL-ALPN</dt><dd>Create an SSL connection chained to a ALPN connection, that uses a negotiation with
|
||||
* the client to determine the next protocol.</dd>
|
||||
* </dl>
|
||||
|
|
|
@ -352,7 +352,7 @@ public class ForwardedRequestCustomizer implements Customizer
|
|||
}
|
||||
|
||||
/**
|
||||
* @return true if the presence of a SSL session or certificate header is sufficient
|
||||
* @return true if the presence of an SSL session or certificate header is sufficient
|
||||
* to indicate a secure request (default is true)
|
||||
*/
|
||||
public boolean isSslIsSecure()
|
||||
|
@ -361,7 +361,7 @@ public class ForwardedRequestCustomizer implements Customizer
|
|||
}
|
||||
|
||||
/**
|
||||
* @param sslIsSecure true if the presence of a SSL session or certificate header is sufficient
|
||||
* @param sslIsSecure true if the presence of an SSL session or certificate header is sufficient
|
||||
* to indicate a secure request (default is true)
|
||||
*/
|
||||
public void setSslIsSecure(boolean sslIsSecure)
|
||||
|
@ -630,16 +630,16 @@ public class ForwardedRequestCustomizer implements Customizer
|
|||
if (!getForwardedPortAsAuthority())
|
||||
{
|
||||
if (_for == null)
|
||||
_for = new PortSetHostPort(_request.getRemoteHost(), field.getIntValue());
|
||||
_for = new PortSetHostPort(_request.getRemoteHost(), Integer.parseInt(getLeftMost(field.getValue())));
|
||||
else if (_for instanceof PossiblyPartialHostPort && _for.getPort() <= 0)
|
||||
_for = new HostPort(HostPort.normalizeHost(_for.getHost()), field.getIntValue());
|
||||
_for = new HostPort(HostPort.normalizeHost(_for.getHost()), Integer.parseInt(getLeftMost(field.getValue())));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_host == null)
|
||||
_host = new PortSetHostPort(_request.getServerName(), field.getIntValue());
|
||||
_host = new PortSetHostPort(_request.getServerName(), Integer.parseInt(getLeftMost(field.getValue())));
|
||||
else if (_host instanceof PossiblyPartialHostPort && _host.getPort() <= 0)
|
||||
_host = new HostPort(HostPort.normalizeHost(_host.getHost()), field.getIntValue());
|
||||
_host = new HostPort(HostPort.normalizeHost(_host.getHost()), Integer.parseInt(getLeftMost(field.getValue())));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ import org.eclipse.jetty.util.thread.Scheduler;
|
|||
|
||||
/**
|
||||
* HttpChannel represents a single endpoint for HTTP semantic processing.
|
||||
* The HttpChannel is both a HttpParser.RequestHandler, where it passively receives events from
|
||||
* The HttpChannel is both an HttpParser.RequestHandler, where it passively receives events from
|
||||
* an incoming HTTP request, and a Runnable, where it actively takes control of the request/response
|
||||
* life cycle and calls the application (perhaps suspending and resuming with multiple calls to run).
|
||||
* The HttpChannel signals the switch from passive mode to active mode by returning true to one of the
|
||||
|
@ -1016,7 +1016,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
|
|||
/**
|
||||
* <p>Listener for {@link HttpChannel} events.</p>
|
||||
* <p>HttpChannel will emit events for the various phases it goes through while
|
||||
* processing a HTTP request and response.</p>
|
||||
* processing an HTTP request and response.</p>
|
||||
* <p>Implementations of this interface may listen to those events to track
|
||||
* timing and/or other values such as request URI, etc.</p>
|
||||
* <p>The events parameters, especially the {@link Request} object, may be
|
||||
|
|
|
@ -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
|
|||
}
|
||||
|
||||
/**
|
||||
* <p>Attempts to perform a HTTP/1.1 upgrade.</p>
|
||||
* <p>Attempts to perform an HTTP/1.1 upgrade.</p>
|
||||
* <p>The upgrade looks up a {@link ConnectionFactory.Upgrading} from the connector
|
||||
* matching the protocol specified in the {@code Upgrade} header.</p>
|
||||
* <p>The upgrade may succeed, be ignored (which can allow a later handler to implement)
|
||||
|
|
|
@ -39,7 +39,7 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
/**
|
||||
* HTTP Configuration.
|
||||
* <p>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).</p>
|
||||
* <p>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
|
|||
}
|
||||
|
||||
/**
|
||||
* <p>The max idle time is applied to a HTTP request for IO operations and
|
||||
* <p>The max idle time is applied to an HTTP request for IO operations and
|
||||
* delayed dispatch.</p>
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>The max idle time is applied to a HTTP request for IO operations and
|
||||
* <p>The max idle time is applied to an HTTP request for IO operations and
|
||||
* delayed dispatch.</p>
|
||||
*
|
||||
* @param timeoutMs the max idle time in ms or if == 0 implies an infinite timeout, <0
|
||||
|
|
|
@ -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 =
|
||||
"<!DOCTYPE html>\r\n" +
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
* <p>Generate a error response body to be sent for a bad message.
|
||||
* <p>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
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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",
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue