Merge remote-tracking branch 'origin/jetty-10.0.x' into jetty-10.0.x-1743-refactor-maven-plugin-redux
Signed-off-by: Jan Bartel <janb@webtide.com>
This commit is contained in:
commit
8faafdd063
|
@ -23,7 +23,7 @@ Documentation
|
||||||
|
|
||||||
Project documentation is available on the Jetty Eclipse website.
|
Project documentation is available on the Jetty Eclipse website.
|
||||||
|
|
||||||
- [http://www.eclipse.org/jetty/documentation](http://www.eclipse.org/jetty/documentation)
|
- [https://www.eclipse.org/jetty/documentation](https://www.eclipse.org/jetty/documentation)
|
||||||
|
|
||||||
Building
|
Building
|
||||||
========
|
========
|
||||||
|
@ -45,4 +45,4 @@ It is possible to bypass tests by building with `mvn clean install -DskipTests`.
|
||||||
Professional Services
|
Professional Services
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
Expert advice and production support are available through [Webtide.com](http://webtide.com).
|
Expert advice and production support are available through [Webtide.com](https://webtide.com).
|
||||||
|
|
|
@ -460,6 +460,11 @@ jetty-9.4.15.v20190215 - 15 February 2019
|
||||||
+ 3350 Do not expect to be able to connect to https URLs with the HttpClient
|
+ 3350 Do not expect to be able to connect to https URLs with the HttpClient
|
||||||
created from a parameterless constructor
|
created from a parameterless constructor
|
||||||
|
|
||||||
|
jetty-9.3.28.v20191105 - 05 November 2019
|
||||||
|
+ 3989 Inform custom ManagedSelector of dead selector via optional
|
||||||
|
onFailedSelect()
|
||||||
|
+ 4217 SslConnection.DecryptedEnpoint.flush eternal busy loop
|
||||||
|
|
||||||
jetty-9.3.27.v20190418 - 18 April 2019
|
jetty-9.3.27.v20190418 - 18 April 2019
|
||||||
+ 3549 Directory Listing on Windows reveals Resource Base path
|
+ 3549 Directory Listing on Windows reveals Resource Base path
|
||||||
+ 3555 DefaultHandler Reveals Base Resource Path of each Context
|
+ 3555 DefaultHandler Reveals Base Resource Path of each Context
|
||||||
|
@ -472,6 +477,9 @@ jetty-9.3.26.v20190403 - 03 April 2019
|
||||||
ForwardedRequestCustomizer
|
ForwardedRequestCustomizer
|
||||||
+ 3319 Allow reverse sort for directory listed files
|
+ 3319 Allow reverse sort for directory listed files
|
||||||
|
|
||||||
|
jetty-9.2.29.v20191105 - 05 November 2019
|
||||||
|
+ 4217 SslConnection.DecryptedEnpoint.flush eternal busy loop
|
||||||
|
|
||||||
jetty-9.2.28.v20190418 - 18 April 2019
|
jetty-9.2.28.v20190418 - 18 April 2019
|
||||||
+ 3549 Directory Listing on Windows reveals Resource Base path
|
+ 3549 Directory Listing on Windows reveals Resource Base path
|
||||||
+ 3555 DefaultHandler Reveals Base Resource Path of each Context
|
+ 3555 DefaultHandler Reveals Base Resource Path of each Context
|
||||||
|
|
|
@ -100,8 +100,8 @@
|
||||||
<GITDOCURL>https://github.com/eclipse/jetty.project/tree/jetty-10.0.x-doc-refactor/jetty-documentation/src/main/asciidoc</GITDOCURL>
|
<GITDOCURL>https://github.com/eclipse/jetty.project/tree/jetty-10.0.x-doc-refactor/jetty-documentation/src/main/asciidoc</GITDOCURL>
|
||||||
<DISTGUIDE>../distribution-guide/index.html</DISTGUIDE>
|
<DISTGUIDE>../distribution-guide/index.html</DISTGUIDE>
|
||||||
<EMBEDGUIDE>../embedded-guide/index.html</EMBEDGUIDE>
|
<EMBEDGUIDE>../embedded-guide/index.html</EMBEDGUIDE>
|
||||||
<QUICKGUIDE>../quickstart-guideindex.html</QUICKGUIDE>
|
<QUICKGUIDE>../quickstart-guide/index.html</QUICKGUIDE>
|
||||||
<CONTRIBGUIDE>../contribution-guideindex.html</CONTRIBGUIDE>
|
<CONTRIBGUIDE>../contribution-guide/index.html</CONTRIBGUIDE>
|
||||||
<MVNCENTRAL>http://central.maven.org/maven2</MVNCENTRAL>
|
<MVNCENTRAL>http://central.maven.org/maven2</MVNCENTRAL>
|
||||||
<VERSION>${project.version}</VERSION>
|
<VERSION>${project.version}</VERSION>
|
||||||
<TIMESTAMP>${maven.build.timestamp}</TIMESTAMP>
|
<TIMESTAMP>${maven.build.timestamp}</TIMESTAMP>
|
||||||
|
|
|
@ -708,7 +708,7 @@ public class HttpParser
|
||||||
|
|
||||||
case LF:
|
case LF:
|
||||||
setState(State.HEADER);
|
setState(State.HEADER);
|
||||||
handle |= _responseHandler.startResponse(_version, _responseStatus, null);
|
handle = _responseHandler.startResponse(_version, _responseStatus, null);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -805,7 +805,7 @@ public class HttpParser
|
||||||
if (_responseHandler != null)
|
if (_responseHandler != null)
|
||||||
{
|
{
|
||||||
setState(State.HEADER);
|
setState(State.HEADER);
|
||||||
handle |= _responseHandler.startResponse(_version, _responseStatus, null);
|
handle = _responseHandler.startResponse(_version, _responseStatus, null);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -835,15 +835,13 @@ public class HttpParser
|
||||||
checkVersion();
|
checkVersion();
|
||||||
|
|
||||||
// Should we try to cache header fields?
|
// Should we try to cache header fields?
|
||||||
if (_fieldCache == null && _version.getVersion() >= HttpVersion.HTTP_1_1.getVersion() && _handler.getHeaderCacheSize() > 0)
|
|
||||||
{
|
|
||||||
int headerCache = _handler.getHeaderCacheSize();
|
int headerCache = _handler.getHeaderCacheSize();
|
||||||
|
if (_fieldCache == null && _version.getVersion() >= HttpVersion.HTTP_1_1.getVersion() && headerCache > 0)
|
||||||
_fieldCache = new ArrayTernaryTrie<>(headerCache);
|
_fieldCache = new ArrayTernaryTrie<>(headerCache);
|
||||||
}
|
|
||||||
|
|
||||||
setState(State.HEADER);
|
setState(State.HEADER);
|
||||||
|
|
||||||
handle |= _requestHandler.startRequest(_methodString, _uri.toString(), _version);
|
handle = _requestHandler.startRequest(_methodString, _uri.toString(), _version);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case ALPHA:
|
case ALPHA:
|
||||||
|
@ -865,7 +863,7 @@ public class HttpParser
|
||||||
case LF:
|
case LF:
|
||||||
String reason = takeString();
|
String reason = takeString();
|
||||||
setState(State.HEADER);
|
setState(State.HEADER);
|
||||||
handle |= _responseHandler.startResponse(_version, _responseStatus, reason);
|
handle = _responseHandler.startResponse(_version, _responseStatus, reason);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case ALPHA:
|
case ALPHA:
|
||||||
|
@ -1589,7 +1587,6 @@ public class HttpParser
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle _content
|
// Handle _content
|
||||||
byte ch;
|
|
||||||
while (_state.ordinal() < State.TRAILER.ordinal() && remaining > 0)
|
while (_state.ordinal() < State.TRAILER.ordinal() && remaining > 0)
|
||||||
{
|
{
|
||||||
switch (_state)
|
switch (_state)
|
||||||
|
|
|
@ -44,6 +44,7 @@ import static org.hamcrest.Matchers.nullValue;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
public class HttpParserTest
|
public class HttpParserTest
|
||||||
|
@ -94,7 +95,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLineParseMockIP() throws Exception
|
public void testLineParseMockIP()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer("POST /mock/127.0.0.1 HTTP/1.1\r\n" + "\r\n");
|
ByteBuffer buffer = BufferUtil.toBuffer("POST /mock/127.0.0.1 HTTP/1.1\r\n" + "\r\n");
|
||||||
|
|
||||||
|
@ -108,7 +109,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLineParse0() throws Exception
|
public void testLineParse0()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer("POST /foo HTTP/1.0\r\n" + "\r\n");
|
ByteBuffer buffer = BufferUtil.toBuffer("POST /foo HTTP/1.0\r\n" + "\r\n");
|
||||||
|
|
||||||
|
@ -122,7 +123,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLineParse1RFC2616() throws Exception
|
public void testLineParse1RFC2616()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer("GET /999\r\n");
|
ByteBuffer buffer = BufferUtil.toBuffer("GET /999\r\n");
|
||||||
|
|
||||||
|
@ -139,7 +140,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLineParse1() throws Exception
|
public void testLineParse1()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer("GET /999\r\n");
|
ByteBuffer buffer = BufferUtil.toBuffer("GET /999\r\n");
|
||||||
|
|
||||||
|
@ -151,7 +152,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLineParse2RFC2616() throws Exception
|
public void testLineParse2RFC2616()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer("POST /222 \r\n");
|
ByteBuffer buffer = BufferUtil.toBuffer("POST /222 \r\n");
|
||||||
|
|
||||||
|
@ -168,7 +169,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLineParse2() throws Exception
|
public void testLineParse2()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer("POST /222 \r\n");
|
ByteBuffer buffer = BufferUtil.toBuffer("POST /222 \r\n");
|
||||||
|
|
||||||
|
@ -181,7 +182,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLineParse3() throws Exception
|
public void testLineParse3()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer("POST /fo\u0690 HTTP/1.0\r\n" + "\r\n", StandardCharsets.UTF_8);
|
ByteBuffer buffer = BufferUtil.toBuffer("POST /fo\u0690 HTTP/1.0\r\n" + "\r\n", StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
@ -195,7 +196,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLineParse4() throws Exception
|
public void testLineParse4()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer("POST /foo?param=\u0690 HTTP/1.0\r\n" + "\r\n", StandardCharsets.UTF_8);
|
ByteBuffer buffer = BufferUtil.toBuffer("POST /foo?param=\u0690 HTTP/1.0\r\n" + "\r\n", StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
@ -209,7 +210,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLongURLParse() throws Exception
|
public void testLongURLParse()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer("POST /123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/ HTTP/1.0\r\n" + "\r\n");
|
ByteBuffer buffer = BufferUtil.toBuffer("POST /123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/123456789abcdef/ HTTP/1.0\r\n" + "\r\n");
|
||||||
|
|
||||||
|
@ -223,7 +224,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAllowedLinePreamble() throws Exception
|
public void testAllowedLinePreamble()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer("\r\n\r\nGET / HTTP/1.0\r\n");
|
ByteBuffer buffer = BufferUtil.toBuffer("\r\n\r\nGET / HTTP/1.0\r\n");
|
||||||
|
|
||||||
|
@ -237,7 +238,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDisallowedLinePreamble() throws Exception
|
public void testDisallowedLinePreamble()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer("\r\n \r\nGET / HTTP/1.0\r\n");
|
ByteBuffer buffer = BufferUtil.toBuffer("\r\n \r\nGET / HTTP/1.0\r\n");
|
||||||
|
|
||||||
|
@ -248,7 +249,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConnect() throws Exception
|
public void testConnect()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer("CONNECT 192.168.1.2:80 HTTP/1.1\r\n" + "\r\n");
|
ByteBuffer buffer = BufferUtil.toBuffer("CONNECT 192.168.1.2:80 HTTP/1.1\r\n" + "\r\n");
|
||||||
HttpParser.RequestHandler handler = new Handler();
|
HttpParser.RequestHandler handler = new Handler();
|
||||||
|
@ -261,7 +262,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSimple() throws Exception
|
public void testSimple()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / HTTP/1.0\r\n" +
|
"GET / HTTP/1.0\r\n" +
|
||||||
|
@ -286,7 +287,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFoldedField2616() throws Exception
|
public void testFoldedField2616()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / HTTP/1.0\r\n" +
|
"GET / HTTP/1.0\r\n" +
|
||||||
|
@ -313,7 +314,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFoldedField7230() throws Exception
|
public void testFoldedField7230()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / HTTP/1.0\r\n" +
|
"GET / HTTP/1.0\r\n" +
|
||||||
|
@ -332,7 +333,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWhiteSpaceInName() throws Exception
|
public void testWhiteSpaceInName()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / HTTP/1.0\r\n" +
|
"GET / HTTP/1.0\r\n" +
|
||||||
|
@ -349,7 +350,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWhiteSpaceAfterName() throws Exception
|
public void testWhiteSpaceAfterName()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / HTTP/1.0\r\n" +
|
"GET / HTTP/1.0\r\n" +
|
||||||
|
@ -390,10 +391,8 @@ public class HttpParserTest
|
||||||
{" \r \t \r\n\r\n\r\n", "Illegal character SPACE"}
|
{" \r \t \r\n\r\n\r\n", "Illegal character SPACE"}
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; i < compliances.length; i++)
|
for (HttpCompliance compliance : compliances)
|
||||||
{
|
{
|
||||||
HttpCompliance compliance = compliances[i];
|
|
||||||
|
|
||||||
for (int j = 0; j < whitespaces.length; j++)
|
for (int j = 0; j < whitespaces.length; j++)
|
||||||
{
|
{
|
||||||
String request =
|
String request =
|
||||||
|
@ -421,7 +420,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoValue() throws Exception
|
public void testNoValue()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / HTTP/1.0\r\n" +
|
"GET / HTTP/1.0\r\n" +
|
||||||
|
@ -449,7 +448,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTrailingSpacesInHeaderNameNoCustom0() throws Exception
|
public void testTrailingSpacesInHeaderNameNoCustom0()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"HTTP/1.1 204 No Content\r\n" +
|
"HTTP/1.1 204 No Content\r\n" +
|
||||||
|
@ -468,7 +467,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoColon7230() throws Exception
|
public void testNoColon7230()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / HTTP/1.0\r\n" +
|
"GET / HTTP/1.0\r\n" +
|
||||||
|
@ -484,7 +483,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHeaderParseDirect() throws Exception
|
public void testHeaderParseDirect()
|
||||||
{
|
{
|
||||||
ByteBuffer b0 = BufferUtil.toBuffer(
|
ByteBuffer b0 = BufferUtil.toBuffer(
|
||||||
"GET / HTTP/1.0\r\n" +
|
"GET / HTTP/1.0\r\n" +
|
||||||
|
@ -535,7 +534,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHeaderParseCRLF() throws Exception
|
public void testHeaderParseCRLF()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / HTTP/1.0\r\n" +
|
"GET / HTTP/1.0\r\n" +
|
||||||
|
@ -581,7 +580,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHeaderParseLF() throws Exception
|
public void testHeaderParseLF()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / HTTP/1.0\n" +
|
"GET / HTTP/1.0\n" +
|
||||||
|
@ -627,7 +626,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testQuoted() throws Exception
|
public void testQuoted()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / HTTP/1.0\n" +
|
"GET / HTTP/1.0\n" +
|
||||||
|
@ -652,7 +651,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEncodedHeader() throws Exception
|
public void testEncodedHeader()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.allocate(4096);
|
ByteBuffer buffer = BufferUtil.allocate(4096);
|
||||||
BufferUtil.flipToFill(buffer);
|
BufferUtil.flipToFill(buffer);
|
||||||
|
@ -678,11 +677,11 @@ public class HttpParserTest
|
||||||
assertEquals("Header2", _hdr[1]);
|
assertEquals("Header2", _hdr[1]);
|
||||||
assertEquals("" + (char)255, _val[1]);
|
assertEquals("" + (char)255, _val[1]);
|
||||||
assertEquals(1, _headers);
|
assertEquals(1, _headers);
|
||||||
assertEquals(null, _bad);
|
assertNull(_bad);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testResponseBufferUpgradeFrom() throws Exception
|
public void testResponseBufferUpgradeFrom()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"HTTP/1.1 101 Upgrade\r\n" +
|
"HTTP/1.1 101 Upgrade\r\n" +
|
||||||
|
@ -704,7 +703,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBadMethodEncoding() throws Exception
|
public void testBadMethodEncoding()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"G\u00e6T / HTTP/1.0\r\nHeader0: value0\r\n\n\n");
|
"G\u00e6T / HTTP/1.0\r\nHeader0: value0\r\n\n\n");
|
||||||
|
@ -716,7 +715,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBadVersionEncoding() throws Exception
|
public void testBadVersionEncoding()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / H\u00e6P/1.0\r\nHeader0: value0\r\n\n\n");
|
"GET / H\u00e6P/1.0\r\nHeader0: value0\r\n\n\n");
|
||||||
|
@ -728,7 +727,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBadHeaderEncoding() throws Exception
|
public void testBadHeaderEncoding()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / HTTP/1.0\r\n" +
|
"GET / HTTP/1.0\r\n" +
|
||||||
|
@ -742,7 +741,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // TODO: Parameterize Test
|
@Test // TODO: Parameterize Test
|
||||||
public void testBadHeaderNames() throws Exception
|
public void testBadHeaderNames()
|
||||||
{
|
{
|
||||||
String[] bad = new String[]
|
String[] bad = new String[]
|
||||||
{
|
{
|
||||||
|
@ -763,20 +762,20 @@ public class HttpParserTest
|
||||||
"Foo[Bar: value\r\n",
|
"Foo[Bar: value\r\n",
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; i < bad.length; i++)
|
for (String s : bad)
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / HTTP/1.0\r\n" + bad[i] + "\r\n");
|
"GET / HTTP/1.0\r\n" + s + "\r\n");
|
||||||
|
|
||||||
HttpParser.RequestHandler handler = new Handler();
|
HttpParser.RequestHandler handler = new Handler();
|
||||||
HttpParser parser = new HttpParser(handler);
|
HttpParser parser = new HttpParser(handler);
|
||||||
parseAll(parser, buffer);
|
parseAll(parser, buffer);
|
||||||
assertThat(bad[i], _bad, Matchers.notNullValue());
|
assertThat(s, _bad, Matchers.notNullValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHeaderTab() throws Exception
|
public void testHeaderTab()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / HTTP/1.1\r\n" +
|
"GET / HTTP/1.1\r\n" +
|
||||||
|
@ -798,7 +797,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCaseSensitiveMethod() throws Exception
|
public void testCaseSensitiveMethod()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"gEt / http/1.0\r\n" +
|
"gEt / http/1.0\r\n" +
|
||||||
|
@ -814,7 +813,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCaseSensitiveMethodLegacy() throws Exception
|
public void testCaseSensitiveMethodLegacy()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"gEt / http/1.0\r\n" +
|
"gEt / http/1.0\r\n" +
|
||||||
|
@ -830,7 +829,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCaseInsensitiveHeader() throws Exception
|
public void testCaseInsensitiveHeader()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / http/1.0\r\n" +
|
"GET / http/1.0\r\n" +
|
||||||
|
@ -853,7 +852,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCaseInSensitiveHeaderLegacy() throws Exception
|
public void testCaseInSensitiveHeaderLegacy()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / http/1.0\r\n" +
|
"GET / http/1.0\r\n" +
|
||||||
|
@ -876,7 +875,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSplitHeaderParse() throws Exception
|
public void testSplitHeaderParse()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"XXXXSPLIT / HTTP/1.0\r\n" +
|
"XXXXSPLIT / HTTP/1.0\r\n" +
|
||||||
|
@ -929,7 +928,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testChunkParse() throws Exception
|
public void testChunkParse()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET /chunk HTTP/1.0\r\n" +
|
"GET /chunk HTTP/1.0\r\n" +
|
||||||
|
@ -959,7 +958,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBadChunkParse() throws Exception
|
public void testBadChunkParse()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET /chunk HTTP/1.0\r\n" +
|
"GET /chunk HTTP/1.0\r\n" +
|
||||||
|
@ -983,7 +982,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testChunkParseTrailer() throws Exception
|
public void testChunkParseTrailer()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET /chunk HTTP/1.0\r\n" +
|
"GET /chunk HTTP/1.0\r\n" +
|
||||||
|
@ -1018,7 +1017,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testChunkParseTrailers() throws Exception
|
public void testChunkParseTrailers()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET /chunk HTTP/1.0\r\n" +
|
"GET /chunk HTTP/1.0\r\n" +
|
||||||
|
@ -1056,7 +1055,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testChunkParseBadTrailer() throws Exception
|
public void testChunkParseBadTrailer()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET /chunk HTTP/1.0\r\n" +
|
"GET /chunk HTTP/1.0\r\n" +
|
||||||
|
@ -1088,7 +1087,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testChunkParseNoTrailer() throws Exception
|
public void testChunkParseNoTrailer()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET /chunk HTTP/1.0\r\n" +
|
"GET /chunk HTTP/1.0\r\n" +
|
||||||
|
@ -1119,7 +1118,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testStartEOF() throws Exception
|
public void testStartEOF()
|
||||||
{
|
{
|
||||||
HttpParser.RequestHandler handler = new Handler();
|
HttpParser.RequestHandler handler = new Handler();
|
||||||
HttpParser parser = new HttpParser(handler);
|
HttpParser parser = new HttpParser(handler);
|
||||||
|
@ -1127,11 +1126,11 @@ public class HttpParserTest
|
||||||
parser.parseNext(BufferUtil.EMPTY_BUFFER);
|
parser.parseNext(BufferUtil.EMPTY_BUFFER);
|
||||||
|
|
||||||
assertTrue(_early);
|
assertTrue(_early);
|
||||||
assertEquals(null, _bad);
|
assertNull(_bad);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEarlyEOF() throws Exception
|
public void testEarlyEOF()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET /uri HTTP/1.0\r\n" +
|
"GET /uri HTTP/1.0\r\n" +
|
||||||
|
@ -1152,7 +1151,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testChunkEarlyEOF() throws Exception
|
public void testChunkEarlyEOF()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET /chunk HTTP/1.0\r\n" +
|
"GET /chunk HTTP/1.0\r\n" +
|
||||||
|
@ -1178,7 +1177,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMultiParse() throws Exception
|
public void testMultiParse()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET /mp HTTP/1.0\r\n" +
|
"GET /mp HTTP/1.0\r\n" +
|
||||||
|
@ -1227,7 +1226,7 @@ public class HttpParserTest
|
||||||
assertEquals(2, _headers);
|
assertEquals(2, _headers);
|
||||||
assertEquals("Header2", _hdr[1]);
|
assertEquals("Header2", _hdr[1]);
|
||||||
assertEquals("value2", _val[1]);
|
assertEquals("value2", _val[1]);
|
||||||
assertEquals(null, _content);
|
assertNull(_content);
|
||||||
|
|
||||||
parser.reset();
|
parser.reset();
|
||||||
init();
|
init();
|
||||||
|
@ -1243,7 +1242,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMultiParseEarlyEOF() throws Exception
|
public void testMultiParseEarlyEOF()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer0 = BufferUtil.toBuffer(
|
ByteBuffer buffer0 = BufferUtil.toBuffer(
|
||||||
"GET /mp HTTP/1.0\r\n" +
|
"GET /mp HTTP/1.0\r\n" +
|
||||||
|
@ -1294,7 +1293,7 @@ public class HttpParserTest
|
||||||
assertEquals(2, _headers);
|
assertEquals(2, _headers);
|
||||||
assertEquals("Header2", _hdr[1]);
|
assertEquals("Header2", _hdr[1]);
|
||||||
assertEquals("value2", _val[1]);
|
assertEquals("value2", _val[1]);
|
||||||
assertEquals(null, _content);
|
assertNull(_content);
|
||||||
|
|
||||||
parser.reset();
|
parser.reset();
|
||||||
init();
|
init();
|
||||||
|
@ -1309,7 +1308,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testResponseParse0() throws Exception
|
public void testResponseParse0()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"HTTP/1.1 200 Correct\r\n" +
|
"HTTP/1.1 200 Correct\r\n" +
|
||||||
|
@ -1330,7 +1329,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testResponseParse1() throws Exception
|
public void testResponseParse1()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"HTTP/1.1 304 Not-Modified\r\n" +
|
"HTTP/1.1 304 Not-Modified\r\n" +
|
||||||
|
@ -1348,7 +1347,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testResponseParse2() throws Exception
|
public void testResponseParse2()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"HTTP/1.1 204 No-Content\r\n" +
|
"HTTP/1.1 204 No-Content\r\n" +
|
||||||
|
@ -1384,7 +1383,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testResponseParse3() throws Exception
|
public void testResponseParse3()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"HTTP/1.1 200\r\n" +
|
"HTTP/1.1 200\r\n" +
|
||||||
|
@ -1398,14 +1397,14 @@ public class HttpParserTest
|
||||||
parser.parseNext(buffer);
|
parser.parseNext(buffer);
|
||||||
assertEquals("HTTP/1.1", _methodOrVersion);
|
assertEquals("HTTP/1.1", _methodOrVersion);
|
||||||
assertEquals("200", _uriOrStatus);
|
assertEquals("200", _uriOrStatus);
|
||||||
assertEquals(null, _versionOrReason);
|
assertNull(_versionOrReason);
|
||||||
assertEquals(_content.length(), 10);
|
assertEquals(_content.length(), 10);
|
||||||
assertTrue(_headerCompleted);
|
assertTrue(_headerCompleted);
|
||||||
assertTrue(_messageCompleted);
|
assertTrue(_messageCompleted);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testResponseParse4() throws Exception
|
public void testResponseParse4()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"HTTP/1.1 200 \r\n" +
|
"HTTP/1.1 200 \r\n" +
|
||||||
|
@ -1419,14 +1418,14 @@ public class HttpParserTest
|
||||||
parser.parseNext(buffer);
|
parser.parseNext(buffer);
|
||||||
assertEquals("HTTP/1.1", _methodOrVersion);
|
assertEquals("HTTP/1.1", _methodOrVersion);
|
||||||
assertEquals("200", _uriOrStatus);
|
assertEquals("200", _uriOrStatus);
|
||||||
assertEquals(null, _versionOrReason);
|
assertNull(_versionOrReason);
|
||||||
assertEquals(_content.length(), 10);
|
assertEquals(_content.length(), 10);
|
||||||
assertTrue(_headerCompleted);
|
assertTrue(_headerCompleted);
|
||||||
assertTrue(_messageCompleted);
|
assertTrue(_messageCompleted);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testResponseEOFContent() throws Exception
|
public void testResponseEOFContent()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"HTTP/1.1 200 \r\n" +
|
"HTTP/1.1 200 \r\n" +
|
||||||
|
@ -1441,7 +1440,7 @@ public class HttpParserTest
|
||||||
|
|
||||||
assertEquals("HTTP/1.1", _methodOrVersion);
|
assertEquals("HTTP/1.1", _methodOrVersion);
|
||||||
assertEquals("200", _uriOrStatus);
|
assertEquals("200", _uriOrStatus);
|
||||||
assertEquals(null, _versionOrReason);
|
assertNull(_versionOrReason);
|
||||||
assertEquals(12, _content.length());
|
assertEquals(12, _content.length());
|
||||||
assertEquals("0123456789\r\n", _content);
|
assertEquals("0123456789\r\n", _content);
|
||||||
assertTrue(_headerCompleted);
|
assertTrue(_headerCompleted);
|
||||||
|
@ -1449,7 +1448,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testResponse304WithContentLength() throws Exception
|
public void testResponse304WithContentLength()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"HTTP/1.1 304 found\r\n" +
|
"HTTP/1.1 304 found\r\n" +
|
||||||
|
@ -1462,13 +1461,13 @@ public class HttpParserTest
|
||||||
assertEquals("HTTP/1.1", _methodOrVersion);
|
assertEquals("HTTP/1.1", _methodOrVersion);
|
||||||
assertEquals("304", _uriOrStatus);
|
assertEquals("304", _uriOrStatus);
|
||||||
assertEquals("found", _versionOrReason);
|
assertEquals("found", _versionOrReason);
|
||||||
assertEquals(null, _content);
|
assertNull(_content);
|
||||||
assertTrue(_headerCompleted);
|
assertTrue(_headerCompleted);
|
||||||
assertTrue(_messageCompleted);
|
assertTrue(_messageCompleted);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testResponse101WithTransferEncoding() throws Exception
|
public void testResponse101WithTransferEncoding()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"HTTP/1.1 101 switching protocols\r\n" +
|
"HTTP/1.1 101 switching protocols\r\n" +
|
||||||
|
@ -1481,13 +1480,13 @@ public class HttpParserTest
|
||||||
assertEquals("HTTP/1.1", _methodOrVersion);
|
assertEquals("HTTP/1.1", _methodOrVersion);
|
||||||
assertEquals("101", _uriOrStatus);
|
assertEquals("101", _uriOrStatus);
|
||||||
assertEquals("switching protocols", _versionOrReason);
|
assertEquals("switching protocols", _versionOrReason);
|
||||||
assertEquals(null, _content);
|
assertNull(_content);
|
||||||
assertTrue(_headerCompleted);
|
assertTrue(_headerCompleted);
|
||||||
assertTrue(_messageCompleted);
|
assertTrue(_messageCompleted);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testResponseReasonIso8859_1() throws Exception
|
public void testResponseReasonIso8859_1()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"HTTP/1.1 302 déplacé temporairement\r\n" +
|
"HTTP/1.1 302 déplacé temporairement\r\n" +
|
||||||
|
@ -1503,7 +1502,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSeekEOF() throws Exception
|
public void testSeekEOF()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"HTTP/1.1 200 OK\r\n" +
|
"HTTP/1.1 200 OK\r\n" +
|
||||||
|
@ -1520,7 +1519,7 @@ public class HttpParserTest
|
||||||
assertEquals("HTTP/1.1", _methodOrVersion);
|
assertEquals("HTTP/1.1", _methodOrVersion);
|
||||||
assertEquals("200", _uriOrStatus);
|
assertEquals("200", _uriOrStatus);
|
||||||
assertEquals("OK", _versionOrReason);
|
assertEquals("OK", _versionOrReason);
|
||||||
assertEquals(null, _content);
|
assertNull(_content);
|
||||||
assertTrue(_headerCompleted);
|
assertTrue(_headerCompleted);
|
||||||
assertTrue(_messageCompleted);
|
assertTrue(_messageCompleted);
|
||||||
|
|
||||||
|
@ -1535,7 +1534,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoURI() throws Exception
|
public void testNoURI()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET\r\n" +
|
"GET\r\n" +
|
||||||
|
@ -1547,7 +1546,7 @@ public class HttpParserTest
|
||||||
HttpParser parser = new HttpParser(handler);
|
HttpParser parser = new HttpParser(handler);
|
||||||
|
|
||||||
parser.parseNext(buffer);
|
parser.parseNext(buffer);
|
||||||
assertEquals(null, _methodOrVersion);
|
assertNull(_methodOrVersion);
|
||||||
assertEquals("No URI", _bad);
|
assertEquals("No URI", _bad);
|
||||||
assertFalse(buffer.hasRemaining());
|
assertFalse(buffer.hasRemaining());
|
||||||
assertEquals(HttpParser.State.CLOSE, parser.getState());
|
assertEquals(HttpParser.State.CLOSE, parser.getState());
|
||||||
|
@ -1557,7 +1556,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoURI2() throws Exception
|
public void testNoURI2()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET \r\n" +
|
"GET \r\n" +
|
||||||
|
@ -1569,7 +1568,7 @@ public class HttpParserTest
|
||||||
HttpParser parser = new HttpParser(handler);
|
HttpParser parser = new HttpParser(handler);
|
||||||
|
|
||||||
parser.parseNext(buffer);
|
parser.parseNext(buffer);
|
||||||
assertEquals(null, _methodOrVersion);
|
assertNull(_methodOrVersion);
|
||||||
assertEquals("No URI", _bad);
|
assertEquals("No URI", _bad);
|
||||||
assertFalse(buffer.hasRemaining());
|
assertFalse(buffer.hasRemaining());
|
||||||
assertEquals(HttpParser.State.CLOSE, parser.getState());
|
assertEquals(HttpParser.State.CLOSE, parser.getState());
|
||||||
|
@ -1579,7 +1578,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUnknownReponseVersion() throws Exception
|
public void testUnknownReponseVersion()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"HPPT/7.7 200 OK\r\n" +
|
"HPPT/7.7 200 OK\r\n" +
|
||||||
|
@ -1591,7 +1590,7 @@ public class HttpParserTest
|
||||||
HttpParser parser = new HttpParser(handler);
|
HttpParser parser = new HttpParser(handler);
|
||||||
|
|
||||||
parser.parseNext(buffer);
|
parser.parseNext(buffer);
|
||||||
assertEquals(null, _methodOrVersion);
|
assertNull(_methodOrVersion);
|
||||||
assertEquals("Unknown Version", _bad);
|
assertEquals("Unknown Version", _bad);
|
||||||
assertFalse(buffer.hasRemaining());
|
assertFalse(buffer.hasRemaining());
|
||||||
assertEquals(HttpParser.State.CLOSE, parser.getState());
|
assertEquals(HttpParser.State.CLOSE, parser.getState());
|
||||||
|
@ -1601,7 +1600,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoStatus() throws Exception
|
public void testNoStatus()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"HTTP/1.1\r\n" +
|
"HTTP/1.1\r\n" +
|
||||||
|
@ -1613,7 +1612,7 @@ public class HttpParserTest
|
||||||
HttpParser parser = new HttpParser(handler);
|
HttpParser parser = new HttpParser(handler);
|
||||||
|
|
||||||
parser.parseNext(buffer);
|
parser.parseNext(buffer);
|
||||||
assertEquals(null, _methodOrVersion);
|
assertNull(_methodOrVersion);
|
||||||
assertEquals("No Status", _bad);
|
assertEquals("No Status", _bad);
|
||||||
assertFalse(buffer.hasRemaining());
|
assertFalse(buffer.hasRemaining());
|
||||||
assertEquals(HttpParser.State.CLOSE, parser.getState());
|
assertEquals(HttpParser.State.CLOSE, parser.getState());
|
||||||
|
@ -1623,7 +1622,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoStatus2() throws Exception
|
public void testNoStatus2()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"HTTP/1.1 \r\n" +
|
"HTTP/1.1 \r\n" +
|
||||||
|
@ -1635,7 +1634,7 @@ public class HttpParserTest
|
||||||
HttpParser parser = new HttpParser(handler);
|
HttpParser parser = new HttpParser(handler);
|
||||||
|
|
||||||
parser.parseNext(buffer);
|
parser.parseNext(buffer);
|
||||||
assertEquals(null, _methodOrVersion);
|
assertNull(_methodOrVersion);
|
||||||
assertEquals("No Status", _bad);
|
assertEquals("No Status", _bad);
|
||||||
assertFalse(buffer.hasRemaining());
|
assertFalse(buffer.hasRemaining());
|
||||||
assertEquals(HttpParser.State.CLOSE, parser.getState());
|
assertEquals(HttpParser.State.CLOSE, parser.getState());
|
||||||
|
@ -1645,7 +1644,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBadRequestVersion() throws Exception
|
public void testBadRequestVersion()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / HPPT/7.7\r\n" +
|
"GET / HPPT/7.7\r\n" +
|
||||||
|
@ -1657,7 +1656,7 @@ public class HttpParserTest
|
||||||
HttpParser parser = new HttpParser(handler);
|
HttpParser parser = new HttpParser(handler);
|
||||||
|
|
||||||
parser.parseNext(buffer);
|
parser.parseNext(buffer);
|
||||||
assertEquals(null, _methodOrVersion);
|
assertNull(_methodOrVersion);
|
||||||
assertEquals("Unknown Version", _bad);
|
assertEquals("Unknown Version", _bad);
|
||||||
assertFalse(buffer.hasRemaining());
|
assertFalse(buffer.hasRemaining());
|
||||||
assertEquals(HttpParser.State.CLOSE, parser.getState());
|
assertEquals(HttpParser.State.CLOSE, parser.getState());
|
||||||
|
@ -1675,7 +1674,7 @@ public class HttpParserTest
|
||||||
parser = new HttpParser(handler);
|
parser = new HttpParser(handler);
|
||||||
|
|
||||||
parser.parseNext(buffer);
|
parser.parseNext(buffer);
|
||||||
assertEquals(null, _methodOrVersion);
|
assertNull(_methodOrVersion);
|
||||||
assertEquals("Unknown Version", _bad);
|
assertEquals("Unknown Version", _bad);
|
||||||
assertFalse(buffer.hasRemaining());
|
assertFalse(buffer.hasRemaining());
|
||||||
assertEquals(HttpParser.State.CLOSE, parser.getState());
|
assertEquals(HttpParser.State.CLOSE, parser.getState());
|
||||||
|
@ -1685,7 +1684,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBadCR() throws Exception
|
public void testBadCR()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / HTTP/1.0\r\n" +
|
"GET / HTTP/1.0\r\n" +
|
||||||
|
@ -1723,7 +1722,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBadContentLength0() throws Exception
|
public void testBadContentLength0()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / HTTP/1.0\r\n" +
|
"GET / HTTP/1.0\r\n" +
|
||||||
|
@ -1745,7 +1744,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBadContentLength1() throws Exception
|
public void testBadContentLength1()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / HTTP/1.0\r\n" +
|
"GET / HTTP/1.0\r\n" +
|
||||||
|
@ -1767,7 +1766,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBadContentLength2() throws Exception
|
public void testBadContentLength2()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / HTTP/1.0\r\n" +
|
"GET / HTTP/1.0\r\n" +
|
||||||
|
@ -1879,7 +1878,6 @@ public class HttpParserTest
|
||||||
"0\r\n" +
|
"0\r\n" +
|
||||||
"\r\n");
|
"\r\n");
|
||||||
|
|
||||||
|
|
||||||
HttpParser.RequestHandler handler = new Handler();
|
HttpParser.RequestHandler handler = new Handler();
|
||||||
HttpParser parser = new HttpParser(handler, HttpCompliance.RFC2616_LEGACY);
|
HttpParser parser = new HttpParser(handler, HttpCompliance.RFC2616_LEGACY);
|
||||||
parseAll(parser, buffer);
|
parseAll(parser, buffer);
|
||||||
|
@ -1896,7 +1894,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHost() throws Exception
|
public void testHost()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / HTTP/1.1\r\n" +
|
"GET / HTTP/1.1\r\n" +
|
||||||
|
@ -1912,7 +1910,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUriHost11() throws Exception
|
public void testUriHost11()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET http://host/ HTTP/1.1\r\n" +
|
"GET http://host/ HTTP/1.1\r\n" +
|
||||||
|
@ -1928,7 +1926,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUriHost10() throws Exception
|
public void testUriHost10()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET http://host/ HTTP/1.0\r\n" +
|
"GET http://host/ HTTP/1.0\r\n" +
|
||||||
|
@ -1943,7 +1941,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoHost() throws Exception
|
public void testNoHost()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / HTTP/1.1\r\n" +
|
"GET / HTTP/1.1\r\n" +
|
||||||
|
@ -1957,7 +1955,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIPHost() throws Exception
|
public void testIPHost()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / HTTP/1.1\r\n" +
|
"GET / HTTP/1.1\r\n" +
|
||||||
|
@ -1973,7 +1971,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIPv6Host() throws Exception
|
public void testIPv6Host()
|
||||||
{
|
{
|
||||||
Assumptions.assumeTrue(Net.isIpv6InterfaceAvailable());
|
Assumptions.assumeTrue(Net.isIpv6InterfaceAvailable());
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
|
@ -1990,7 +1988,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBadIPv6Host() throws Exception
|
public void testBadIPv6Host()
|
||||||
{
|
{
|
||||||
try (StacklessLogging s = new StacklessLogging(HttpParser.class))
|
try (StacklessLogging s = new StacklessLogging(HttpParser.class))
|
||||||
{
|
{
|
||||||
|
@ -2008,7 +2006,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHostPort() throws Exception
|
public void testHostPort()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / HTTP/1.1\r\n" +
|
"GET / HTTP/1.1\r\n" +
|
||||||
|
@ -2024,7 +2022,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHostBadPort() throws Exception
|
public void testHostBadPort()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / HTTP/1.1\r\n" +
|
"GET / HTTP/1.1\r\n" +
|
||||||
|
@ -2039,7 +2037,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIPHostPort() throws Exception
|
public void testIPHostPort()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / HTTP/1.1\r\n" +
|
"GET / HTTP/1.1\r\n" +
|
||||||
|
@ -2055,7 +2053,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIPv6HostPort() throws Exception
|
public void testIPv6HostPort()
|
||||||
{
|
{
|
||||||
Assumptions.assumeTrue(Net.isIpv6InterfaceAvailable());
|
Assumptions.assumeTrue(Net.isIpv6InterfaceAvailable());
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
|
@ -2072,7 +2070,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEmptyHostPort() throws Exception
|
public void testEmptyHostPort()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / HTTP/1.1\r\n" +
|
"GET / HTTP/1.1\r\n" +
|
||||||
|
@ -2083,13 +2081,13 @@ public class HttpParserTest
|
||||||
HttpParser.RequestHandler handler = new Handler();
|
HttpParser.RequestHandler handler = new Handler();
|
||||||
HttpParser parser = new HttpParser(handler);
|
HttpParser parser = new HttpParser(handler);
|
||||||
parser.parseNext(buffer);
|
parser.parseNext(buffer);
|
||||||
assertEquals(null, _host);
|
assertNull(_host);
|
||||||
assertEquals(null, _bad);
|
assertNull(_bad);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("ReferenceEquality")
|
@SuppressWarnings("ReferenceEquality")
|
||||||
public void testCachedField() throws Exception
|
public void testCachedField()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / HTTP/1.1\r\n" +
|
"GET / HTTP/1.1\r\n" +
|
||||||
|
@ -2104,11 +2102,11 @@ public class HttpParserTest
|
||||||
|
|
||||||
buffer.position(0);
|
buffer.position(0);
|
||||||
parseAll(parser, buffer);
|
parseAll(parser, buffer);
|
||||||
assertTrue(field == _fields.get(0));
|
assertSame(field, _fields.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParseRequest() throws Exception
|
public void testParseRequest()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / HTTP/1.1\r\n" +
|
"GET / HTTP/1.1\r\n" +
|
||||||
|
@ -2137,7 +2135,7 @@ public class HttpParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHTTP2Preface() throws Exception
|
public void testHTTP2Preface()
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"PRI * HTTP/2.0\r\n" +
|
"PRI * HTTP/2.0\r\n" +
|
||||||
|
@ -2155,7 +2153,7 @@ public class HttpParserTest
|
||||||
assertEquals("*", _uriOrStatus);
|
assertEquals("*", _uriOrStatus);
|
||||||
assertEquals("HTTP/2.0", _versionOrReason);
|
assertEquals("HTTP/2.0", _versionOrReason);
|
||||||
assertEquals(-1, _headers);
|
assertEquals(-1, _headers);
|
||||||
assertEquals(null, _bad);
|
assertNull(_bad);
|
||||||
}
|
}
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
|
|
|
@ -23,6 +23,24 @@
|
||||||
<onlyAnalyze>org.eclipse.jetty.jaspi.*</onlyAnalyze>
|
<onlyAnalyze>org.eclipse.jetty.jaspi.*</onlyAnalyze>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.felix</groupId>
|
||||||
|
<artifactId>maven-bundle-plugin</artifactId>
|
||||||
|
<extensions>true</extensions>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>manifest</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<instructions>
|
||||||
|
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
|
||||||
|
<Provide-Capability>osgi.serviceloader;osgi.serviceloader=org.eclipse.jetty.security.Authenticator$Factory</Provide-Capability>
|
||||||
|
</instructions>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,9 @@
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
//
|
//
|
||||||
|
|
||||||
|
import org.eclipse.jetty.security.Authenticator;
|
||||||
|
import org.eclipse.jetty.security.jaspi.JaspiAuthenticatorFactory;
|
||||||
|
|
||||||
module org.eclipse.jetty.security.jaspi
|
module org.eclipse.jetty.security.jaspi
|
||||||
{
|
{
|
||||||
exports org.eclipse.jetty.security.jaspi;
|
exports org.eclipse.jetty.security.jaspi;
|
||||||
|
@ -28,4 +31,6 @@ module org.eclipse.jetty.security.jaspi
|
||||||
requires org.eclipse.jetty.security;
|
requires org.eclipse.jetty.security;
|
||||||
requires org.eclipse.jetty.server;
|
requires org.eclipse.jetty.server;
|
||||||
requires org.eclipse.jetty.util;
|
requires org.eclipse.jetty.util;
|
||||||
|
|
||||||
|
provides Authenticator.Factory with JaspiAuthenticatorFactory;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
org.eclipse.jetty.security.jaspi.JaspiAuthenticatorFactory
|
|
@ -24,6 +24,24 @@
|
||||||
<onlyAnalyze>org.eclipse.jetty.security.openid.*</onlyAnalyze>
|
<onlyAnalyze>org.eclipse.jetty.security.openid.*</onlyAnalyze>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.felix</groupId>
|
||||||
|
<artifactId>maven-bundle-plugin</artifactId>
|
||||||
|
<extensions>true</extensions>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>manifest</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<instructions>
|
||||||
|
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
|
||||||
|
<Provide-Capability>osgi.serviceloader;osgi.serviceloader=org.eclipse.jetty.security.Authenticator$Factory</Provide-Capability>
|
||||||
|
</instructions>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
|
|
@ -21,13 +21,12 @@ package org.eclipse.jetty.security.openid;
|
||||||
import javax.servlet.ServletContext;
|
import javax.servlet.ServletContext;
|
||||||
|
|
||||||
import org.eclipse.jetty.security.Authenticator;
|
import org.eclipse.jetty.security.Authenticator;
|
||||||
import org.eclipse.jetty.security.DefaultAuthenticatorFactory;
|
|
||||||
import org.eclipse.jetty.security.IdentityService;
|
import org.eclipse.jetty.security.IdentityService;
|
||||||
import org.eclipse.jetty.security.LoginService;
|
import org.eclipse.jetty.security.LoginService;
|
||||||
import org.eclipse.jetty.server.Server;
|
import org.eclipse.jetty.server.Server;
|
||||||
import org.eclipse.jetty.util.security.Constraint;
|
import org.eclipse.jetty.util.security.Constraint;
|
||||||
|
|
||||||
public class OpenIdAuthenticatorFactory extends DefaultAuthenticatorFactory
|
public class OpenIdAuthenticatorFactory implements Authenticator.Factory
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public Authenticator getAuthenticator(Server server, ServletContext context, Authenticator.AuthConfiguration configuration, IdentityService identityService, LoginService loginService)
|
public Authenticator getAuthenticator(Server server, ServletContext context, Authenticator.AuthConfiguration configuration, IdentityService identityService, LoginService loginService)
|
||||||
|
@ -35,6 +34,6 @@ public class OpenIdAuthenticatorFactory extends DefaultAuthenticatorFactory
|
||||||
String auth = configuration.getAuthMethod();
|
String auth = configuration.getAuthMethod();
|
||||||
if (Constraint.__OPENID_AUTH.equalsIgnoreCase(auth))
|
if (Constraint.__OPENID_AUTH.equalsIgnoreCase(auth))
|
||||||
return new OpenIdAuthenticator();
|
return new OpenIdAuthenticator();
|
||||||
return super.getAuthenticator(server, context, configuration, identityService, loginService);
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
org.eclipse.jetty.security.openid.OpenIdAuthenticatorFactory
|
|
@ -24,6 +24,23 @@
|
||||||
<onlyAnalyze>org.eclipse.jetty.security.*</onlyAnalyze>
|
<onlyAnalyze>org.eclipse.jetty.security.*</onlyAnalyze>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.felix</groupId>
|
||||||
|
<artifactId>maven-bundle-plugin</artifactId>
|
||||||
|
<extensions>true</extensions>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>manifest</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<instructions>
|
||||||
|
<Require-Capability>osgi.serviceloader; filter:="(osgi.serviceloader=org.eclipse.jetty.security.Authenticator$Factory)";resolution:=optional;cardinality:=multiple, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)";resolution:=optional</Require-Capability>
|
||||||
|
</instructions>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
//
|
//
|
||||||
|
|
||||||
|
import org.eclipse.jetty.security.Authenticator;
|
||||||
|
|
||||||
module org.eclipse.jetty.security
|
module org.eclipse.jetty.security
|
||||||
{
|
{
|
||||||
exports org.eclipse.jetty.security;
|
exports org.eclipse.jetty.security;
|
||||||
|
@ -30,4 +32,6 @@ module org.eclipse.jetty.security
|
||||||
requires static java.sql;
|
requires static java.sql;
|
||||||
// Only required if using SPNEGO.
|
// Only required if using SPNEGO.
|
||||||
requires static java.security.jgss;
|
requires static java.security.jgss;
|
||||||
|
|
||||||
|
uses Authenticator.Factory;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,10 +20,13 @@ package org.eclipse.jetty.security;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.ServiceLoader;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
@ -38,6 +41,7 @@ import org.eclipse.jetty.server.UserIdentity;
|
||||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||||
import org.eclipse.jetty.server.handler.ContextHandler.Context;
|
import org.eclipse.jetty.server.handler.ContextHandler.Context;
|
||||||
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||||
|
import org.eclipse.jetty.util.component.DumpableCollection;
|
||||||
import org.eclipse.jetty.util.log.Log;
|
import org.eclipse.jetty.util.log.Log;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
|
|
||||||
|
@ -58,20 +62,31 @@ import org.eclipse.jetty.util.log.Logger;
|
||||||
public abstract class SecurityHandler extends HandlerWrapper implements Authenticator.AuthConfiguration
|
public abstract class SecurityHandler extends HandlerWrapper implements Authenticator.AuthConfiguration
|
||||||
{
|
{
|
||||||
private static final Logger LOG = Log.getLogger(SecurityHandler.class);
|
private static final Logger LOG = Log.getLogger(SecurityHandler.class);
|
||||||
|
private static final List<Authenticator.Factory> __knownAuthenticatorFactories = new ArrayList<>();
|
||||||
|
|
||||||
private boolean _checkWelcomeFiles = false;
|
private boolean _checkWelcomeFiles = false;
|
||||||
private Authenticator _authenticator;
|
private Authenticator _authenticator;
|
||||||
private Authenticator.Factory _authenticatorFactory = new DefaultAuthenticatorFactory();
|
private Authenticator.Factory _authenticatorFactory;
|
||||||
private String _realmName;
|
private String _realmName;
|
||||||
private String _authMethod;
|
private String _authMethod;
|
||||||
private final Map<String, String> _initParameters = new HashMap<String, String>();
|
private final Map<String, String> _initParameters = new HashMap<>();
|
||||||
private LoginService _loginService;
|
private LoginService _loginService;
|
||||||
private IdentityService _identityService;
|
private IdentityService _identityService;
|
||||||
private boolean _renewSession = true;
|
private boolean _renewSession = true;
|
||||||
|
|
||||||
|
static
|
||||||
|
{
|
||||||
|
for (Authenticator.Factory factory : ServiceLoader.load(Authenticator.Factory.class))
|
||||||
|
{
|
||||||
|
__knownAuthenticatorFactories.add(factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
__knownAuthenticatorFactories.add(new DefaultAuthenticatorFactory());
|
||||||
|
}
|
||||||
|
|
||||||
protected SecurityHandler()
|
protected SecurityHandler()
|
||||||
{
|
{
|
||||||
addBean(_authenticatorFactory);
|
addBean(new DumpableCollection("knownAuthenticatorFactories", __knownAuthenticatorFactories));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -163,6 +178,14 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti
|
||||||
_authenticatorFactory = authenticatorFactory;
|
_authenticatorFactory = authenticatorFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the list of discovered authenticatorFactories
|
||||||
|
*/
|
||||||
|
public List<Authenticator.Factory> getKnownAuthenticatorFactories()
|
||||||
|
{
|
||||||
|
return __knownAuthenticatorFactories;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the realmName
|
* @return the realmName
|
||||||
*/
|
*/
|
||||||
|
@ -241,12 +264,12 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti
|
||||||
* @param key the init key
|
* @param key the init key
|
||||||
* @param value the init value
|
* @param value the init value
|
||||||
* @return previous value
|
* @return previous value
|
||||||
* @throws IllegalStateException if the SecurityHandler is running
|
* @throws IllegalStateException if the SecurityHandler is started
|
||||||
*/
|
*/
|
||||||
public String setInitParameter(String key, String value)
|
public String setInitParameter(String key, String value)
|
||||||
{
|
{
|
||||||
if (isRunning())
|
if (isStarted())
|
||||||
throw new IllegalStateException("running");
|
throw new IllegalStateException("started");
|
||||||
return _initParameters.put(key, value);
|
return _initParameters.put(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,9 +359,40 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti
|
||||||
throw new IllegalStateException("LoginService has different IdentityService to " + this);
|
throw new IllegalStateException("LoginService has different IdentityService to " + this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Authenticator.Factory authenticatorFactory = getAuthenticatorFactory();
|
if (_authenticator == null && _identityService != null)
|
||||||
if (_authenticator == null && authenticatorFactory != null && _identityService != null)
|
{
|
||||||
setAuthenticator(authenticatorFactory.getAuthenticator(getServer(), ContextHandler.getCurrentContext(), this, _identityService, _loginService));
|
// If someone has set an authenticator factory only use that, otherwise try the list of discovered factories.
|
||||||
|
if (_authenticatorFactory != null)
|
||||||
|
{
|
||||||
|
Authenticator authenticator = _authenticatorFactory.getAuthenticator(getServer(), ContextHandler.getCurrentContext(),
|
||||||
|
this, _identityService, _loginService);
|
||||||
|
|
||||||
|
if (authenticator != null)
|
||||||
|
{
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("Created authenticator {} with {}", authenticator, _authenticatorFactory);
|
||||||
|
|
||||||
|
setAuthenticator(authenticator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (Authenticator.Factory factory : getKnownAuthenticatorFactories())
|
||||||
|
{
|
||||||
|
Authenticator authenticator = factory.getAuthenticator(getServer(), ContextHandler.getCurrentContext(),
|
||||||
|
this, _identityService, _loginService);
|
||||||
|
|
||||||
|
if (authenticator != null)
|
||||||
|
{
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("Created authenticator {} with {}", authenticator, factory);
|
||||||
|
|
||||||
|
setAuthenticator(authenticator);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (_authenticator != null)
|
if (_authenticator != null)
|
||||||
_authenticator.setConfiguration(this);
|
_authenticator.setConfiguration(this);
|
||||||
|
|
|
@ -27,11 +27,9 @@ import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.servlet.RequestDispatcher;
|
import javax.servlet.RequestDispatcher;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
@ -106,16 +104,24 @@ public class ErrorHandler extends AbstractHandler
|
||||||
{
|
{
|
||||||
if (errorDispatcher != null)
|
if (errorDispatcher != null)
|
||||||
{
|
{
|
||||||
errorDispatcher.error(request, response);
|
try
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
|
errorDispatcher.error(request, response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (ServletException e)
|
||||||
|
{
|
||||||
|
LOG.debug(e);
|
||||||
|
if (response.isCommitted())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String message = (String)request.getAttribute(Dispatcher.ERROR_MESSAGE);
|
String message = (String)request.getAttribute(Dispatcher.ERROR_MESSAGE);
|
||||||
if (message == null)
|
if (message == null)
|
||||||
message = baseRequest.getResponse().getReason();
|
message = baseRequest.getResponse().getReason();
|
||||||
generateAcceptableResponse(baseRequest, request, response, response.getStatus(), message);
|
generateAcceptableResponse(baseRequest, request, response, response.getStatus(), message);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
|
|
|
@ -601,11 +601,11 @@ public class Main
|
||||||
}
|
}
|
||||||
catch (ConnectException e)
|
catch (ConnectException e)
|
||||||
{
|
{
|
||||||
usageExit(e, ERR_NOT_STOPPED, jsvcStartArgs.isTestingModeEnabled());
|
usageExit(e, ERR_NOT_STOPPED, jsvcStartArgs != null && jsvcStartArgs.isTestingModeEnabled());
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
usageExit(e, ERR_UNKNOWN, jsvcStartArgs.isTestingModeEnabled());
|
usageExit(e, ERR_UNKNOWN, jsvcStartArgs != null && jsvcStartArgs.isTestingModeEnabled());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -381,4 +381,11 @@ public class JarFileResource extends JarResource
|
||||||
URL url = new URL(string);
|
URL url = new URL(string);
|
||||||
return url.sameFile(resource.getURI().toURL());
|
return url.sameFile(resource.getURI().toURL());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public File getJarFile()
|
||||||
|
{
|
||||||
|
if (_file != null)
|
||||||
|
return _file;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,15 +20,17 @@ package org.eclipse.jetty.webapp;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import org.eclipse.jetty.server.Connector;
|
import org.eclipse.jetty.server.Connector;
|
||||||
import org.eclipse.jetty.server.NetworkConnector;
|
import org.eclipse.jetty.server.NetworkConnector;
|
||||||
import org.eclipse.jetty.server.Server;
|
import org.eclipse.jetty.server.Server;
|
||||||
import org.eclipse.jetty.util.IO;
|
import org.eclipse.jetty.util.IO;
|
||||||
import org.eclipse.jetty.util.URIUtil;
|
import org.eclipse.jetty.util.StringUtil;
|
||||||
import org.eclipse.jetty.util.log.Log;
|
import org.eclipse.jetty.util.log.Log;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
|
import org.eclipse.jetty.util.resource.JarFileResource;
|
||||||
import org.eclipse.jetty.util.resource.JarResource;
|
import org.eclipse.jetty.util.resource.JarResource;
|
||||||
import org.eclipse.jetty.util.resource.Resource;
|
import org.eclipse.jetty.util.resource.Resource;
|
||||||
import org.eclipse.jetty.util.resource.ResourceCollection;
|
import org.eclipse.jetty.util.resource.ResourceCollection;
|
||||||
|
@ -497,7 +499,7 @@ public class WebInfConfiguration extends AbstractConfiguration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Resource base
|
// Resource base
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Resource resource = context.getBaseResource();
|
Resource resource = context.getBaseResource();
|
||||||
|
@ -506,27 +508,21 @@ public class WebInfConfiguration extends AbstractConfiguration
|
||||||
if (context.getWar() == null || context.getWar().length() == 0)
|
if (context.getWar() == null || context.getWar().length() == 0)
|
||||||
throw new IllegalStateException("No resourceBase or war set for context");
|
throw new IllegalStateException("No resourceBase or war set for context");
|
||||||
|
|
||||||
// Set dir or WAR
|
// Set dir or WAR to resource
|
||||||
resource = context.newResource(context.getWar());
|
resource = context.newResource(context.getWar());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resource.getURI().getPath() != null)
|
String resourceBaseName = getResourceBaseName(resource);
|
||||||
{
|
canonicalName.append(resourceBaseName);
|
||||||
String tmp = URIUtil.decodePath(resource.getURI().getPath());
|
|
||||||
if (tmp.endsWith("/"))
|
|
||||||
tmp = tmp.substring(0, tmp.length() - 1);
|
|
||||||
if (tmp.endsWith("!"))
|
|
||||||
tmp = tmp.substring(0, tmp.length() - 1);
|
|
||||||
//get just the last part which is the filename
|
|
||||||
int i = tmp.lastIndexOf("/");
|
|
||||||
canonicalName.append(tmp.substring(i + 1, tmp.length()));
|
|
||||||
}
|
|
||||||
canonicalName.append("-");
|
canonicalName.append("-");
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
LOG.warn("Can't generate resourceBase as part of webapp tmp dir name " + e);
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug(e);
|
{
|
||||||
|
LOG.debug("Can't get resource base name", e);
|
||||||
|
}
|
||||||
|
canonicalName.append("-"); // empty resourceBaseName segment
|
||||||
}
|
}
|
||||||
|
|
||||||
//Context name
|
//Context name
|
||||||
|
@ -553,6 +549,70 @@ public class WebInfConfiguration extends AbstractConfiguration
|
||||||
|
|
||||||
canonicalName.append("-");
|
canonicalName.append("-");
|
||||||
|
|
||||||
return canonicalName.toString();
|
return StringUtil.sanitizeFileSystemName(canonicalName.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static String getResourceBaseName(Resource resource)
|
||||||
|
{
|
||||||
|
// Use File System and File interface if present
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File resourceFile = resource.getFile();
|
||||||
|
if ((resourceFile != null) && (resource instanceof JarFileResource))
|
||||||
|
{
|
||||||
|
resourceFile = ((JarFileResource)resource).getJarFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resourceFile != null)
|
||||||
|
{
|
||||||
|
return resourceFile.getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
{
|
||||||
|
LOG.debug("Resource has no File reference: {}", resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use URI itself.
|
||||||
|
URI uri = resource.getURI();
|
||||||
|
if (uri == null)
|
||||||
|
{
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
{
|
||||||
|
LOG.debug("Resource has no URI reference: {}", resource);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return getUriLastPathSegment(uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static String getUriLastPathSegment(URI uri)
|
||||||
|
{
|
||||||
|
String ssp = uri.getSchemeSpecificPart();
|
||||||
|
// strip off deep jar:file: reference information
|
||||||
|
int idx = ssp.indexOf("!/");
|
||||||
|
if (idx != -1)
|
||||||
|
{
|
||||||
|
ssp = ssp.substring(0, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strip off trailing '/' if present
|
||||||
|
if (ssp.endsWith("/"))
|
||||||
|
{
|
||||||
|
ssp = ssp.substring(0, ssp.length() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only interested in last segment
|
||||||
|
idx = ssp.lastIndexOf('/');
|
||||||
|
if (idx != -1)
|
||||||
|
{
|
||||||
|
ssp = ssp.substring(idx + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ssp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,211 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// 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.webapp;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.nio.file.FileSystem;
|
||||||
|
import java.nio.file.FileSystems;
|
||||||
|
import java.nio.file.FileVisitOption;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.text.Normalizer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.toolchain.test.FS;
|
||||||
|
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||||
|
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
|
||||||
|
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
|
||||||
|
import org.eclipse.jetty.util.log.Log;
|
||||||
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
|
import org.eclipse.jetty.util.resource.PathResource;
|
||||||
|
import org.eclipse.jetty.util.resource.Resource;
|
||||||
|
import org.junit.jupiter.api.condition.OS;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WebInfConfigurationTest
|
||||||
|
*/
|
||||||
|
@ExtendWith(WorkDirExtension.class)
|
||||||
|
public class WebInfConfigurationTest
|
||||||
|
{
|
||||||
|
private static final Logger LOG = Log.getLogger(WebInfConfigurationTest.class);
|
||||||
|
private static final String TEST_RESOURCE_JAR = "test-base-resource.jar";
|
||||||
|
|
||||||
|
public WorkDir workDir;
|
||||||
|
|
||||||
|
public static Stream<Arguments> rawResourceNames()
|
||||||
|
{
|
||||||
|
return Stream.of(
|
||||||
|
Arguments.of("/", ""),
|
||||||
|
Arguments.of("/a", "a")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("rawResourceNames")
|
||||||
|
public void testTinyGetResourceBaseName(String rawPath, String expectedName) throws IOException
|
||||||
|
{
|
||||||
|
Resource resource = Resource.newResource(rawPath);
|
||||||
|
assertThat(WebInfConfiguration.getResourceBaseName(resource), is(expectedName));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Stream<Arguments> fileBaseResourceNames()
|
||||||
|
{
|
||||||
|
return Stream.of(
|
||||||
|
Arguments.of("test.war", "test.war"),
|
||||||
|
Arguments.of("a/b/c/test.war", "test.war"),
|
||||||
|
Arguments.of("bar%2Fbaz/test.war", "test.war"),
|
||||||
|
Arguments.of("fizz buzz/test.war", "test.war"),
|
||||||
|
Arguments.of("another one/bites the dust/", "bites the dust"),
|
||||||
|
Arguments.of("another+one/bites+the+dust/", "bites+the+dust"),
|
||||||
|
Arguments.of("another%20one/bites%20the%20dust/", "bites%20the%20dust"),
|
||||||
|
Arguments.of("spanish/n\u00FAmero.war", "n\u00FAmero.war"),
|
||||||
|
Arguments.of("spanish/n%C3%BAmero.war", "n%C3%BAmero.war"),
|
||||||
|
Arguments.of("a/b!/", "b!"),
|
||||||
|
Arguments.of("a/b!/c/", "c"),
|
||||||
|
Arguments.of("a/b!/c/d/", "d"),
|
||||||
|
Arguments.of("a/b%21/", "b%21")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("fileBaseResourceNames")
|
||||||
|
public void testPathGetResourceBaseName(String basePath, String expectedName) throws IOException
|
||||||
|
{
|
||||||
|
Path root = workDir.getPath();
|
||||||
|
Path base = root.resolve(basePath);
|
||||||
|
if (basePath.endsWith("/"))
|
||||||
|
{
|
||||||
|
// we are working with a directory.
|
||||||
|
FS.ensureDirExists(base);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FS.ensureDirExists(base.getParent());
|
||||||
|
FS.touch(base);
|
||||||
|
}
|
||||||
|
|
||||||
|
Resource resource = new PathResource(base);
|
||||||
|
assertThat(WebInfConfiguration.getResourceBaseName(resource), is(expectedName));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Stream<Arguments> fileUriBaseResourceNames()
|
||||||
|
{
|
||||||
|
return Stream.of(
|
||||||
|
Arguments.of("test.war", "test.war"),
|
||||||
|
Arguments.of("a/b/c/test.war", "test.war"),
|
||||||
|
Arguments.of("bar%2Fbaz/test.war", "test.war"),
|
||||||
|
Arguments.of("fizz buzz/test.war", "test.war"),
|
||||||
|
Arguments.of("another one/bites the dust/", "bites the dust"),
|
||||||
|
Arguments.of("another+one/bites+the+dust/", "bites+the+dust"),
|
||||||
|
Arguments.of("another%20one/bites%20the%20dust/", "bites%20the%20dust"),
|
||||||
|
Arguments.of("spanish/n\u00FAmero.war", "n\u00FAmero.war"),
|
||||||
|
Arguments.of("spanish/n%C3%BAmero.war", "n%C3%BAmero.war"),
|
||||||
|
Arguments.of("a/b!/", "b"),
|
||||||
|
Arguments.of("a/b!/c/", "b"),
|
||||||
|
Arguments.of("a/b!/c/d/", "b"),
|
||||||
|
Arguments.of("a/b%21/", "b%21")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Similar to testPathGetResourceBaseName, but with "file:" URIs
|
||||||
|
*/
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("fileUriBaseResourceNames")
|
||||||
|
public void testFileUriGetUriLastPathSegment(String basePath, String expectedName) throws IOException
|
||||||
|
{
|
||||||
|
Path root = workDir.getPath();
|
||||||
|
Path base = root.resolve(basePath);
|
||||||
|
if (basePath.endsWith("/"))
|
||||||
|
{
|
||||||
|
FS.ensureDirExists(base);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FS.ensureDirExists(base.getParent());
|
||||||
|
FS.touch(base);
|
||||||
|
}
|
||||||
|
URI uri = base.toUri();
|
||||||
|
if (OS.MAC.isCurrentOs())
|
||||||
|
{
|
||||||
|
// Normalize Unicode to NFD form that OSX Path/FileSystem produces
|
||||||
|
expectedName = Normalizer.normalize(expectedName, Normalizer.Form.NFD);
|
||||||
|
}
|
||||||
|
assertThat(WebInfConfiguration.getUriLastPathSegment(uri), is(expectedName));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Stream<Arguments> uriLastSegmentSource() throws URISyntaxException, IOException
|
||||||
|
{
|
||||||
|
Path testJar = MavenTestingUtils.getTestResourcePathFile(TEST_RESOURCE_JAR);
|
||||||
|
URI uri = new URI("jar", testJar.toUri().toASCIIString(), null);
|
||||||
|
|
||||||
|
Map<String, Object> env = new HashMap<>();
|
||||||
|
env.put("multi-release", "runtime");
|
||||||
|
|
||||||
|
List<Arguments> arguments = new ArrayList<>();
|
||||||
|
arguments.add(Arguments.of(uri, TEST_RESOURCE_JAR));
|
||||||
|
try (FileSystem zipFs = FileSystems.newFileSystem(uri, env))
|
||||||
|
{
|
||||||
|
FileVisitOption[] fileVisitOptions = new FileVisitOption[]{};
|
||||||
|
|
||||||
|
for (Path root : zipFs.getRootDirectories())
|
||||||
|
{
|
||||||
|
Stream<Path> entryStream = Files.find(root, 10, (path, attrs) -> true, fileVisitOptions);
|
||||||
|
entryStream.forEach((path) ->
|
||||||
|
{
|
||||||
|
if (path.toString().endsWith("!/"))
|
||||||
|
{
|
||||||
|
// skip - JAR entry type not supported by Jetty
|
||||||
|
// TODO: re-enable once we start to use zipfs
|
||||||
|
LOG.warn("Skipping Unsupported entry: " + path.toUri());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
arguments.add(Arguments.of(path.toUri(), TEST_RESOURCE_JAR));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return arguments.stream();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests of URIs last segment, including "jar:file:" based URIs.
|
||||||
|
*/
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("uriLastSegmentSource")
|
||||||
|
public void testGetUriLastPathSegment(URI uri, String expectedName) throws IOException
|
||||||
|
{
|
||||||
|
assertThat(WebInfConfiguration.getUriLastPathSegment(uri), is(expectedName));
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
|
@ -545,13 +545,7 @@ public class JavaxWebSocketFrameHandler implements FrameHandler
|
||||||
|
|
||||||
public void onPing(Frame frame, Callback callback)
|
public void onPing(Frame frame, Callback callback)
|
||||||
{
|
{
|
||||||
ByteBuffer payload = BufferUtil.EMPTY_BUFFER;
|
ByteBuffer payload = BufferUtil.copy(frame.getPayload());
|
||||||
|
|
||||||
if (frame.hasPayload())
|
|
||||||
{
|
|
||||||
payload = ByteBuffer.allocate(frame.getPayloadLength());
|
|
||||||
BufferUtil.put(frame.getPayload(), payload);
|
|
||||||
}
|
|
||||||
coreSession.sendFrame(new Frame(OpCode.PONG).setPayload(payload), Callback.NOOP, false);
|
coreSession.sendFrame(new Frame(OpCode.PONG).setPayload(payload), Callback.NOOP, false);
|
||||||
callback.succeeded();
|
callback.succeeded();
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.websocket.javax.server.config;
|
package org.eclipse.jetty.websocket.javax.server.config;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ServiceLoader;
|
import java.util.ServiceLoader;
|
||||||
import javax.websocket.Extension;
|
import javax.websocket.Extension;
|
||||||
|
@ -28,6 +29,7 @@ import javax.websocket.server.ServerEndpointConfig.Configurator;
|
||||||
|
|
||||||
import org.eclipse.jetty.util.log.Log;
|
import org.eclipse.jetty.util.log.Log;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
|
import org.eclipse.jetty.websocket.core.ExtensionConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The "Container Default Configurator" per the JSR-356 spec.
|
* The "Container Default Configurator" per the JSR-356 spec.
|
||||||
|
@ -78,7 +80,16 @@ public final class ContainerDefaultConfigurator extends Configurator
|
||||||
@Override
|
@Override
|
||||||
public List<Extension> getNegotiatedExtensions(List<Extension> installed, List<Extension> requested)
|
public List<Extension> getNegotiatedExtensions(List<Extension> installed, List<Extension> requested)
|
||||||
{
|
{
|
||||||
return requested;
|
List<Extension> negotiatedExtensions = new ArrayList<>();
|
||||||
|
for (Extension ext : requested)
|
||||||
|
{
|
||||||
|
// Only choose the first extension if multiple with the same name.
|
||||||
|
long matches = negotiatedExtensions.stream().filter(e -> e.getName().equals(ext.getName())).count();
|
||||||
|
if (matches == 0)
|
||||||
|
negotiatedExtensions.add(ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
return negotiatedExtensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"options": {
|
||||||
|
"failByDrop": false
|
||||||
|
},
|
||||||
|
"outdir": "./target/reports/servers",
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"agent": "Jetty-10.0.0-SNAPSHOT",
|
||||||
|
"url": "ws://127.0.0.1:9001",
|
||||||
|
"options": {
|
||||||
|
"version": 18
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"cases": ["*"],
|
||||||
|
"exclude-cases": [],
|
||||||
|
"exclude-agent-cases": {}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"options": {
|
||||||
|
"failByDrop": false
|
||||||
|
},
|
||||||
|
"url": "ws://127.0.0.1:9001",
|
||||||
|
"outdir": "./target/reports/clients",
|
||||||
|
"cases": ["*"],
|
||||||
|
"exclude-cases": [],
|
||||||
|
"exclude-agent-cases": {}
|
||||||
|
}
|
|
@ -52,28 +52,32 @@ public class EventSocket
|
||||||
public void onOpen(Session session)
|
public void onOpen(Session session)
|
||||||
{
|
{
|
||||||
this.session = session;
|
this.session = session;
|
||||||
LOG.info("{} onOpen(): {}", toString(), session);
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("{} onOpen(): {}", toString(), session);
|
||||||
openLatch.countDown();
|
openLatch.countDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnMessage
|
@OnMessage
|
||||||
public void onMessage(String message) throws IOException
|
public void onMessage(String message) throws IOException
|
||||||
{
|
{
|
||||||
LOG.info("{} onMessage(): {}", toString(), message);
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("{} onMessage(): {}", toString(), message);
|
||||||
messageQueue.offer(message);
|
messageQueue.offer(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClose
|
@OnClose
|
||||||
public void onClose(CloseReason reason)
|
public void onClose(CloseReason reason)
|
||||||
{
|
{
|
||||||
LOG.info("{} onClose(): {}", toString(), reason);
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("{} onClose(): {}", toString(), reason);
|
||||||
closeLatch.countDown();
|
closeLatch.countDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnError
|
@OnError
|
||||||
public void onError(Throwable cause)
|
public void onError(Throwable cause)
|
||||||
{
|
{
|
||||||
LOG.info("{} onError(): {}", toString(), cause);
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("{} onError(): {}", toString(), cause);
|
||||||
error = cause;
|
error = cause;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,200 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// 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.websocket.javax.tests.autobahn;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import javax.websocket.CloseReason;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.util.Jetty;
|
||||||
|
import org.eclipse.jetty.util.UrlEncoded;
|
||||||
|
import org.eclipse.jetty.util.component.LifeCycle;
|
||||||
|
import org.eclipse.jetty.util.log.Log;
|
||||||
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
|
import org.eclipse.jetty.websocket.javax.client.JavaxWebSocketClientContainer;
|
||||||
|
import org.eclipse.jetty.websocket.javax.tests.EventSocket;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WebSocket Client for use with <a href="https://github.com/crossbario/autobahn-testsuite">autobahn websocket testsuite</a> (wstest).
|
||||||
|
* <p>
|
||||||
|
* Installing Autobahn:
|
||||||
|
* </p>
|
||||||
|
* <pre>
|
||||||
|
* # For Debian / Ubuntu
|
||||||
|
* $ sudo apt-get install python python-dev python-twisted
|
||||||
|
* $ sudo apt-get install python-pip
|
||||||
|
* $ sudo pip install autobahntestsuite
|
||||||
|
*
|
||||||
|
* # For Fedora / Redhat
|
||||||
|
* $ sudo yum install python python-dev python-pip twisted
|
||||||
|
* $ sudo yum install libffi-devel
|
||||||
|
* $ sudo pip install autobahntestsuite
|
||||||
|
* </pre>
|
||||||
|
* <p>
|
||||||
|
* Upgrading an existing installation of autobahntestsuite
|
||||||
|
* </p>
|
||||||
|
* <pre>
|
||||||
|
* $ sudo pip install -U autobahntestsuite
|
||||||
|
* </pre>
|
||||||
|
* <p>
|
||||||
|
* Running Autobahn Fuzzing Server (which you run this client implementation against):
|
||||||
|
* </p>
|
||||||
|
* <pre>
|
||||||
|
* # Change to javax-websocket-tests directory first.
|
||||||
|
* $ cd jetty-websocket/javax-websocket-tests/
|
||||||
|
* $ wstest --mode=fuzzingserver --spec=fuzzingserver.json
|
||||||
|
*
|
||||||
|
* # Report output is configured (in the fuzzingserver.json) at location:
|
||||||
|
* $ ls target/reports/clients/
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public class JavaxAutobahnClient
|
||||||
|
{
|
||||||
|
public static void main(String[] args)
|
||||||
|
{
|
||||||
|
String hostname = "localhost";
|
||||||
|
int port = 9001;
|
||||||
|
|
||||||
|
if (args.length > 0)
|
||||||
|
hostname = args[0];
|
||||||
|
if (args.length > 1)
|
||||||
|
port = Integer.parseInt(args[1]);
|
||||||
|
|
||||||
|
// Optional case numbers
|
||||||
|
// NOTE: these are url query parameter case numbers (whole integers, eg "6"), not the case ids (eg "7.3.1")
|
||||||
|
int[] caseNumbers = null;
|
||||||
|
if (args.length > 2)
|
||||||
|
{
|
||||||
|
int offset = 2;
|
||||||
|
caseNumbers = new int[args.length - offset];
|
||||||
|
for (int i = offset; i < args.length; i++)
|
||||||
|
{
|
||||||
|
caseNumbers[i - offset] = Integer.parseInt(args[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JavaxAutobahnClient client = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String userAgent = "JettyWebsocketClient/" + Jetty.VERSION;
|
||||||
|
client = new JavaxAutobahnClient(hostname, port, userAgent);
|
||||||
|
|
||||||
|
LOG.info("Running test suite...");
|
||||||
|
LOG.info("Using Fuzzing Server: {}:{}", hostname, port);
|
||||||
|
LOG.info("User Agent: {}", userAgent);
|
||||||
|
|
||||||
|
if (caseNumbers == null)
|
||||||
|
{
|
||||||
|
int caseCount = client.getCaseCount();
|
||||||
|
LOG.info("Will run all {} cases ...", caseCount);
|
||||||
|
for (int caseNum = 1; caseNum <= caseCount; caseNum++)
|
||||||
|
{
|
||||||
|
LOG.info("Running case {} (of {}) ...", caseNum, caseCount);
|
||||||
|
client.runCaseByNumber(caseNum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG.info("Will run %d cases ...", caseNumbers.length);
|
||||||
|
for (int caseNum : caseNumbers)
|
||||||
|
{
|
||||||
|
client.runCaseByNumber(caseNum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOG.info("All test cases executed.");
|
||||||
|
client.updateReports();
|
||||||
|
}
|
||||||
|
catch (Throwable t)
|
||||||
|
{
|
||||||
|
LOG.warn("Test Failed", t);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (client != null)
|
||||||
|
client.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Logger LOG = Log.getLogger(JavaxAutobahnClient.class);
|
||||||
|
private URI baseWebsocketUri;
|
||||||
|
private JavaxWebSocketClientContainer clientContainer;
|
||||||
|
private String userAgent;
|
||||||
|
|
||||||
|
public JavaxAutobahnClient(String hostname, int port, String userAgent) throws Exception
|
||||||
|
{
|
||||||
|
this.userAgent = userAgent;
|
||||||
|
this.baseWebsocketUri = new URI("ws://" + hostname + ":" + port);
|
||||||
|
this.clientContainer = new JavaxWebSocketClientContainer();
|
||||||
|
clientContainer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop()
|
||||||
|
{
|
||||||
|
LifeCycle.stop(clientContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCaseCount()
|
||||||
|
{
|
||||||
|
URI wsUri = baseWebsocketUri.resolve("/getCaseCount");
|
||||||
|
EventSocket onCaseCount = new EventSocket();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
clientContainer.connectToServer(onCaseCount, wsUri);
|
||||||
|
String msg = onCaseCount.messageQueue.poll(10, TimeUnit.SECONDS);
|
||||||
|
onCaseCount.session.close(new CloseReason(CloseReason.CloseCodes.GOING_AWAY, null));
|
||||||
|
assertTrue(onCaseCount.closeLatch.await(2, TimeUnit.SECONDS));
|
||||||
|
assertNotNull(msg);
|
||||||
|
return Integer.decode(msg);
|
||||||
|
}
|
||||||
|
catch (Throwable t)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("Unable to get Case Count", t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runCaseByNumber(int caseNumber) throws Exception
|
||||||
|
{
|
||||||
|
URI wsUri = baseWebsocketUri.resolve("/runCase?case=" + caseNumber + "&agent=" + UrlEncoded.encodeString(userAgent));
|
||||||
|
LOG.info("test uri: {}", wsUri);
|
||||||
|
|
||||||
|
JavaxAutobahnSocket echoHandler = new JavaxAutobahnSocket();
|
||||||
|
clientContainer.connectToServer(echoHandler, wsUri);
|
||||||
|
|
||||||
|
// Wait up to 5 min as some of the tests can take a while
|
||||||
|
if (!echoHandler.closeLatch.await(5, TimeUnit.MINUTES))
|
||||||
|
{
|
||||||
|
LOG.warn("could not close {}, closing session", echoHandler);
|
||||||
|
echoHandler.session.close(new CloseReason(CloseReason.CloseCodes.GOING_AWAY, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateReports() throws Exception
|
||||||
|
{
|
||||||
|
URI wsUri = baseWebsocketUri.resolve("/updateReports?agent=" + UrlEncoded.encodeString(userAgent));
|
||||||
|
EventSocket onUpdateReports = new EventSocket();
|
||||||
|
clientContainer.connectToServer(onUpdateReports, wsUri);
|
||||||
|
assertTrue(onUpdateReports.closeLatch.await(15, TimeUnit.SECONDS));
|
||||||
|
LOG.info("Reports updated.");
|
||||||
|
LOG.info("Test suite finished!");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// 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.websocket.javax.tests.autobahn;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.server.ServerConnector;
|
||||||
|
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||||
|
import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WebSocket Server for use with <a href="https://github.com/crossbario/autobahn-testsuite">autobahn websocket testsuite</a> (wstest).
|
||||||
|
* <p>
|
||||||
|
* Installing Autobahn:
|
||||||
|
* </p>
|
||||||
|
* <pre>
|
||||||
|
* # For Debian / Ubuntu
|
||||||
|
* $ sudo apt-get install python python-dev python-twisted
|
||||||
|
* $ sudo apt-get install python-pip
|
||||||
|
* $ sudo pip install autobahntestsuite
|
||||||
|
*
|
||||||
|
* # For Fedora / Redhat
|
||||||
|
* $ sudo yum install python python-dev python-pip twisted
|
||||||
|
* $ sudo yum install libffi-devel
|
||||||
|
* $ sudo pip install autobahntestsuite
|
||||||
|
* </pre>
|
||||||
|
* <p>
|
||||||
|
* Upgrading an existing installation of autobahntestsuite
|
||||||
|
* </p>
|
||||||
|
* <pre>
|
||||||
|
* $ sudo pip install -U autobahntestsuite
|
||||||
|
* </pre>
|
||||||
|
* <p>
|
||||||
|
* Running Autobahn Fuzzing Client (against this server implementation):
|
||||||
|
* </p>
|
||||||
|
* <pre>
|
||||||
|
* # Change to javax-websocket-tests directory first.
|
||||||
|
* $ cd jetty-websocket/javax-websocket-tests/
|
||||||
|
* $ wstest --mode=fuzzingclient --spec=fuzzingclient.json
|
||||||
|
*
|
||||||
|
* # Report output is configured (in the fuzzingclient.json) at location:
|
||||||
|
* $ ls target/reports/servers/
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public class JavaxAutobahnServer
|
||||||
|
{
|
||||||
|
public static void main(String[] args) throws Exception
|
||||||
|
{
|
||||||
|
int port = 9001; // same port as found in fuzzing-client.json
|
||||||
|
if (args != null && args.length > 0)
|
||||||
|
port = Integer.parseInt(args[0]);
|
||||||
|
|
||||||
|
Server server = new Server(port);
|
||||||
|
ServerConnector connector = new ServerConnector(server);
|
||||||
|
connector.setIdleTimeout(10000);
|
||||||
|
server.addConnector(connector);
|
||||||
|
ServletContextHandler context = new ServletContextHandler();
|
||||||
|
context.setContextPath("/");
|
||||||
|
server.setHandler(context);
|
||||||
|
|
||||||
|
JavaxWebSocketServletContainerInitializer.configure(context, (servletContext, container)->
|
||||||
|
container.addEndpoint(JavaxAutobahnSocket.class));
|
||||||
|
|
||||||
|
server.start();
|
||||||
|
server.join();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// 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.websocket.javax.tests.autobahn;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import javax.websocket.ClientEndpoint;
|
||||||
|
import javax.websocket.OnClose;
|
||||||
|
import javax.websocket.OnError;
|
||||||
|
import javax.websocket.OnMessage;
|
||||||
|
import javax.websocket.OnOpen;
|
||||||
|
import javax.websocket.Session;
|
||||||
|
import javax.websocket.server.ServerEndpoint;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.util.log.Log;
|
||||||
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
|
|
||||||
|
@ClientEndpoint
|
||||||
|
@ServerEndpoint("/")
|
||||||
|
public class JavaxAutobahnSocket
|
||||||
|
{
|
||||||
|
private static final Logger LOG = Log.getLogger(JavaxAutobahnSocket.class);
|
||||||
|
|
||||||
|
public Session session;
|
||||||
|
public CountDownLatch closeLatch = new CountDownLatch(1);
|
||||||
|
|
||||||
|
@OnOpen
|
||||||
|
public void onConnect(Session session)
|
||||||
|
{
|
||||||
|
this.session = session;
|
||||||
|
session.setMaxTextMessageBufferSize(Integer.MAX_VALUE);
|
||||||
|
session.setMaxBinaryMessageBufferSize(Integer.MAX_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnMessage
|
||||||
|
public void onText(String message) throws IOException
|
||||||
|
{
|
||||||
|
session.getBasicRemote().sendText(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnMessage
|
||||||
|
public void onBinary(ByteBuffer message) throws IOException
|
||||||
|
{
|
||||||
|
session.getBasicRemote().sendBinary(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnError
|
||||||
|
public void onError(Throwable t)
|
||||||
|
{
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("onError()", t);
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnClose
|
||||||
|
public void onClose()
|
||||||
|
{
|
||||||
|
closeLatch.countDown();
|
||||||
|
}
|
||||||
|
}
|
|
@ -84,6 +84,20 @@ public interface WebSocketPolicy
|
||||||
*/
|
*/
|
||||||
long getMaxTextMessageSize();
|
long getMaxTextMessageSize();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum payload size of any WebSocket Frame which can be received.
|
||||||
|
*
|
||||||
|
* @return the maximum size of a WebSocket Frame.
|
||||||
|
*/
|
||||||
|
long getMaxFrameSize();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If true, frames are automatically fragmented to respect the maximum frame size.
|
||||||
|
*
|
||||||
|
* @return whether to automatically fragment incoming WebSocket Frames.
|
||||||
|
*/
|
||||||
|
boolean isAutoFragment();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The duration that a websocket may be idle before being closed by the implementation
|
* The duration that a websocket may be idle before being closed by the implementation
|
||||||
*
|
*
|
||||||
|
@ -123,4 +137,21 @@ public interface WebSocketPolicy
|
||||||
* @param size the maximum allowed size of a text message.
|
* @param size the maximum allowed size of a text message.
|
||||||
*/
|
*/
|
||||||
void setMaxTextMessageSize(long size);
|
void setMaxTextMessageSize(long size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum payload size of any WebSocket Frame which can be received.
|
||||||
|
* <p>
|
||||||
|
* WebSocket Frames over this maximum will result in a close code 1009 {@link StatusCode#MESSAGE_TOO_LARGE}
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param maxFrameSize the maximum allowed size of a WebSocket Frame.
|
||||||
|
*/
|
||||||
|
void setMaxFrameSize(long maxFrameSize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set to true, frames are automatically fragmented to respect the maximum frame size.
|
||||||
|
*
|
||||||
|
* @param autoFragment whether to automatically fragment incoming WebSocket Frames.
|
||||||
|
*/
|
||||||
|
void setAutoFragment(boolean autoFragment);
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,8 @@ import org.eclipse.jetty.websocket.api.Session;
|
||||||
* <p>
|
* <p>
|
||||||
* <u>Binary Message Versions</u>
|
* <u>Binary Message Versions</u>
|
||||||
* <ol>
|
* <ol>
|
||||||
|
* <li>{@code public void methodName(ByteBuffer message)}</li>
|
||||||
|
* <li><code>public void methodName({@link Session} session, ByteBuffer message)</code></li>
|
||||||
* <li>{@code public void methodName(byte buf[], int offset, int length)}</li>
|
* <li>{@code public void methodName(byte buf[], int offset, int length)}</li>
|
||||||
* <li><code>public void methodName({@link Session} session, byte buf[], int offset, int length)</code></li>
|
* <li><code>public void methodName({@link Session} session, byte buf[], int offset, int length)</code></li>
|
||||||
* <li>{@code public void methodName(InputStream stream)}</li>
|
* <li>{@code public void methodName(InputStream stream)}</li>
|
||||||
|
|
|
@ -41,6 +41,7 @@ import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||||
import org.eclipse.jetty.util.log.Log;
|
import org.eclipse.jetty.util.log.Log;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||||
|
import org.eclipse.jetty.util.thread.ShutdownThread;
|
||||||
import org.eclipse.jetty.websocket.api.Session;
|
import org.eclipse.jetty.websocket.api.Session;
|
||||||
import org.eclipse.jetty.websocket.api.UpgradeRequest;
|
import org.eclipse.jetty.websocket.api.UpgradeRequest;
|
||||||
import org.eclipse.jetty.websocket.api.WebSocketBehavior;
|
import org.eclipse.jetty.websocket.api.WebSocketBehavior;
|
||||||
|
@ -65,7 +66,8 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketPoli
|
||||||
private final List<WebSocketSessionListener> sessionListeners = new CopyOnWriteArrayList<>();
|
private final List<WebSocketSessionListener> sessionListeners = new CopyOnWriteArrayList<>();
|
||||||
private final SessionTracker sessionTracker = new SessionTracker();
|
private final SessionTracker sessionTracker = new SessionTracker();
|
||||||
private final FrameHandler.ConfigurationCustomizer configurationCustomizer = new FrameHandler.ConfigurationCustomizer();
|
private final FrameHandler.ConfigurationCustomizer configurationCustomizer = new FrameHandler.ConfigurationCustomizer();
|
||||||
private WebSocketComponents components = new WebSocketComponents();
|
private final WebSocketComponents components = new WebSocketComponents();
|
||||||
|
private boolean stopAtShutdown = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiate a WebSocketClient with defaults
|
* Instantiate a WebSocketClient with defaults
|
||||||
|
@ -235,6 +237,18 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketPoli
|
||||||
return configurationCustomizer.getMaxTextMessageSize();
|
return configurationCustomizer.getMaxTextMessageSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getMaxFrameSize()
|
||||||
|
{
|
||||||
|
return configurationCustomizer.getMaxFrameSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAutoFragment()
|
||||||
|
{
|
||||||
|
return configurationCustomizer.isAutoFragment();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setIdleTimeout(Duration duration)
|
public void setIdleTimeout(Duration duration)
|
||||||
{
|
{
|
||||||
|
@ -266,6 +280,18 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketPoli
|
||||||
configurationCustomizer.setMaxTextMessageSize(size);
|
configurationCustomizer.setMaxTextMessageSize(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMaxFrameSize(long maxFrameSize)
|
||||||
|
{
|
||||||
|
configurationCustomizer.setMaxFrameSize(maxFrameSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAutoFragment(boolean autoFragment)
|
||||||
|
{
|
||||||
|
configurationCustomizer.setAutoFragment(autoFragment);
|
||||||
|
}
|
||||||
|
|
||||||
public SocketAddress getBindAddress()
|
public SocketAddress getBindAddress()
|
||||||
{
|
{
|
||||||
return getHttpClient().getBindAddress();
|
return getHttpClient().getBindAddress();
|
||||||
|
@ -340,6 +366,31 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketPoli
|
||||||
return getHttpClient().getSslContextFactory();
|
return getHttpClient().getSslContextFactory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set JVM shutdown behavior.
|
||||||
|
* @param stop If true, this client instance will be explicitly stopped when the
|
||||||
|
* JVM is shutdown. Otherwise the application is responsible for maintaining the WebSocketClient lifecycle.
|
||||||
|
* @see Runtime#addShutdownHook(Thread)
|
||||||
|
* @see ShutdownThread
|
||||||
|
*/
|
||||||
|
public synchronized void setStopAtShutdown(boolean stop)
|
||||||
|
{
|
||||||
|
if (stop)
|
||||||
|
{
|
||||||
|
if (!stopAtShutdown && !ShutdownThread.isRegistered(this))
|
||||||
|
ShutdownThread.register(this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ShutdownThread.deregister(this);
|
||||||
|
|
||||||
|
stopAtShutdown = stop;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isStopAtShutdown()
|
||||||
|
{
|
||||||
|
return stopAtShutdown;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
|
|
|
@ -29,6 +29,7 @@ import org.eclipse.jetty.util.log.Logger;
|
||||||
import org.eclipse.jetty.websocket.api.BatchMode;
|
import org.eclipse.jetty.websocket.api.BatchMode;
|
||||||
import org.eclipse.jetty.websocket.api.UpgradeRequest;
|
import org.eclipse.jetty.websocket.api.UpgradeRequest;
|
||||||
import org.eclipse.jetty.websocket.api.UpgradeResponse;
|
import org.eclipse.jetty.websocket.api.UpgradeResponse;
|
||||||
|
import org.eclipse.jetty.websocket.api.WriteCallback;
|
||||||
import org.eclipse.jetty.websocket.common.invoke.InvalidSignatureException;
|
import org.eclipse.jetty.websocket.common.invoke.InvalidSignatureException;
|
||||||
import org.eclipse.jetty.websocket.core.BadPayloadException;
|
import org.eclipse.jetty.websocket.core.BadPayloadException;
|
||||||
import org.eclipse.jetty.websocket.core.CloseException;
|
import org.eclipse.jetty.websocket.core.CloseException;
|
||||||
|
@ -359,10 +360,8 @@ public class JettyWebSocketFrameHandler implements FrameHandler
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Automatically respond
|
// Automatically respond
|
||||||
Frame pong = new Frame(OpCode.PONG);
|
ByteBuffer payload = BufferUtil.copy(frame.getPayload());
|
||||||
if (frame.hasPayload())
|
getSession().getRemote().sendPong(payload, WriteCallback.NOOP);
|
||||||
pong.setPayload(frame.getPayload());
|
|
||||||
getSession().getRemote().getCoreSession().sendFrame(pong, Callback.NOOP, false);
|
|
||||||
}
|
}
|
||||||
callback.succeeded();
|
callback.succeeded();
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,6 +117,18 @@ public class WebSocketSession extends AbstractLifeCycle implements Session, Susp
|
||||||
return coreSession.getMaxTextMessageSize();
|
return coreSession.getMaxTextMessageSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getMaxFrameSize()
|
||||||
|
{
|
||||||
|
return coreSession.getMaxFrameSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAutoFragment()
|
||||||
|
{
|
||||||
|
return coreSession.isAutoFragment();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setIdleTimeout(Duration duration)
|
public void setIdleTimeout(Duration duration)
|
||||||
{
|
{
|
||||||
|
@ -147,6 +159,18 @@ public class WebSocketSession extends AbstractLifeCycle implements Session, Susp
|
||||||
coreSession.setMaxTextMessageSize(size);
|
coreSession.setMaxTextMessageSize(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMaxFrameSize(long maxFrameSize)
|
||||||
|
{
|
||||||
|
coreSession.setMaxFrameSize(maxFrameSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAutoFragment(boolean autoFragment)
|
||||||
|
{
|
||||||
|
coreSession.setAutoFragment(autoFragment);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getProtocolVersion()
|
public String getProtocolVersion()
|
||||||
{
|
{
|
||||||
|
|
|
@ -295,6 +295,18 @@ public class OutgoingMessageCapture extends FrameHandler.CoreSession.Empty imple
|
||||||
return maxMessageSize;
|
return maxMessageSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getMaxFrameSize()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAutoFragment()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setIdleTimeout(Duration duration)
|
public void setIdleTimeout(Duration duration)
|
||||||
{
|
{
|
||||||
|
@ -319,6 +331,16 @@ public class OutgoingMessageCapture extends FrameHandler.CoreSession.Empty imple
|
||||||
public void setMaxTextMessageSize(long size)
|
public void setMaxTextMessageSize(long size)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMaxFrameSize(long maxFrameSize)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAutoFragment(boolean autoFragment)
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -206,6 +206,18 @@ public class JettyWebSocketServerContainer extends ContainerLifeCycle implements
|
||||||
return customizer.getMaxTextMessageSize();
|
return customizer.getMaxTextMessageSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getMaxFrameSize()
|
||||||
|
{
|
||||||
|
return customizer.getMaxFrameSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAutoFragment()
|
||||||
|
{
|
||||||
|
return customizer.isAutoFragment();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setIdleTimeout(Duration duration)
|
public void setIdleTimeout(Duration duration)
|
||||||
{
|
{
|
||||||
|
@ -235,4 +247,16 @@ public class JettyWebSocketServerContainer extends ContainerLifeCycle implements
|
||||||
{
|
{
|
||||||
customizer.setMaxTextMessageSize(size);
|
customizer.setMaxTextMessageSize(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMaxFrameSize(long maxFrameSize)
|
||||||
|
{
|
||||||
|
customizer.setMaxFrameSize(maxFrameSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAutoFragment(boolean autoFragment)
|
||||||
|
{
|
||||||
|
customizer.setAutoFragment(autoFragment);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@ import java.time.Duration;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.eclipse.jetty.http.pathmap.PathSpec;
|
import org.eclipse.jetty.http.pathmap.PathSpec;
|
||||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
|
||||||
import org.eclipse.jetty.websocket.api.WebSocketBehavior;
|
import org.eclipse.jetty.websocket.api.WebSocketBehavior;
|
||||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||||
import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
|
import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
|
||||||
|
@ -50,44 +49,25 @@ public class JettyWebSocketServletFactory implements WebSocketPolicy
|
||||||
return WebSocketBehavior.SERVER;
|
return WebSocketBehavior.SERVER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* If true, frames are automatically fragmented to respect the maximum frame size.
|
|
||||||
*
|
|
||||||
* @return whether to automatically fragment incoming WebSocket Frames.
|
|
||||||
*/
|
|
||||||
public boolean isAutoFragment()
|
public boolean isAutoFragment()
|
||||||
{
|
{
|
||||||
return factory.isAutoFragment();
|
return factory.isAutoFragment();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* If set to true, frames are automatically fragmented to respect the maximum frame size.
|
|
||||||
*
|
|
||||||
* @param autoFragment whether to automatically fragment incoming WebSocket Frames.
|
|
||||||
*/
|
|
||||||
public void setAutoFragment(boolean autoFragment)
|
public void setAutoFragment(boolean autoFragment)
|
||||||
{
|
{
|
||||||
factory.setAutoFragment(autoFragment);
|
factory.setAutoFragment(autoFragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* The maximum payload size of any WebSocket Frame which can be received.
|
|
||||||
*
|
|
||||||
* @return the maximum size of a WebSocket Frame.
|
|
||||||
*/
|
|
||||||
public long getMaxFrameSize()
|
public long getMaxFrameSize()
|
||||||
{
|
{
|
||||||
return factory.getMaxFrameSize();
|
return factory.getMaxFrameSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* The maximum payload size of any WebSocket Frame which can be received.
|
|
||||||
* <p>
|
|
||||||
* WebSocket Frames over this maximum will result in a close code 1009 {@link StatusCode#MESSAGE_TOO_LARGE}
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param maxFrameSize the maximum allowed size of a WebSocket Frame.
|
|
||||||
*/
|
|
||||||
public void setMaxFrameSize(long maxFrameSize)
|
public void setMaxFrameSize(long maxFrameSize)
|
||||||
{
|
{
|
||||||
factory.setMaxFrameSize(maxFrameSize);
|
factory.setMaxFrameSize(maxFrameSize);
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"options": {
|
||||||
|
"failByDrop": false
|
||||||
|
},
|
||||||
|
"outdir": "./target/reports/servers",
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"agent": "Jetty-10.0.0-SNAPSHOT",
|
||||||
|
"url": "ws://127.0.0.1:9001",
|
||||||
|
"options": {
|
||||||
|
"version": 18
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"cases": ["*"],
|
||||||
|
"exclude-cases": [],
|
||||||
|
"exclude-agent-cases": {}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"options": {
|
||||||
|
"failByDrop": false
|
||||||
|
},
|
||||||
|
"url": "ws://127.0.0.1:9001",
|
||||||
|
"outdir": "./target/reports/clients",
|
||||||
|
"cases": ["*"],
|
||||||
|
"exclude-cases": [],
|
||||||
|
"exclude-agent-cases": {}
|
||||||
|
}
|
|
@ -57,14 +57,16 @@ public class EventSocket
|
||||||
{
|
{
|
||||||
this.session = session;
|
this.session = session;
|
||||||
behavior = session.getPolicy().getBehavior().name();
|
behavior = session.getPolicy().getBehavior().name();
|
||||||
LOG.info("{} onOpen(): {}", toString(), session);
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("{} onOpen(): {}", toString(), session);
|
||||||
openLatch.countDown();
|
openLatch.countDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnWebSocketMessage
|
@OnWebSocketMessage
|
||||||
public void onMessage(String message) throws IOException
|
public void onMessage(String message) throws IOException
|
||||||
{
|
{
|
||||||
LOG.info("{} onMessage(): {}", toString(), message);
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("{} onMessage(): {}", toString(), message);
|
||||||
messageQueue.offer(message);
|
messageQueue.offer(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,14 +74,16 @@ public class EventSocket
|
||||||
public void onMessage(byte buf[], int offset, int len)
|
public void onMessage(byte buf[], int offset, int len)
|
||||||
{
|
{
|
||||||
ByteBuffer message = ByteBuffer.wrap(buf, offset, len);
|
ByteBuffer message = ByteBuffer.wrap(buf, offset, len);
|
||||||
LOG.info("{} onMessage(): {}", toString(), message);
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("{} onMessage(): {}", toString(), message);
|
||||||
binaryMessageQueue.offer(message);
|
binaryMessageQueue.offer(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnWebSocketClose
|
@OnWebSocketClose
|
||||||
public void onClose(int statusCode, String reason)
|
public void onClose(int statusCode, String reason)
|
||||||
{
|
{
|
||||||
LOG.info("{} onClose(): {}:{}", toString(), statusCode, reason);
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("{} onClose(): {}:{}", toString(), statusCode, reason);
|
||||||
this.statusCode = statusCode;
|
this.statusCode = statusCode;
|
||||||
this.reason = reason;
|
this.reason = reason;
|
||||||
closeLatch.countDown();
|
closeLatch.countDown();
|
||||||
|
@ -88,7 +92,8 @@ public class EventSocket
|
||||||
@OnWebSocketError
|
@OnWebSocketError
|
||||||
public void onError(Throwable cause)
|
public void onError(Throwable cause)
|
||||||
{
|
{
|
||||||
LOG.info("{} onError(): {}", toString(), cause);
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("{} onError(): {}", toString(), cause);
|
||||||
error = cause;
|
error = cause;
|
||||||
errorLatch.countDown();
|
errorLatch.countDown();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,227 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// 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.websocket.tests.autobahn;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.util.Jetty;
|
||||||
|
import org.eclipse.jetty.util.UrlEncoded;
|
||||||
|
import org.eclipse.jetty.util.log.Log;
|
||||||
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
|
import org.eclipse.jetty.websocket.api.Session;
|
||||||
|
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||||
|
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||||
|
import org.eclipse.jetty.websocket.tests.EchoSocket;
|
||||||
|
import org.eclipse.jetty.websocket.tests.EventSocket;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WebSocket Client for use with <a href="https://github.com/crossbario/autobahn-testsuite">autobahn websocket testsuite</a> (wstest).
|
||||||
|
* <p>
|
||||||
|
* Installing Autobahn:
|
||||||
|
* </p>
|
||||||
|
* <pre>
|
||||||
|
* # For Debian / Ubuntu
|
||||||
|
* $ sudo apt-get install python python-dev python-twisted
|
||||||
|
* $ sudo apt-get install python-pip
|
||||||
|
* $ sudo pip install autobahntestsuite
|
||||||
|
*
|
||||||
|
* # For Fedora / Redhat
|
||||||
|
* $ sudo yum install python python-dev python-pip twisted
|
||||||
|
* $ sudo yum install libffi-devel
|
||||||
|
* $ sudo pip install autobahntestsuite
|
||||||
|
* </pre>
|
||||||
|
* <p>
|
||||||
|
* Upgrading an existing installation of autobahntestsuite
|
||||||
|
* </p>
|
||||||
|
* <pre>
|
||||||
|
* $ sudo pip install -U autobahntestsuite
|
||||||
|
* </pre>
|
||||||
|
* <p>
|
||||||
|
* Running Autobahn Fuzzing Server (which you run this client implementation against):
|
||||||
|
* </p>
|
||||||
|
* <pre>
|
||||||
|
* # Change to jetty-websocket-tests directory first.
|
||||||
|
* $ cd jetty-websocket/jetty-websocket-tests/
|
||||||
|
* $ wstest --mode=fuzzingserver --spec=fuzzingserver.json
|
||||||
|
*
|
||||||
|
* # Report output is configured (in the fuzzingserver.json) at location:
|
||||||
|
* $ ls target/reports/clients/
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public class JettyAutobahnClient
|
||||||
|
{
|
||||||
|
public static void main(String[] args)
|
||||||
|
{
|
||||||
|
String hostname = "localhost";
|
||||||
|
int port = 9001;
|
||||||
|
|
||||||
|
if (args.length > 0)
|
||||||
|
hostname = args[0];
|
||||||
|
if (args.length > 1)
|
||||||
|
port = Integer.parseInt(args[1]);
|
||||||
|
|
||||||
|
// Optional case numbers
|
||||||
|
// NOTE: these are url query parameter case numbers (whole integers, eg "6"), not the case ids (eg "7.3.1")
|
||||||
|
int[] caseNumbers = null;
|
||||||
|
if (args.length > 2)
|
||||||
|
{
|
||||||
|
int offset = 2;
|
||||||
|
caseNumbers = new int[args.length - offset];
|
||||||
|
for (int i = offset; i < args.length; i++)
|
||||||
|
{
|
||||||
|
caseNumbers[i - offset] = Integer.parseInt(args[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JettyAutobahnClient client = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String userAgent = "JettyWebsocketClient/" + Jetty.VERSION;
|
||||||
|
client = new JettyAutobahnClient(hostname, port, userAgent);
|
||||||
|
|
||||||
|
LOG.info("Running test suite...");
|
||||||
|
LOG.info("Using Fuzzing Server: {}:{}", hostname, port);
|
||||||
|
LOG.info("User Agent: {}", userAgent);
|
||||||
|
|
||||||
|
if (caseNumbers == null)
|
||||||
|
{
|
||||||
|
int caseCount = client.getCaseCount();
|
||||||
|
LOG.info("Will run all {} cases ...", caseCount);
|
||||||
|
for (int caseNum = 1; caseNum <= caseCount; caseNum++)
|
||||||
|
{
|
||||||
|
LOG.info("Running case {} (of {}) ...", caseNum, caseCount);
|
||||||
|
client.runCaseByNumber(caseNum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG.info("Will run %d cases ...", caseNumbers.length);
|
||||||
|
for (int caseNum : caseNumbers)
|
||||||
|
{
|
||||||
|
client.runCaseByNumber(caseNum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOG.info("All test cases executed.");
|
||||||
|
client.updateReports();
|
||||||
|
}
|
||||||
|
catch (Throwable t)
|
||||||
|
{
|
||||||
|
LOG.warn("Test Failed", t);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (client != null)
|
||||||
|
client.shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Logger LOG = Log.getLogger(JettyAutobahnClient.class);
|
||||||
|
private URI baseWebsocketUri;
|
||||||
|
private WebSocketClient client;
|
||||||
|
private String userAgent;
|
||||||
|
|
||||||
|
public JettyAutobahnClient(String hostname, int port, String userAgent) throws Exception
|
||||||
|
{
|
||||||
|
this.userAgent = userAgent;
|
||||||
|
this.baseWebsocketUri = new URI("ws://" + hostname + ":" + port);
|
||||||
|
this.client = new WebSocketClient();
|
||||||
|
this.client.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCaseCount() throws IOException, InterruptedException
|
||||||
|
{
|
||||||
|
URI wsUri = baseWebsocketUri.resolve("/getCaseCount");
|
||||||
|
EventSocket onCaseCount = new EventSocket();
|
||||||
|
CompletableFuture<Session> response = client.connect(onCaseCount, wsUri);
|
||||||
|
|
||||||
|
if (waitForUpgrade(wsUri, response))
|
||||||
|
{
|
||||||
|
String msg = onCaseCount.messageQueue.poll(10, TimeUnit.SECONDS);
|
||||||
|
onCaseCount.session.close(StatusCode.SHUTDOWN, null);
|
||||||
|
assertTrue(onCaseCount.closeLatch.await(2, TimeUnit.SECONDS));
|
||||||
|
assertNotNull(msg);
|
||||||
|
return Integer.decode(msg);
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("Unable to get Case Count");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runCaseByNumber(int caseNumber) throws IOException, InterruptedException
|
||||||
|
{
|
||||||
|
URI wsUri = baseWebsocketUri.resolve("/runCase?case=" + caseNumber + "&agent=" + UrlEncoded.encodeString(userAgent));
|
||||||
|
LOG.info("test uri: {}", wsUri);
|
||||||
|
|
||||||
|
EchoSocket echoHandler = new JettyAutobahnSocket();
|
||||||
|
Future<Session> response = client.connect(echoHandler, wsUri);
|
||||||
|
if (waitForUpgrade(wsUri, response))
|
||||||
|
{
|
||||||
|
// Wait up to 5 min as some of the tests can take a while
|
||||||
|
if (!echoHandler.closeLatch.await(5, TimeUnit.MINUTES))
|
||||||
|
{
|
||||||
|
LOG.warn("could not close {}, aborting session", echoHandler);
|
||||||
|
echoHandler.session.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdown()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
client.stop();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
LOG.warn("Unable to stop WebSocketClient", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateReports() throws IOException, InterruptedException, ExecutionException, TimeoutException
|
||||||
|
{
|
||||||
|
URI wsUri = baseWebsocketUri.resolve("/updateReports?agent=" + UrlEncoded.encodeString(userAgent));
|
||||||
|
EventSocket onUpdateReports = new EventSocket();
|
||||||
|
Future<Session> response = client.connect(onUpdateReports, wsUri);
|
||||||
|
response.get(5, TimeUnit.SECONDS);
|
||||||
|
assertTrue(onUpdateReports.closeLatch.await(15, TimeUnit.SECONDS));
|
||||||
|
LOG.info("Reports updated.");
|
||||||
|
LOG.info("Test suite finished!");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean waitForUpgrade(URI wsUri, Future<Session> response)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
response.get(10, TimeUnit.SECONDS);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Throwable t)
|
||||||
|
{
|
||||||
|
LOG.warn("Unable to connect to: " + wsUri, t);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// 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.websocket.tests.autobahn;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.server.ServerConnector;
|
||||||
|
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||||
|
import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WebSocket Server for use with <a href="https://github.com/crossbario/autobahn-testsuite">autobahn websocket testsuite</a> (wstest).
|
||||||
|
* <p>
|
||||||
|
* Installing Autobahn:
|
||||||
|
* </p>
|
||||||
|
* <pre>
|
||||||
|
* # For Debian / Ubuntu
|
||||||
|
* $ sudo apt-get install python python-dev python-twisted
|
||||||
|
* $ sudo apt-get install python-pip
|
||||||
|
* $ sudo pip install autobahntestsuite
|
||||||
|
*
|
||||||
|
* # For Fedora / Redhat
|
||||||
|
* $ sudo yum install python python-dev python-pip twisted
|
||||||
|
* $ sudo yum install libffi-devel
|
||||||
|
* $ sudo pip install autobahntestsuite
|
||||||
|
* </pre>
|
||||||
|
* <p>
|
||||||
|
* Upgrading an existing installation of autobahntestsuite
|
||||||
|
* </p>
|
||||||
|
* <pre>
|
||||||
|
* $ sudo pip install -U autobahntestsuite
|
||||||
|
* </pre>
|
||||||
|
* <p>
|
||||||
|
* Running Autobahn Fuzzing Client (against this server implementation):
|
||||||
|
* </p>
|
||||||
|
* <pre>
|
||||||
|
* # Change to jetty-websocket-tests directory first.
|
||||||
|
* $ cd jetty-websocket/jetty-websocket-tests/
|
||||||
|
* $ wstest --mode=fuzzingclient --spec=fuzzingclient.json
|
||||||
|
*
|
||||||
|
* # Report output is configured (in the fuzzingclient.json) at location:
|
||||||
|
* $ ls target/reports/servers/
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public class JettyAutobahnServer
|
||||||
|
{
|
||||||
|
public static void main(String[] args) throws Exception
|
||||||
|
{
|
||||||
|
int port = 9001; // same port as found in fuzzing-client.json
|
||||||
|
if (args != null && args.length > 0)
|
||||||
|
port = Integer.parseInt(args[0]);
|
||||||
|
|
||||||
|
Server server = new Server(port);
|
||||||
|
ServerConnector connector = new ServerConnector(server);
|
||||||
|
connector.setIdleTimeout(10000);
|
||||||
|
server.addConnector(connector);
|
||||||
|
ServletContextHandler context = new ServletContextHandler();
|
||||||
|
context.setContextPath("/");
|
||||||
|
server.setHandler(context);
|
||||||
|
|
||||||
|
JettyWebSocketServletContainerInitializer.configure(context, (servletContext, container)->
|
||||||
|
container.addMapping("/", (req, resp) -> new JettyAutobahnSocket()));
|
||||||
|
|
||||||
|
server.start();
|
||||||
|
server.join();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// 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.websocket.tests.autobahn;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.websocket.api.Session;
|
||||||
|
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||||
|
import org.eclipse.jetty.websocket.core.WebSocketConstants;
|
||||||
|
import org.eclipse.jetty.websocket.tests.EchoSocket;
|
||||||
|
|
||||||
|
@WebSocket
|
||||||
|
public class JettyAutobahnSocket extends EchoSocket
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onOpen(Session session)
|
||||||
|
{
|
||||||
|
super.onOpen(session);
|
||||||
|
session.setMaxTextMessageSize(Long.MAX_VALUE);
|
||||||
|
session.setMaxBinaryMessageSize(Long.MAX_VALUE);
|
||||||
|
session.setMaxFrameSize(WebSocketConstants.DEFAULT_MAX_FRAME_SIZE*2);
|
||||||
|
}
|
||||||
|
}
|
|
@ -141,7 +141,7 @@
|
||||||
</goals>
|
</goals>
|
||||||
<configuration>
|
<configuration>
|
||||||
<!-- The class that contains a main method which accepts the port as a parameter to start the server. -->
|
<!-- The class that contains a main method which accepts the port as a parameter to start the server. -->
|
||||||
<mainClass>org.eclipse.jetty.websocket.core.autobahn.AutobahnWebSocketServer</mainClass>
|
<mainClass>org.eclipse.jetty.websocket.core.autobahn.CoreAutobahnServer</mainClass>
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
|
|
|
@ -28,7 +28,6 @@ import org.eclipse.jetty.util.DecoratedObjectFactory;
|
||||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||||
import org.eclipse.jetty.util.log.Log;
|
import org.eclipse.jetty.util.log.Log;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
import org.eclipse.jetty.util.thread.ShutdownThread;
|
|
||||||
import org.eclipse.jetty.websocket.core.ExtensionConfig;
|
import org.eclipse.jetty.websocket.core.ExtensionConfig;
|
||||||
import org.eclipse.jetty.websocket.core.FrameHandler;
|
import org.eclipse.jetty.websocket.core.FrameHandler;
|
||||||
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
||||||
|
@ -92,20 +91,9 @@ public class WebSocketCoreClient extends ContainerLifeCycle
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("connect to websocket {}", request.getURI());
|
LOG.debug("connect to websocket {}", request.getURI());
|
||||||
|
|
||||||
init();
|
|
||||||
|
|
||||||
return request.sendAsync();
|
return request.sendAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: review need for this.
|
|
||||||
private synchronized void init() throws IOException
|
|
||||||
{
|
|
||||||
if (!ShutdownThread.isRegistered(this))
|
|
||||||
{
|
|
||||||
ShutdownThread.register(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public WebSocketExtensionRegistry getExtensionRegistry()
|
public WebSocketExtensionRegistry getExtensionRegistry()
|
||||||
{
|
{
|
||||||
return components.getExtensionRegistry();
|
return components.getExtensionRegistry();
|
||||||
|
|
|
@ -48,6 +48,7 @@ import org.junit.jupiter.api.Test;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static org.hamcrest.Matchers.not;
|
||||||
import static org.hamcrest.Matchers.startsWith;
|
import static org.hamcrest.Matchers.startsWith;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
@ -104,6 +105,7 @@ public class WebSocketNegotiationTest extends WebSocketTester
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "test":
|
case "test":
|
||||||
|
case "testExtensionThatDoesNotExist":
|
||||||
case "testInvalidExtensionParameter":
|
case "testInvalidExtensionParameter":
|
||||||
case "testAcceptTwoExtensionsOfSameName":
|
case "testAcceptTwoExtensionsOfSameName":
|
||||||
case "testInvalidUpgradeRequest":
|
case "testInvalidUpgradeRequest":
|
||||||
|
@ -239,6 +241,23 @@ public class WebSocketNegotiationTest extends WebSocketTester
|
||||||
assertNull(extensionHeader.get(5, TimeUnit.SECONDS));
|
assertNull(extensionHeader.get(5, TimeUnit.SECONDS));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExtensionThatDoesNotExist() throws Exception
|
||||||
|
{
|
||||||
|
Socket client = new Socket();
|
||||||
|
client.connect(new InetSocketAddress("127.0.0.1", server.getLocalPort()));
|
||||||
|
|
||||||
|
HttpFields httpFields = newUpgradeRequest("nonExistentExtensionName");
|
||||||
|
String upgradeRequest = "GET / HTTP/1.1\r\n" + httpFields;
|
||||||
|
client.getOutputStream().write(upgradeRequest.getBytes(StandardCharsets.ISO_8859_1));
|
||||||
|
String response = getUpgradeResponse(client.getInputStream());
|
||||||
|
|
||||||
|
assertThat(response, startsWith("HTTP/1.1 101 Switching Protocols"));
|
||||||
|
assertThat(response, containsString("Sec-WebSocket-Protocol: test"));
|
||||||
|
assertThat(response, containsString("Sec-WebSocket-Accept: +WahVcVmeMLKQUMm0fvPrjSjwzI="));
|
||||||
|
assertThat(response, not(containsString(HttpHeader.SEC_WEBSOCKET_EXTENSIONS.asString())));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAcceptTwoExtensionsOfSameName() throws Exception
|
public void testAcceptTwoExtensionsOfSameName() throws Exception
|
||||||
{
|
{
|
||||||
|
|
|
@ -62,7 +62,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
* Running Autobahn Fuzzing Server (which you run this client implementation against):
|
* Running Autobahn Fuzzing Server (which you run this client implementation against):
|
||||||
* </p>
|
* </p>
|
||||||
* <pre>
|
* <pre>
|
||||||
* # Change to websocket-core
|
* # Change to websocket-core first
|
||||||
* $ cd jetty-websocket/websocket-core
|
* $ cd jetty-websocket/websocket-core
|
||||||
* $ wstest --mode=fuzzingserver --spec=fuzzingserver.json
|
* $ wstest --mode=fuzzingserver --spec=fuzzingserver.json
|
||||||
*
|
*
|
||||||
|
@ -70,7 +70,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
* $ ls target/reports/clients/
|
* $ ls target/reports/clients/
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public class AutobahnWebSocketClient
|
public class CoreAutobahnClient
|
||||||
{
|
{
|
||||||
public static void main(String[] args)
|
public static void main(String[] args)
|
||||||
{
|
{
|
||||||
|
@ -95,11 +95,11 @@ public class AutobahnWebSocketClient
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AutobahnWebSocketClient client = null;
|
CoreAutobahnClient client = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
String userAgent = "JettyWebsocketClient/" + Jetty.VERSION;
|
String userAgent = "JettyWebsocketClient/" + Jetty.VERSION;
|
||||||
client = new AutobahnWebSocketClient(hostname, port, userAgent);
|
client = new CoreAutobahnClient(hostname, port, userAgent);
|
||||||
|
|
||||||
LOG.info("Running test suite...");
|
LOG.info("Running test suite...");
|
||||||
LOG.info("Using Fuzzing Server: {}:{}", hostname, port);
|
LOG.info("Using Fuzzing Server: {}:{}", hostname, port);
|
||||||
|
@ -137,12 +137,12 @@ public class AutobahnWebSocketClient
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Logger LOG = Log.getLogger(AutobahnWebSocketClient.class);
|
private static final Logger LOG = Log.getLogger(CoreAutobahnClient.class);
|
||||||
private URI baseWebsocketUri;
|
private URI baseWebsocketUri;
|
||||||
private WebSocketCoreClient client;
|
private WebSocketCoreClient client;
|
||||||
private String userAgent;
|
private String userAgent;
|
||||||
|
|
||||||
public AutobahnWebSocketClient(String hostname, int port, String userAgent) throws Exception
|
public CoreAutobahnClient(String hostname, int port, String userAgent) throws Exception
|
||||||
{
|
{
|
||||||
this.userAgent = userAgent;
|
this.userAgent = userAgent;
|
||||||
this.baseWebsocketUri = new URI("ws://" + hostname + ":" + port);
|
this.baseWebsocketUri = new URI("ws://" + hostname + ":" + port);
|
|
@ -57,7 +57,7 @@ import org.eclipse.jetty.websocket.core.server.WebSocketUpgradeHandler;
|
||||||
* $ ls target/reports/servers/
|
* $ ls target/reports/servers/
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public class AutobahnWebSocketServer
|
public class CoreAutobahnServer
|
||||||
{
|
{
|
||||||
public static void main(String[] args) throws Exception
|
public static void main(String[] args) throws Exception
|
||||||
{
|
{
|
|
@ -176,7 +176,7 @@ public class ServletUpgradeResponse
|
||||||
if (matches < 1)
|
if (matches < 1)
|
||||||
throw new IllegalArgumentException("Extension not a requested extension");
|
throw new IllegalArgumentException("Extension not a requested extension");
|
||||||
|
|
||||||
matches = negotiation.getNegotiatedExtensions().stream().filter(e -> e.getName().equals(config.getName())).count();
|
matches = configs.stream().filter(e -> e.getName().equals(config.getName())).count();
|
||||||
if (matches > 1)
|
if (matches > 1)
|
||||||
throw new IllegalArgumentException("Multiple extensions of the same name");
|
throw new IllegalArgumentException("Multiple extensions of the same name");
|
||||||
}
|
}
|
||||||
|
|
|
@ -988,7 +988,9 @@ public class HttpClientStreamTest extends AbstractTest<TransportScenario>
|
||||||
public void testUploadWithOutputStreamFailureToConnect(Transport transport) throws Exception
|
public void testUploadWithOutputStreamFailureToConnect(Transport transport) throws Exception
|
||||||
{
|
{
|
||||||
init(transport);
|
init(transport);
|
||||||
scenario.start(new EmptyServerHandler());
|
|
||||||
|
long connectTimeout = 1000;
|
||||||
|
scenario.start(new EmptyServerHandler(), httpClient -> httpClient.setConnectTimeout(connectTimeout));
|
||||||
|
|
||||||
final byte[] data = new byte[512];
|
final byte[] data = new byte[512];
|
||||||
final CountDownLatch latch = new CountDownLatch(1);
|
final CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
@ -1013,7 +1015,7 @@ public class HttpClientStreamTest extends AbstractTest<TransportScenario>
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
assertTrue(latch.await(2 * connectTimeout, TimeUnit.SECONDS));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
|
@ -1070,7 +1072,9 @@ public class HttpClientStreamTest extends AbstractTest<TransportScenario>
|
||||||
public void testUploadWithConnectFailureClosesStream(Transport transport) throws Exception
|
public void testUploadWithConnectFailureClosesStream(Transport transport) throws Exception
|
||||||
{
|
{
|
||||||
init(transport);
|
init(transport);
|
||||||
scenario.start(new EmptyServerHandler());
|
|
||||||
|
long connectTimeout = 1000;
|
||||||
|
scenario.start(new EmptyServerHandler(), httpClient -> httpClient.setConnectTimeout(connectTimeout));
|
||||||
|
|
||||||
final CountDownLatch closeLatch = new CountDownLatch(1);
|
final CountDownLatch closeLatch = new CountDownLatch(1);
|
||||||
InputStream stream = new ByteArrayInputStream("test".getBytes(StandardCharsets.UTF_8))
|
InputStream stream = new ByteArrayInputStream("test".getBytes(StandardCharsets.UTF_8))
|
||||||
|
@ -1097,7 +1101,7 @@ public class HttpClientStreamTest extends AbstractTest<TransportScenario>
|
||||||
completeLatch.countDown();
|
completeLatch.countDown();
|
||||||
});
|
});
|
||||||
|
|
||||||
assertTrue(completeLatch.await(5, TimeUnit.SECONDS));
|
assertTrue(completeLatch.await(2 * connectTimeout, TimeUnit.SECONDS));
|
||||||
assertTrue(closeLatch.await(5, TimeUnit.SECONDS));
|
assertTrue(closeLatch.await(5, TimeUnit.SECONDS));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue