Issue #3978 - HTTP/2 vulnerabilities.
Code cleanups and reformatting. Fixed logic for SETTINGS frame replies: they are not subject to rate control. Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
parent
53fc01793c
commit
508ad4aff9
|
@ -27,7 +27,6 @@ import java.util.Map;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.http.HttpServlet;
|
import javax.servlet.http.HttpServlet;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
@ -153,7 +152,7 @@ public class HTTP2Test extends AbstractTest
|
||||||
start(new HttpServlet()
|
start(new HttpServlet()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException
|
||||||
{
|
{
|
||||||
resp.getOutputStream().write(content);
|
resp.getOutputStream().write(content);
|
||||||
}
|
}
|
||||||
|
@ -201,7 +200,7 @@ public class HTTP2Test extends AbstractTest
|
||||||
start(new EmptyHttpServlet()
|
start(new EmptyHttpServlet()
|
||||||
{
|
{
|
||||||
@Override
|
@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());
|
IO.copy(request.getInputStream(), response.getOutputStream());
|
||||||
}
|
}
|
||||||
|
@ -245,7 +244,7 @@ public class HTTP2Test extends AbstractTest
|
||||||
start(new HttpServlet()
|
start(new HttpServlet()
|
||||||
{
|
{
|
||||||
@Override
|
@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);
|
int download = request.getIntHeader(downloadBytes);
|
||||||
byte[] content = new byte[download];
|
byte[] content = new byte[download];
|
||||||
|
@ -288,7 +287,7 @@ public class HTTP2Test extends AbstractTest
|
||||||
start(new HttpServlet()
|
start(new HttpServlet()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
protected void service(HttpServletRequest request, HttpServletResponse response)
|
||||||
{
|
{
|
||||||
response.setStatus(status);
|
response.setStatus(status);
|
||||||
}
|
}
|
||||||
|
@ -323,7 +322,7 @@ public class HTTP2Test extends AbstractTest
|
||||||
start(new HttpServlet()
|
start(new HttpServlet()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
protected void service(HttpServletRequest request, HttpServletResponse response)
|
||||||
{
|
{
|
||||||
assertEquals(host, request.getServerName());
|
assertEquals(host, request.getServerName());
|
||||||
assertEquals(port, request.getServerPort());
|
assertEquals(port, request.getServerPort());
|
||||||
|
|
|
@ -57,6 +57,7 @@ import org.eclipse.jetty.util.AtomicBiInteger;
|
||||||
import org.eclipse.jetty.util.Atomics;
|
import org.eclipse.jetty.util.Atomics;
|
||||||
import org.eclipse.jetty.util.Callback;
|
import org.eclipse.jetty.util.Callback;
|
||||||
import org.eclipse.jetty.util.CountingCallback;
|
import org.eclipse.jetty.util.CountingCallback;
|
||||||
|
import org.eclipse.jetty.util.MathUtils;
|
||||||
import org.eclipse.jetty.util.Promise;
|
import org.eclipse.jetty.util.Promise;
|
||||||
import org.eclipse.jetty.util.Retainable;
|
import org.eclipse.jetty.util.Retainable;
|
||||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||||
|
@ -464,7 +465,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
||||||
if (stream != null)
|
if (stream != null)
|
||||||
{
|
{
|
||||||
int streamSendWindow = stream.updateSendWindow(0);
|
int streamSendWindow = stream.updateSendWindow(0);
|
||||||
if (sumOverflows(streamSendWindow, windowDelta))
|
if (MathUtils.sumOverflows(streamSendWindow, windowDelta))
|
||||||
{
|
{
|
||||||
reset(new ResetFrame(streamId, ErrorCode.FLOW_CONTROL_ERROR.code), Callback.NOOP);
|
reset(new ResetFrame(streamId, ErrorCode.FLOW_CONTROL_ERROR.code), Callback.NOOP);
|
||||||
}
|
}
|
||||||
|
@ -483,7 +484,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int sessionSendWindow = updateSendWindow(0);
|
int sessionSendWindow = updateSendWindow(0);
|
||||||
if (sumOverflows(sessionSendWindow, windowDelta))
|
if (MathUtils.sumOverflows(sessionSendWindow, windowDelta))
|
||||||
onConnectionFailure(ErrorCode.FLOW_CONTROL_ERROR.code, "invalid_flow_control_window");
|
onConnectionFailure(ErrorCode.FLOW_CONTROL_ERROR.code, "invalid_flow_control_window");
|
||||||
else
|
else
|
||||||
onWindowUpdate(null, frame);
|
onWindowUpdate(null, frame);
|
||||||
|
@ -501,19 +502,6 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
||||||
callback.succeeded();
|
callback.succeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean sumOverflows(int a, int b)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Math.addExact(a, b);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
catch (ArithmeticException x)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onConnectionFailure(int error, String reason)
|
public void onConnectionFailure(int error, String reason)
|
||||||
{
|
{
|
||||||
|
|
|
@ -33,13 +33,12 @@ public class HeaderParser
|
||||||
private final RateControl rateControl;
|
private final RateControl rateControl;
|
||||||
private State state = State.LENGTH;
|
private State state = State.LENGTH;
|
||||||
private int cursor;
|
private int cursor;
|
||||||
|
|
||||||
private int length;
|
private int length;
|
||||||
private int type;
|
private int type;
|
||||||
private int flags;
|
private int flags;
|
||||||
private int streamId;
|
private int streamId;
|
||||||
|
|
||||||
HeaderParser(RateControl rateControl)
|
public HeaderParser(RateControl rateControl)
|
||||||
{
|
{
|
||||||
this.rateControl = rateControl;
|
this.rateControl = rateControl;
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@ public class Parser
|
||||||
|
|
||||||
public Parser(ByteBufferPool byteBufferPool, Listener listener, int maxDynamicTableSize, int maxHeaderSize)
|
public Parser(ByteBufferPool byteBufferPool, Listener listener, int maxDynamicTableSize, int maxHeaderSize)
|
||||||
{
|
{
|
||||||
this (byteBufferPool, listener, maxDynamicTableSize, maxHeaderSize, RateControl.NO_RATE_CONTROL);
|
this(byteBufferPool, listener, maxDynamicTableSize, maxHeaderSize, RateControl.NO_RATE_CONTROL);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Parser(ByteBufferPool byteBufferPool, Listener listener, int maxDynamicTableSize, int maxHeaderSize, RateControl rateControl)
|
public Parser(ByteBufferPool byteBufferPool, Listener listener, int maxDynamicTableSize, int maxHeaderSize, RateControl rateControl)
|
||||||
|
@ -76,7 +76,6 @@ public class Parser
|
||||||
public void init(UnaryOperator<Listener> wrapper)
|
public void init(UnaryOperator<Listener> wrapper)
|
||||||
{
|
{
|
||||||
Listener listener = wrapper.apply(this.listener);
|
Listener listener = wrapper.apply(this.listener);
|
||||||
RateControl rateControl = getRateControl();
|
|
||||||
unknownBodyParser = new UnknownBodyParser(headerParser, listener);
|
unknownBodyParser = new UnknownBodyParser(headerParser, listener);
|
||||||
HeaderBlockParser headerBlockParser = new HeaderBlockParser(headerParser, byteBufferPool, hpackDecoder, unknownBodyParser);
|
HeaderBlockParser headerBlockParser = new HeaderBlockParser(headerParser, byteBufferPool, hpackDecoder, unknownBodyParser);
|
||||||
HeaderBlockFragments headerBlockFragments = new HeaderBlockFragments();
|
HeaderBlockFragments headerBlockFragments = new HeaderBlockFragments();
|
||||||
|
@ -240,11 +239,6 @@ public class Parser
|
||||||
this.maxSettingsKeys = maxSettingsKeys;
|
this.maxSettingsKeys = maxSettingsKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RateControl getRateControl()
|
|
||||||
{
|
|
||||||
return headerParser.getRateControl();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void notifyConnectionFailure(int error, String reason)
|
protected void notifyConnectionFailure(int error, String reason)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|
|
@ -23,7 +23,7 @@ package org.eclipse.jetty.http2.parser;
|
||||||
*/
|
*/
|
||||||
public interface RateControl
|
public interface RateControl
|
||||||
{
|
{
|
||||||
RateControl NO_RATE_CONTROL = event -> true;
|
public static final RateControl NO_RATE_CONTROL = event -> true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Applications should call this method when they want to signal an
|
* <p>Applications should call this method when they want to signal an
|
||||||
|
|
|
@ -73,8 +73,9 @@ public class SettingsBodyParser extends BodyParser
|
||||||
@Override
|
@Override
|
||||||
protected void emptyBody(ByteBuffer buffer)
|
protected void emptyBody(ByteBuffer buffer)
|
||||||
{
|
{
|
||||||
SettingsFrame frame = new SettingsFrame(Collections.emptyMap(), hasFlag(Flags.ACK));
|
boolean isReply = hasFlag(Flags.ACK);
|
||||||
if (!rateControlOnEvent(frame))
|
SettingsFrame frame = new SettingsFrame(Collections.emptyMap(), isReply);
|
||||||
|
if (!isReply && !rateControlOnEvent(frame))
|
||||||
connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_settings_frame_rate");
|
connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_settings_frame_rate");
|
||||||
else
|
else
|
||||||
onSettings(frame);
|
onSettings(frame);
|
||||||
|
|
|
@ -176,16 +176,17 @@ public class HpackDecoder
|
||||||
name = Huffman.decode(buffer, length);
|
name = Huffman.decode(buffer, length);
|
||||||
else
|
else
|
||||||
name = toASCIIString(buffer, length);
|
name = toASCIIString(buffer, length);
|
||||||
check: for (int i = name.length(); i-- > 0;)
|
check:
|
||||||
|
for (int i = name.length(); i-- > 0;)
|
||||||
{
|
{
|
||||||
char c = name.charAt(i);
|
char c = name.charAt(i);
|
||||||
if (c>0xff)
|
if (c > 0xff)
|
||||||
{
|
{
|
||||||
_builder.streamException("Illegal header name %s", name);
|
_builder.streamException("Illegal header name %s", name);
|
||||||
break check;
|
break;
|
||||||
}
|
}
|
||||||
HttpTokens.Token token = HttpTokens.TOKENS[0xFF & c];
|
HttpTokens.Token token = HttpTokens.TOKENS[0xFF & c];
|
||||||
switch(token.getType())
|
switch (token.getType())
|
||||||
{
|
{
|
||||||
case ALPHA:
|
case ALPHA:
|
||||||
if (c >= 'A' && c <= 'Z')
|
if (c >= 'A' && c <= 'Z')
|
||||||
|
|
|
@ -115,7 +115,7 @@ public class MetaDataBuilder
|
||||||
{
|
{
|
||||||
case C_STATUS:
|
case C_STATUS:
|
||||||
if (checkPseudoHeader(header, _status))
|
if (checkPseudoHeader(header, _status))
|
||||||
_status = Integer.valueOf(field.getIntValue());
|
_status = field.getIntValue();
|
||||||
_response = true;
|
_response = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -384,7 +384,7 @@ public class HpackDecoderTest
|
||||||
mdb.emit(new HttpField(HttpHeader.C_SCHEME, "http"));
|
mdb.emit(new HttpField(HttpHeader.C_SCHEME, "http"));
|
||||||
mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost:8080"));
|
mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost:8080"));
|
||||||
mdb.emit(new HttpField(HttpHeader.C_PATH, ""));
|
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"));
|
assertThat(ex.getMessage(), Matchers.containsString("No Path"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,7 +394,7 @@ public class HpackDecoderTest
|
||||||
mdb.emit(new HttpField(HttpHeader.C_SCHEME, "http"));
|
mdb.emit(new HttpField(HttpHeader.C_SCHEME, "http"));
|
||||||
mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost:8080"));
|
mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost:8080"));
|
||||||
mdb.emit(new HttpField(HttpHeader.C_PATH, "/"));
|
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"));
|
assertThat(ex.getMessage(), Matchers.containsString("No Method"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -404,7 +404,7 @@ public class HpackDecoderTest
|
||||||
mdb.emit(new HttpField(HttpHeader.C_METHOD, "GET"));
|
mdb.emit(new HttpField(HttpHeader.C_METHOD, "GET"));
|
||||||
mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost:8080"));
|
mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost:8080"));
|
||||||
mdb.emit(new HttpField(HttpHeader.C_PATH, "/"));
|
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"));
|
assertThat(ex.getMessage(), Matchers.containsString("No Scheme"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -414,7 +414,7 @@ public class HpackDecoderTest
|
||||||
mdb.emit(new HttpField(HttpHeader.C_METHOD, "GET"));
|
mdb.emit(new HttpField(HttpHeader.C_METHOD, "GET"));
|
||||||
mdb.emit(new HttpField(HttpHeader.C_SCHEME, "http"));
|
mdb.emit(new HttpField(HttpHeader.C_SCHEME, "http"));
|
||||||
mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost:8080"));
|
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"));
|
assertThat(ex.getMessage(), Matchers.containsString("No Path"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,7 +426,7 @@ public class HpackDecoderTest
|
||||||
mdb.emit(new HttpField(HttpHeader.C_SCHEME, "http"));
|
mdb.emit(new HttpField(HttpHeader.C_SCHEME, "http"));
|
||||||
mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost:8080"));
|
mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost:8080"));
|
||||||
mdb.emit(new HttpField(HttpHeader.C_PATH, "/"));
|
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"));
|
assertThat(ex.getMessage(), Matchers.containsString("Duplicate"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,7 +439,7 @@ public class HpackDecoderTest
|
||||||
mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost:8080"));
|
mdb.emit(new HttpField(HttpHeader.C_AUTHORITY, "localhost:8080"));
|
||||||
mdb.emit(new HttpField(HttpHeader.C_PATH, "/"));
|
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"));
|
assertThat(ex.getMessage(), Matchers.containsString("Duplicate"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -463,7 +463,7 @@ public class HpackDecoderTest
|
||||||
|
|
||||||
/* 5.2.1: Sends a Huffman-encoded string literal representation with padding longer than 7 bits */
|
/* 5.2.1: Sends a Huffman-encoded string literal representation with padding longer than 7 bits */
|
||||||
@Test
|
@Test
|
||||||
public void testHuffmanEncodedExtraPadding() throws Exception
|
public void testHuffmanEncodedExtraPadding()
|
||||||
{
|
{
|
||||||
HpackDecoder decoder = new HpackDecoder(4096, 8192);
|
HpackDecoder decoder = new HpackDecoder(4096, 8192);
|
||||||
|
|
||||||
|
@ -475,7 +475,7 @@ public class HpackDecoderTest
|
||||||
|
|
||||||
/* 5.2.2: Sends a Huffman-encoded string literal representation padded by zero */
|
/* 5.2.2: Sends a Huffman-encoded string literal representation padded by zero */
|
||||||
@Test
|
@Test
|
||||||
public void testHuffmanEncodedZeroPadding() throws Exception
|
public void testHuffmanEncodedZeroPadding()
|
||||||
{
|
{
|
||||||
HpackDecoder decoder = new HpackDecoder(4096, 8192);
|
HpackDecoder decoder = new HpackDecoder(4096, 8192);
|
||||||
|
|
||||||
|
@ -488,7 +488,7 @@ public class HpackDecoderTest
|
||||||
|
|
||||||
/* 5.2.3: Sends a Huffman-encoded string literal representation containing the EOS symbol */
|
/* 5.2.3: Sends a Huffman-encoded string literal representation containing the EOS symbol */
|
||||||
@Test
|
@Test
|
||||||
public void testHuffmanEncodedWithEOS() throws Exception
|
public void testHuffmanEncodedWithEOS()
|
||||||
{
|
{
|
||||||
HpackDecoder decoder = new HpackDecoder(4096, 8192);
|
HpackDecoder decoder = new HpackDecoder(4096, 8192);
|
||||||
|
|
||||||
|
@ -500,7 +500,7 @@ public class HpackDecoderTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHuffmanEncodedOneIncompleteOctet() throws Exception
|
public void testHuffmanEncodedOneIncompleteOctet()
|
||||||
{
|
{
|
||||||
HpackDecoder decoder = new HpackDecoder(4096, 8192);
|
HpackDecoder decoder = new HpackDecoder(4096, 8192);
|
||||||
|
|
||||||
|
@ -512,7 +512,7 @@ public class HpackDecoderTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHuffmanEncodedTwoIncompleteOctet() throws Exception
|
public void testHuffmanEncodedTwoIncompleteOctet()
|
||||||
{
|
{
|
||||||
HpackDecoder decoder = new HpackDecoder(4096, 8192);
|
HpackDecoder decoder = new HpackDecoder(4096, 8192);
|
||||||
|
|
||||||
|
@ -524,7 +524,7 @@ public class HpackDecoderTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testZeroLengthName() throws Exception
|
public void testZeroLengthName()
|
||||||
{
|
{
|
||||||
HpackDecoder decoder = new HpackDecoder(4096, 8192);
|
HpackDecoder decoder = new HpackDecoder(4096, 8192);
|
||||||
|
|
||||||
|
@ -547,7 +547,7 @@ public class HpackDecoderTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpperCaseName() throws Exception
|
public void testUpperCaseName()
|
||||||
{
|
{
|
||||||
HpackDecoder decoder = new HpackDecoder(4096, 8192);
|
HpackDecoder decoder = new HpackDecoder(4096, 8192);
|
||||||
|
|
||||||
|
@ -558,7 +558,7 @@ public class HpackDecoderTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWhiteSpaceName() throws Exception
|
public void testWhiteSpaceName()
|
||||||
{
|
{
|
||||||
HpackDecoder decoder = new HpackDecoder(4096, 8192);
|
HpackDecoder decoder = new HpackDecoder(4096, 8192);
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.http2.client.http;
|
package org.eclipse.jetty.http2.client.http;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
|
@ -38,7 +37,6 @@ import java.util.concurrent.TimeoutException;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.function.UnaryOperator;
|
import java.util.function.UnaryOperator;
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
@ -188,7 +186,7 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest
|
||||||
start(new AbstractHandler()
|
start(new AbstractHandler()
|
||||||
{
|
{
|
||||||
@Override
|
@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);
|
baseRequest.setHandled(true);
|
||||||
HttpVersion version = HttpVersion.fromString(request.getProtocol());
|
HttpVersion version = HttpVersion.fromString(request.getProtocol());
|
||||||
|
@ -314,7 +312,7 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest
|
||||||
start(new AbstractHandler()
|
start(new AbstractHandler()
|
||||||
{
|
{
|
||||||
@Override
|
@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);
|
baseRequest.setHandled(true);
|
||||||
assertEquals(path, request.getRequestURI());
|
assertEquals(path, request.getRequestURI());
|
||||||
|
@ -338,7 +336,7 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest
|
||||||
start(new AbstractHandler()
|
start(new AbstractHandler()
|
||||||
{
|
{
|
||||||
@Override
|
@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);
|
baseRequest.setHandled(true);
|
||||||
assertEquals(path, request.getRequestURI());
|
assertEquals(path, request.getRequestURI());
|
||||||
|
|
|
@ -49,7 +49,6 @@ import org.eclipse.jetty.http2.frames.HeadersFrame;
|
||||||
import org.eclipse.jetty.http2.frames.PingFrame;
|
import org.eclipse.jetty.http2.frames.PingFrame;
|
||||||
import org.eclipse.jetty.http2.frames.ResetFrame;
|
import org.eclipse.jetty.http2.frames.ResetFrame;
|
||||||
import org.eclipse.jetty.http2.frames.SettingsFrame;
|
import org.eclipse.jetty.http2.frames.SettingsFrame;
|
||||||
import org.eclipse.jetty.http2.parser.RateControl;
|
|
||||||
import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
|
import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
|
||||||
import org.eclipse.jetty.server.Handler;
|
import org.eclipse.jetty.server.Handler;
|
||||||
import org.eclipse.jetty.server.HttpConfiguration;
|
import org.eclipse.jetty.server.HttpConfiguration;
|
||||||
|
@ -75,7 +74,6 @@ public class MaxConcurrentStreamsTest extends AbstractTest
|
||||||
{
|
{
|
||||||
HTTP2ServerConnectionFactory http2 = new HTTP2ServerConnectionFactory(new HttpConfiguration());
|
HTTP2ServerConnectionFactory http2 = new HTTP2ServerConnectionFactory(new HttpConfiguration());
|
||||||
http2.setMaxConcurrentStreams(maxConcurrentStreams);
|
http2.setMaxConcurrentStreams(maxConcurrentStreams);
|
||||||
http2.setRateControl(RateControl.NO_RATE_CONTROL);
|
|
||||||
prepareServer(http2);
|
prepareServer(http2);
|
||||||
server.setHandler(handler);
|
server.setHandler(handler);
|
||||||
server.start();
|
server.start();
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// All rights reserved. This program and the accompanying materials
|
||||||
|
// are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
// and Apache License v2.0 which accompanies this distribution.
|
||||||
|
//
|
||||||
|
// The Eclipse Public License is available at
|
||||||
|
// http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
//
|
||||||
|
// The Apache License v2.0 is available at
|
||||||
|
// http://www.opensource.org/licenses/apache2.0.php
|
||||||
|
//
|
||||||
|
// You may elect to redistribute this code under either of these licenses.
|
||||||
|
// ========================================================================
|
||||||
|
//
|
||||||
|
|
||||||
|
package org.eclipse.jetty.util;
|
||||||
|
|
||||||
|
public class MathUtils
|
||||||
|
{
|
||||||
|
private MathUtils()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the sum of the arguments overflows an {@code int}.
|
||||||
|
*
|
||||||
|
* @param a the first value
|
||||||
|
* @param b the second value
|
||||||
|
* @return whether the sum of the arguments overflows an {@code int}
|
||||||
|
*/
|
||||||
|
public static boolean sumOverflows(int a, int b)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Math.addExact(a, b);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (ArithmeticException x)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue