Merge remote-tracking branch 'origin/master' into jetty-9.1
Conflicts: aggregates/jetty-all/pom.xml examples/async-rest/async-rest-jar/pom.xml examples/async-rest/async-rest-webapp/pom.xml examples/async-rest/pom.xml examples/embedded/pom.xml examples/pom.xml jetty-annotations/pom.xml jetty-ant/pom.xml jetty-client/pom.xml jetty-continuation/pom.xml jetty-deploy/pom.xml jetty-distribution/pom.xml jetty-http/pom.xml jetty-io/pom.xml jetty-jaas/pom.xml jetty-jaspi/pom.xml jetty-jmx/pom.xml jetty-jndi/pom.xml jetty-jsp/pom.xml jetty-jspc-maven-plugin/pom.xml jetty-maven-plugin/pom.xml jetty-monitor/pom.xml jetty-nosql/pom.xml jetty-osgi/jetty-osgi-boot-jsp/pom.xml jetty-osgi/jetty-osgi-boot-warurl/pom.xml jetty-osgi/jetty-osgi-boot/pom.xml jetty-osgi/jetty-osgi-httpservice/pom.xml jetty-osgi/jetty-osgi-npn/pom.xml jetty-osgi/pom.xml jetty-osgi/test-jetty-osgi-context/pom.xml jetty-osgi/test-jetty-osgi-webapp/pom.xml jetty-plus/pom.xml jetty-proxy/pom.xml jetty-rewrite/pom.xml jetty-runner/pom.xml jetty-security/pom.xml jetty-server/pom.xml jetty-servlet/pom.xml jetty-servlets/pom.xml jetty-spdy/pom.xml jetty-spdy/spdy-client/pom.xml jetty-spdy/spdy-core/pom.xml jetty-spdy/spdy-example-webapp/pom.xml jetty-spdy/spdy-http-server/pom.xml jetty-spdy/spdy-server/pom.xml jetty-spring/pom.xml jetty-start/pom.xml jetty-util-ajax/pom.xml jetty-util/pom.xml jetty-webapp/pom.xml jetty-websocket/pom.xml jetty-websocket/websocket-api/pom.xml jetty-websocket/websocket-client/pom.xml jetty-websocket/websocket-common/pom.xml jetty-websocket/websocket-server/pom.xml jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/Fuzzer.java jetty-websocket/websocket-servlet/pom.xml jetty-xml/pom.xml pom.xml tests/pom.xml tests/test-continuation/pom.xml tests/test-loginservice/pom.xml tests/test-sessions/pom.xml tests/test-sessions/test-hash-sessions/pom.xml tests/test-sessions/test-jdbc-sessions/pom.xml tests/test-sessions/test-sessions-common/pom.xml tests/test-webapps/pom.xml tests/test-webapps/test-jaas-webapp/pom.xml tests/test-webapps/test-jetty-webapp/pom.xml tests/test-webapps/test-jndi-webapp/pom.xml tests/test-webapps/test-mock-resources/pom.xml tests/test-webapps/test-proxy-webapp/pom.xml tests/test-webapps/test-servlet-spec/pom.xml tests/test-webapps/test-servlet-spec/test-container-initializer/pom.xml tests/test-webapps/test-servlet-spec/test-spec-webapp/pom.xml tests/test-webapps/test-servlet-spec/test-web-fragment/pom.xml tests/test-webapps/test-webapp-rfc2616/pom.xml
This commit is contained in:
commit
e4716e05e1
139
VERSION.txt
139
VERSION.txt
|
@ -1,6 +1,141 @@
|
|||
jetty-9.0.4-SNAPSHOT
|
||||
jetty-9.1.0-SNAPSHOT
|
||||
|
||||
jetty-9.0.3.v20130506 06 May 2013
|
||||
jetty-9.0.4.v20130625 - 25 June 2013
|
||||
+ 396706 CGI support parameters
|
||||
+ 397051 Make JDBCLoginService data members protected to facilitate
|
||||
subclassing
|
||||
+ 397193 MongoSessionManager refresh updates last access time
|
||||
+ 398467 Servlet 3.1 Non Blocking IO
|
||||
+ 400503 WebSocket - squelch legitimate Exceptions during testing to avoid
|
||||
false positives
|
||||
+ 401027 javadoc JMX annotations
|
||||
+ 404508 enable overlay deployer
|
||||
+ 405188 HTTP 1.0 with GET returns internal IP address.
|
||||
+ 405313 Websocket client SSL hostname verification is broken, always defaults
|
||||
to raw IP as String
|
||||
+ 406759 supressed stacktrace in ReferrerPushStrategyTest
|
||||
+ 406923 Accept CRLF or LF but not CR as line termination
|
||||
+ 407246 Test harness checked results in callbacks ignored.
|
||||
+ 407325 Test Failure:
|
||||
org.eclipse.jetty.servlets.EventSourceServletTest.testEncoding
|
||||
+ 407326 Test Failure:
|
||||
org.eclipse.jetty.client.HttpClientStreamTest.testInputStreamResponseListenerFailedBeforeResponse[0].
|
||||
+ 407342 ReloadedSessionMissingClassTest uses class compiled with jdk7
|
||||
+ 407386 Cookies not copied in ServletWebSocketRequest
|
||||
+ 407469 Method parameters for @OnWebSocketError should support Throwable
|
||||
+ 407470 Javadoc for @OnWebSocketFrame incorrectly references WebSocketFrame
|
||||
object
|
||||
+ 407491 Better handle empty Accept-Language
|
||||
+ 407614 added excludedMimeTypes to gzipFilter
|
||||
+ 407812 jetty-maven-plugin can not handle whitespaces in equivalent of
|
||||
WEB-INF/classes paths
|
||||
+ 407931 Add toggle for failing on servlet availability
|
||||
+ 407976 JDBCSessionIdManager potentially leaves server in bad state after
|
||||
startup
|
||||
+ 408077 HashSessionManager leaves file handles open after being stopped
|
||||
+ 408117 isAsyncStarted is false on redispatch
|
||||
+ 408118 NullPointerException when parsing request cookies
|
||||
+ 408167 JDBCSessionManager don't mark session as dirty if same attribute
|
||||
value set
|
||||
+ 408281 Inconsistent start/stop handling in ContainerLifeCycle
|
||||
+ 408446 Multipart parsing issue with boundry and charset in ContentType
|
||||
header
|
||||
+ 408529 Etags set in 304 response
|
||||
+ 408600 set correct jetty.url in all pom files
|
||||
+ 408642 setContentType from addHeader
|
||||
+ 408662 In pax-web servlet services requests even if init() has not finished
|
||||
running
|
||||
+ 408709 refactor test-webapp's chat application. Now there's only a single
|
||||
request for user login and initial chat message.
|
||||
+ 408720 NPE in AsyncContext.getRequest()
|
||||
+ 408723 Jetty Maven plugin reload ignores web.xml listeners
|
||||
+ 408768 JSTL jars not scanned by jetty-ant
|
||||
+ 408771 Problem with ShutdownMonitor for jetty-ant
|
||||
+ 408782 Transparent Proxy - rewrite URL is ignoring query strings.
|
||||
+ 408806 getParameter returns null on Multipart request if called before
|
||||
request.getPart()/getParts()
|
||||
+ 408904 Enhance CommandlineBuilder to not escape strings inside single quotes
|
||||
+ 408909 GzipFilter setting of headers when reset and/or not compressed
|
||||
+ 408910 META-INF/jetty-webapp-context.xml file should be able to refer to
|
||||
bundle-relative locations
|
||||
+ 408923 Need to be able to configure the ThreadPool for the default jetty
|
||||
server in osgi
|
||||
+ 408945 XML Args ignored without DTD
|
||||
+ 409012 added reference to example rewrite rules
|
||||
+ 409133 Empty <welcome-file> causes StackOverflowError
|
||||
+ 409228 Set jetty.home property so config files work even if deployed inside
|
||||
a bundle
|
||||
+ 409403 fix IllegalStateException when SPDY is used and the response is
|
||||
written through BufferUtil.writeTo byte by byte
|
||||
+ 409436 NPE on context restart using dynamic servlet registration
|
||||
+ 409441 jetty.xml threadpool arg injection
|
||||
+ 409449 Ensure servlets, filters and listeners added via dynamic
|
||||
registration, annotations or descriptors are cleaned on context restarts
|
||||
+ 409545 Change HttpChannel contract
|
||||
+ 409556 Resource files not closed
|
||||
+ 409598 spdy: Fix NPE when a broken client tried to create duplicate stream
|
||||
IDs
|
||||
+ 409684 Ids and properties not set for execution of jetty xml config files
|
||||
with mvn plugin
|
||||
+ 409796 fix intermittent test issue in
|
||||
ReferrerPushStrategy.testResourceOrder. Happened when the client got closed
|
||||
before the server finished sending all data frames. Client waits now until
|
||||
all data is received.
|
||||
+ 409801 Jetty should allow webdefault to be specified using a relative
|
||||
location when running in OSGi
|
||||
+ 409842 Suspended request completed by a request thread does not set read
|
||||
interest.
|
||||
+ 409953 return buffer.slice() instead of buffer.asReadOnlyBuffer() in
|
||||
ResourceCache to avoid using inefficent path in BufferUtil.writeTo
|
||||
+ 409978 Websocket shouldn't create HttpSession if not present
|
||||
+ 410083 Jetty clients submits incomplete URL to proxy.
|
||||
+ 410098 inject accept-encoding header for all http requests through SPDY as
|
||||
SPDY clients MUST support spdy. Also remove two new tests that have been to
|
||||
implementation agnostic and not needed anymore due to recent code changes
|
||||
+ 410175 WebSocketSession#isSecure() doesn't return true for SSL session on
|
||||
the server side
|
||||
+ 410246 HttpClient with proxy does not tunnel HTTPS requests.
|
||||
+ 410337 throw EofException instead of EOFException in HttpOutput.write() if
|
||||
HttpOutpyt is closed
|
||||
+ 410341 suppress stacktraces that happen during test setup shutdown after
|
||||
successful test run
|
||||
+ 410370 WebSocketCreator.createWebSocket() should use servlet specific
|
||||
parameters
|
||||
+ 410372 Make SSL client certificate information available to server
|
||||
websockets
|
||||
+ 410386 WebSocket Session.getUpgradeRequest().getRequestURI() returns bad URI
|
||||
on server side
|
||||
+ 410405 Avoid NPE for requestDispatcher(../)
|
||||
+ 410469 UpgradeRequest is sent twice when using SSL, one fails warning about
|
||||
WritePendingException
|
||||
+ 410498 ignore type of exception in GoAwayTest.testDataNotProcessedAfterGoAway
|
||||
+ 410522 jetty start broken for command line options
|
||||
+ 410537 Exceptions during @OnWebSocketConnect not reported to
|
||||
@OnWebSocketError
|
||||
+ 410559 Removed FillInterest race
|
||||
+ 410630 MongoSessionManager conflicting session update op
|
||||
+ 410693 ServletContextHandler.setHandler does not relink handlers - check for
|
||||
null
|
||||
+ 410750 NoSQLSessions: implement session context data persistence across
|
||||
server restarts
|
||||
+ 410799 errors while creating push streams in HttpTransportOverSPDY are now
|
||||
logged to debug instead of warn
|
||||
+ 410893 async support defaults to false for spec created servlets and filters
|
||||
+ 410911 Continuation isExpired handling.
|
||||
+ 410995 Avoid reverse DNS lookups when creating SSLEngines.
|
||||
+ 411061 fix cookie handling in spdy. If two different HTTP headers with the
|
||||
same name are set, they should be translated to a single multiheader value
|
||||
according to:
|
||||
http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3#TOC-2.6.10-Name-Value-Header-Block.
|
||||
That applies for Set-Cookie headers for example. Before this changed
|
||||
duplicate header names have overwritten the previous one
|
||||
+ 411135 HttpClient may send proxied https requests to the proxy instead of
|
||||
the target server.
|
||||
+ 411340 add comment why executeOnFillable defaults to true
|
||||
+ 411545 SslConnection.DecryptedEndpoint.fill() sometimes misses a few network
|
||||
bytes
|
||||
|
||||
jetty-9.0.3.v20130506 - 06 May 2013
|
||||
+ 404010 fix cast exception in mongodb session manager
|
||||
+ 404911 WebSocketCloseTest fails spuriously
|
||||
+ 405281 allow filemappedbuffers to not be used
|
||||
|
|
|
@ -43,12 +43,12 @@
|
|||
<td>
|
||||
<h2>information ...</h2>
|
||||
<ul>
|
||||
<li><a href="http://www.eclipse.org/jetty/">Jetty @ Eclipse Home</a></li>
|
||||
<li><a href="http://wiki.eclipse.org/Jetty">Jetty @ Eclipse Doco</a></li>
|
||||
<li><a href="http://www.eclipse.org/jetty/">Jetty Homepage</a></li>
|
||||
<li><a href="http://www.eclipse.org/jetty/documentation/current">Jetty Documentation</a></li>
|
||||
<li><a href="/proxy/apidocs/">Javadoc</a> (via transparent proxy)</li>
|
||||
<li><a href="/proxy/xref/">Xref</a> (via transparent proxy)</li>
|
||||
<li><a
|
||||
href="http://docs.codehaus.org/display/JETTY/Jetty+Powered">Jetty Powered</a></li>
|
||||
href="http://www.eclipse.org/jetty/powered">Jetty Powered</a></li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
|
|
|
@ -55,13 +55,18 @@ public class HttpGenerator
|
|||
private long _contentPrepared = 0;
|
||||
private boolean _noContent = false;
|
||||
private Boolean _persistent = null;
|
||||
private boolean _sendServerVersion;
|
||||
|
||||
private final int _send;
|
||||
private final static int SEND_SERVER=0x01;
|
||||
private final static int SEND_XPOWEREDBY=0x02;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
public static void setServerVersion(String version)
|
||||
{
|
||||
SERVER=StringUtil.getBytes("Server: Jetty("+version+")\015\012");
|
||||
SEND[SEND_SERVER]=StringUtil.getBytes("Server: Jetty("+version+")\015\012");
|
||||
SEND[SEND_XPOWEREDBY]=StringUtil.getBytes("X-Powered-By: Jetty("+version+")\015\012");
|
||||
SEND[SEND_SERVER|SEND_XPOWEREDBY]=StringUtil.getBytes("Server: Jetty("+version+")\015\012X-Powered-By: Jetty("+version+")\015\012");
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
|
@ -71,6 +76,13 @@ public class HttpGenerator
|
|||
/* ------------------------------------------------------------------------------- */
|
||||
public HttpGenerator()
|
||||
{
|
||||
this(false,false);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
public HttpGenerator(boolean sendServerVersion,boolean sendXPoweredBy)
|
||||
{
|
||||
_send=(sendServerVersion?SEND_SERVER:0) | (sendXPoweredBy?SEND_XPOWEREDBY:0);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
|
@ -86,15 +98,17 @@ public class HttpGenerator
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Deprecated
|
||||
public boolean getSendServerVersion ()
|
||||
{
|
||||
return _sendServerVersion;
|
||||
return (_send&SEND_SERVER)!=0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Deprecated
|
||||
public void setSendServerVersion (boolean sendServerVersion)
|
||||
{
|
||||
_sendServerVersion = sendServerVersion;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -537,11 +551,11 @@ public class HttpGenerator
|
|||
/* ------------------------------------------------------------ */
|
||||
private void generateHeaders(Info _info,ByteBuffer header,ByteBuffer content,boolean last)
|
||||
{
|
||||
final RequestInfo _request=(_info instanceof RequestInfo)?(RequestInfo)_info:null;
|
||||
final ResponseInfo _response=(_info instanceof ResponseInfo)?(ResponseInfo)_info:null;
|
||||
final RequestInfo request=(_info instanceof RequestInfo)?(RequestInfo)_info:null;
|
||||
final ResponseInfo response=(_info instanceof ResponseInfo)?(ResponseInfo)_info:null;
|
||||
|
||||
// default field values
|
||||
boolean has_server = false;
|
||||
int send=_send;
|
||||
HttpField transfer_encoding=null;
|
||||
boolean keep_alive=false;
|
||||
boolean close=false;
|
||||
|
@ -584,7 +598,7 @@ public class HttpGenerator
|
|||
|
||||
case CONNECTION:
|
||||
{
|
||||
if (_request!=null)
|
||||
if (request!=null)
|
||||
field.putTo(header);
|
||||
|
||||
// Lookup and/or split connection value field
|
||||
|
@ -619,7 +633,7 @@ public class HttpGenerator
|
|||
case CLOSE:
|
||||
{
|
||||
close=true;
|
||||
if (_response!=null)
|
||||
if (response!=null)
|
||||
{
|
||||
_persistent=false;
|
||||
if (_endOfContent == EndOfContent.UNKNOWN_CONTENT)
|
||||
|
@ -633,7 +647,7 @@ public class HttpGenerator
|
|||
if (_info.getHttpVersion() == HttpVersion.HTTP_1_0)
|
||||
{
|
||||
keep_alive = true;
|
||||
if (_response!=null)
|
||||
if (response!=null)
|
||||
_persistent=true;
|
||||
}
|
||||
break;
|
||||
|
@ -656,11 +670,8 @@ public class HttpGenerator
|
|||
|
||||
case SERVER:
|
||||
{
|
||||
if (getSendServerVersion())
|
||||
{
|
||||
has_server=true;
|
||||
field.putTo(header);
|
||||
}
|
||||
send=send&~SEND_SERVER;
|
||||
field.putTo(header);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -680,7 +691,7 @@ public class HttpGenerator
|
|||
// 4. Content-Length
|
||||
// 5. multipart/byteranges
|
||||
// 6. close
|
||||
int status=_response!=null?_response.getStatus():-1;
|
||||
int status=response!=null?response.getStatus():-1;
|
||||
switch (_endOfContent)
|
||||
{
|
||||
case UNKNOWN_CONTENT:
|
||||
|
@ -688,14 +699,14 @@ public class HttpGenerator
|
|||
// written yet?
|
||||
|
||||
// Response known not to have a body
|
||||
if (_contentPrepared == 0 && _response!=null && (status < 200 || status == 204 || status == 304))
|
||||
if (_contentPrepared == 0 && response!=null && (status < 200 || status == 204 || status == 304))
|
||||
_endOfContent=EndOfContent.NO_CONTENT;
|
||||
else if (_info.getContentLength()>0)
|
||||
{
|
||||
// we have been given a content length
|
||||
_endOfContent=EndOfContent.CONTENT_LENGTH;
|
||||
long content_length = _info.getContentLength();
|
||||
if ((_response!=null || content_length>0 || content_type ) && !_noContent)
|
||||
if ((response!=null || content_length>0 || content_type ) && !_noContent)
|
||||
{
|
||||
// known length but not actually set.
|
||||
header.put(HttpHeader.CONTENT_LENGTH.getBytesColonSpace());
|
||||
|
@ -710,7 +721,7 @@ public class HttpGenerator
|
|||
long content_length = _contentPrepared+BufferUtil.length(content);
|
||||
|
||||
// Do we need to tell the headers about it
|
||||
if ((_response!=null || content_length>0 || content_type ) && !_noContent)
|
||||
if ((response!=null || content_length>0 || content_type ) && !_noContent)
|
||||
{
|
||||
header.put(HttpHeader.CONTENT_LENGTH.getBytesColonSpace());
|
||||
BufferUtil.putDecLong(header, content_length);
|
||||
|
@ -721,7 +732,7 @@ public class HttpGenerator
|
|||
{
|
||||
// No idea, so we must assume that a body is coming
|
||||
_endOfContent = (!isPersistent() || _info.getHttpVersion().ordinal() < HttpVersion.HTTP_1_1.ordinal() ) ? EndOfContent.EOF_CONTENT : EndOfContent.CHUNKED_CONTENT;
|
||||
if (_response!=null && _endOfContent==EndOfContent.EOF_CONTENT)
|
||||
if (response!=null && _endOfContent==EndOfContent.EOF_CONTENT)
|
||||
{
|
||||
_endOfContent=EndOfContent.NO_CONTENT;
|
||||
_noContent=true;
|
||||
|
@ -731,7 +742,7 @@ public class HttpGenerator
|
|||
|
||||
case CONTENT_LENGTH:
|
||||
long content_length = _info.getContentLength();
|
||||
if ((_response!=null || content_length>0 || content_type ) && !_noContent)
|
||||
if ((response!=null || content_length>0 || content_type ) && !_noContent)
|
||||
{
|
||||
// known length but not actually set.
|
||||
header.put(HttpHeader.CONTENT_LENGTH.getBytesColonSpace());
|
||||
|
@ -741,12 +752,12 @@ public class HttpGenerator
|
|||
break;
|
||||
|
||||
case NO_CONTENT:
|
||||
if (_response!=null && status >= 200 && status != 204 && status != 304)
|
||||
if (response!=null && status >= 200 && status != 204 && status != 304)
|
||||
header.put(CONTENT_LENGTH_0);
|
||||
break;
|
||||
|
||||
case EOF_CONTENT:
|
||||
_persistent = _request!=null;
|
||||
_persistent = request!=null;
|
||||
break;
|
||||
|
||||
case CHUNKED_CONTENT:
|
||||
|
@ -780,7 +791,7 @@ public class HttpGenerator
|
|||
}
|
||||
|
||||
// If this is a response, work out persistence
|
||||
if (_response!=null)
|
||||
if (response!=null)
|
||||
{
|
||||
if (!isPersistent() && (close || _info.getHttpVersion().ordinal() > HttpVersion.HTTP_1_0.ordinal()))
|
||||
{
|
||||
|
@ -814,8 +825,8 @@ public class HttpGenerator
|
|||
}
|
||||
}
|
||||
|
||||
if (!has_server && status>199 && getSendServerVersion())
|
||||
header.put(SERVER);
|
||||
if (status>199)
|
||||
header.put(SEND[send]);
|
||||
|
||||
// end the header.
|
||||
header.put(HttpTokens.CRLF);
|
||||
|
@ -851,7 +862,12 @@ public class HttpGenerator
|
|||
private static final byte[] HTTP_1_1_SPACE = StringUtil.getBytes(HttpVersion.HTTP_1_1+" ");
|
||||
private static final byte[] CRLF = StringUtil.getBytes("\015\012");
|
||||
private static final byte[] TRANSFER_ENCODING_CHUNKED = StringUtil.getBytes("Transfer-Encoding: chunked\015\012");
|
||||
private static byte[] SERVER = StringUtil.getBytes("Server: Jetty(7.0.x)\015\012");
|
||||
private static final byte[][] SEND = new byte[][]{
|
||||
new byte[0],
|
||||
StringUtil.getBytes("Server: Jetty(9.x.x)\015\012"),
|
||||
StringUtil.getBytes("X-Powered-By: Jetty(9.x.x)\015\012"),
|
||||
StringUtil.getBytes("Server: Jetty(9.x.x)\015\012X-Powered-By: Jetty(9.x.x)\015\012")
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
|
|
|
@ -108,6 +108,8 @@ public enum HttpHeader
|
|||
SET_COOKIE2("Set-Cookie2"),
|
||||
MIME_VERSION("MIME-Version"),
|
||||
IDENTITY("identity"),
|
||||
|
||||
X_POWERED_BY("X-Powered-By"),
|
||||
|
||||
UNKNOWN("::UNKNOWN::");
|
||||
|
||||
|
|
|
@ -91,6 +91,19 @@ public class HttpTester
|
|||
{
|
||||
_version=version;
|
||||
}
|
||||
|
||||
public void setContent(byte[] bytes)
|
||||
{
|
||||
try
|
||||
{
|
||||
_content=new ByteArrayOutputStream();
|
||||
_content.write(bytes);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void setContent(String content)
|
||||
{
|
||||
|
|
|
@ -34,6 +34,7 @@ import java.util.List;
|
|||
|
||||
import org.eclipse.jetty.http.HttpGenerator.ResponseInfo;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Test;
|
||||
|
||||
public class HttpGeneratorServerTest
|
||||
|
@ -309,6 +310,54 @@ public class HttpGeneratorServerTest
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendServerXPoweredBy() throws Exception
|
||||
{
|
||||
ByteBuffer header = BufferUtil.allocate(8096);
|
||||
ResponseInfo info = new ResponseInfo(HttpVersion.HTTP_1_1, new HttpFields(), -1, 200, null, false);
|
||||
HttpFields fields = new HttpFields();
|
||||
fields.add(HttpHeader.SERVER,"SomeServer");
|
||||
fields.add(HttpHeader.X_POWERED_BY,"SomePower");
|
||||
ResponseInfo infoF = new ResponseInfo(HttpVersion.HTTP_1_1, fields, -1, 200, null, false);
|
||||
String head;
|
||||
|
||||
HttpGenerator gen = new HttpGenerator(true,true);
|
||||
gen.generateResponse(info, header, null, null, true);
|
||||
head = BufferUtil.toString(header);
|
||||
BufferUtil.clear(header);
|
||||
assertThat(head, containsString("HTTP/1.1 200 OK"));
|
||||
assertThat(head, containsString("Server: Jetty(9.x.x)"));
|
||||
assertThat(head, containsString("X-Powered-By: Jetty(9.x.x)"));
|
||||
gen.reset();
|
||||
gen.generateResponse(infoF, header, null, null, true);
|
||||
head = BufferUtil.toString(header);
|
||||
BufferUtil.clear(header);
|
||||
assertThat(head, containsString("HTTP/1.1 200 OK"));
|
||||
assertThat(head, not(containsString("Server: Jetty(9.x.x)")));
|
||||
assertThat(head, containsString("Server: SomeServer"));
|
||||
assertThat(head, containsString("X-Powered-By: Jetty(9.x.x)"));
|
||||
assertThat(head, containsString("X-Powered-By: SomePower"));
|
||||
gen.reset();
|
||||
|
||||
gen = new HttpGenerator(false,false);
|
||||
gen.generateResponse(info, header, null, null, true);
|
||||
head = BufferUtil.toString(header);
|
||||
BufferUtil.clear(header);
|
||||
assertThat(head, containsString("HTTP/1.1 200 OK"));
|
||||
assertThat(head, not(containsString("Server: Jetty(9.x.x)")));
|
||||
assertThat(head, not(containsString("X-Powered-By: Jetty(9.x.x)")));
|
||||
gen.reset();
|
||||
gen.generateResponse(infoF, header, null, null, true);
|
||||
head = BufferUtil.toString(header);
|
||||
BufferUtil.clear(header);
|
||||
assertThat(head, containsString("HTTP/1.1 200 OK"));
|
||||
assertThat(head, not(containsString("Server: Jetty(9.x.x)")));
|
||||
assertThat(head, containsString("Server: SomeServer"));
|
||||
assertThat(head, not(containsString("X-Powered-By: Jetty(9.x.x)")));
|
||||
assertThat(head, containsString("X-Powered-By: SomePower"));
|
||||
gen.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponseNoContent() throws Exception
|
||||
|
|
|
@ -618,6 +618,13 @@ public class SslConnection extends AbstractConnection
|
|||
}
|
||||
else
|
||||
{
|
||||
if (_encryptedInput.hasRemaining())
|
||||
{
|
||||
// if there are more encrypted bytes,
|
||||
// then we need to unwrap more, we don't
|
||||
// care if net_filled is zero
|
||||
continue;
|
||||
}
|
||||
// we need to wait for more net data
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<version>9.0.4-SNAPSHOT</version>
|
||||
<version>9.0.5-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -54,32 +54,32 @@
|
|||
<!-- for all configuration that may be set here. -->
|
||||
<!-- =========================================================== -->
|
||||
<New id="pushStrategy" class="org.eclipse.jetty.spdy.server.http.ReferrerPushStrategy">
|
||||
<!-- Uncomment to blacklist browsers for this push strategy. If one of the blacklisted Strings occurs in the
|
||||
user-agent header sent by the client, push will be disabled for this browser. This is case insensitive" -->
|
||||
<!--
|
||||
<Set name="UserAgentBlacklist">
|
||||
<Array type="String">
|
||||
<Item>.*(?i)firefox/14.*</Item>
|
||||
<Item>.*(?i)firefox/15.*</Item>
|
||||
<Item>.*(?i)firefox/16.*</Item>
|
||||
</Array>
|
||||
</Set>
|
||||
-->
|
||||
<!-- Uncomment to blacklist browsers for this push strategy. If one of the blacklisted Strings occurs in the
|
||||
user-agent header sent by the client, push will be disabled for this browser. This is case insensitive" -->
|
||||
<!--
|
||||
<Set name="UserAgentBlacklist">
|
||||
<Array type="String">
|
||||
<Item>.*(?i)firefox/14.*</Item>
|
||||
<Item>.*(?i)firefox/15.*</Item>
|
||||
<Item>.*(?i)firefox/16.*</Item>
|
||||
</Array>
|
||||
</Set>
|
||||
-->
|
||||
|
||||
<!-- Uncomment to override default file extensions to push -->
|
||||
<!--
|
||||
<Set name="PushRegexps">
|
||||
<Array type="String">
|
||||
<Item>.*\.css</Item>
|
||||
<Item>.*\.js</Item>
|
||||
<Item>.*\.png</Item>
|
||||
<Item>.*\.jpg</Item>
|
||||
<Item>.*\.gif</Item>
|
||||
</Array>
|
||||
</Set>
|
||||
-->
|
||||
<Set name="referrerPushPeriod">5000</Set>
|
||||
<Set name="maxAssociatedResources">32</Set>
|
||||
<!-- Uncomment to override default file extensions to push -->
|
||||
<!--
|
||||
<Set name="PushRegexps">
|
||||
<Array type="String">
|
||||
<Item>.*\.css</Item>
|
||||
<Item>.*\.js</Item>
|
||||
<Item>.*\.png</Item>
|
||||
<Item>.*\.jpg</Item>
|
||||
<Item>.*\.gif</Item>
|
||||
</Array>
|
||||
</Set>
|
||||
-->
|
||||
<Set name="referrerPushPeriod">5000</Set>
|
||||
<Set name="maxAssociatedResources">32</Set>
|
||||
</New>
|
||||
|
||||
<!-- =========================================================== -->
|
||||
|
@ -121,6 +121,10 @@
|
|||
<Arg name="config">
|
||||
<Ref refid="httpConfig"/>
|
||||
</Arg>
|
||||
<!-- Set the initial window size for this SPDY connector. -->
|
||||
<!-- See: http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3#TOC-2.6.8-WINDOW_UPDATE -->
|
||||
<Set name="initialWindowSize">65536</Set>
|
||||
<!-- Uncomment to enable the push strategy with id "pushStrategy" -->
|
||||
<!-- <Arg name="pushStrategy"><Ref refid="pushStrategy"/></Arg> -->
|
||||
</New>
|
||||
</Item>
|
||||
|
@ -131,6 +135,9 @@
|
|||
<Arg name="config">
|
||||
<Ref refid="httpConfig"/>
|
||||
</Arg>
|
||||
<!-- Set the initial window size for this SPDY connector. -->
|
||||
<!-- See: http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3#TOC-2.6.8-WINDOW_UPDATE -->
|
||||
<Set name="initialWindowSize">65536</Set>
|
||||
</New>
|
||||
</Item>
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>9.0.4-SNAPSHOT</version>
|
||||
<version>9.0.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-overlay-deployer</artifactId>
|
||||
|
|
|
@ -48,6 +48,7 @@ public class HttpConfiguration
|
|||
private int _securePort;
|
||||
private String _secureScheme = HttpScheme.HTTPS.asString();
|
||||
private boolean _sendServerVersion = true; //send Server: header
|
||||
private boolean _sendXPoweredBy = false; //send X-Powered-By: header
|
||||
private boolean _sendDateHeader = false; //send Date: header
|
||||
|
||||
|
||||
|
@ -150,11 +151,22 @@ public class HttpConfiguration
|
|||
_sendServerVersion = sendServerVersion;
|
||||
}
|
||||
|
||||
@ManagedAttribute("if true, include the server version in HTTP headers")
|
||||
@ManagedAttribute("if true, send the Server header in responses")
|
||||
public boolean getSendServerVersion()
|
||||
{
|
||||
return _sendServerVersion;
|
||||
}
|
||||
|
||||
public void setSendXPoweredBy (boolean sendXPoweredBy)
|
||||
{
|
||||
_sendXPoweredBy=sendXPoweredBy;
|
||||
}
|
||||
|
||||
@ManagedAttribute("if true, send the X-Powered-By header in responses")
|
||||
public boolean getSendXPoweredBy()
|
||||
{
|
||||
return _sendXPoweredBy;
|
||||
}
|
||||
|
||||
public void setSendDateHeader(boolean sendDateHeader)
|
||||
{
|
||||
|
|
|
@ -91,8 +91,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
|
|||
_config = config;
|
||||
_connector = connector;
|
||||
_bufferPool = _connector.getByteBufferPool();
|
||||
_generator = new HttpGenerator();
|
||||
_generator.setSendServerVersion(_config.getSendServerVersion());
|
||||
_generator = new HttpGenerator(_config.getSendServerVersion(),_config.getSendXPoweredBy());
|
||||
_channel = new HttpChannelOverHttp(connector, config, endPoint, this, new Input());
|
||||
_parser = newHttpParser();
|
||||
|
||||
|
|
|
@ -45,10 +45,12 @@ import javax.servlet.http.HttpServletRequestWrapper;
|
|||
import javax.servlet.http.Part;
|
||||
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.util.LazyList;
|
||||
import org.eclipse.jetty.util.MultiMap;
|
||||
import org.eclipse.jetty.util.MultiPartInputStreamParser;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
|
@ -259,11 +261,11 @@ public class MultiPartFilter implements Filter
|
|||
{
|
||||
try
|
||||
{
|
||||
return new String((byte[])o,_encoding);
|
||||
return getParameterBytesAsString(name, (byte[])o);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
else if (o!=null)
|
||||
|
@ -282,9 +284,7 @@ public class MultiPartFilter implements Filter
|
|||
|
||||
for ( Object key : _params.keySet() )
|
||||
{
|
||||
String[] a = LazyList.toStringArray(getParameter((String)key));
|
||||
cmap.put((String)key,a);
|
||||
|
||||
cmap.put((String)key,getParameterValues((String)key));
|
||||
}
|
||||
|
||||
return Collections.unmodifiableMap(cmap);
|
||||
|
@ -318,7 +318,7 @@ public class MultiPartFilter implements Filter
|
|||
{
|
||||
try
|
||||
{
|
||||
v[i]=new String((byte[])o,_encoding);
|
||||
v[i]=getParameterBytesAsString(name, (byte[])o);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
|
@ -341,5 +341,23 @@ public class MultiPartFilter implements Filter
|
|||
{
|
||||
_encoding=enc;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
private String getParameterBytesAsString (String name, byte[] bytes)
|
||||
throws UnsupportedEncodingException
|
||||
{
|
||||
//check if there is a specific encoding for the parameter
|
||||
Object ct = _params.getValue(name+CONTENT_TYPE_SUFFIX,0);
|
||||
//use default if not
|
||||
String contentType = _encoding;
|
||||
if (ct != null)
|
||||
{
|
||||
String tmp = MimeTypes.getCharsetFromContentType((String)ct);
|
||||
contentType = (tmp == null?_encoding:tmp);
|
||||
}
|
||||
|
||||
return new String(bytes,contentType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,11 +26,13 @@ import static org.junit.Assert.assertNotNull;
|
|||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.ServletException;
|
||||
|
@ -38,10 +40,12 @@ import javax.servlet.http.HttpServlet;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
|
||||
import org.eclipse.jetty.http.HttpTester;
|
||||
import org.eclipse.jetty.servlet.FilterHolder;
|
||||
import org.eclipse.jetty.servlet.ServletTester;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
@ -105,6 +109,7 @@ public class MultipartFilterTest
|
|||
public void tearDown() throws Exception
|
||||
{
|
||||
tester.stop();
|
||||
tester=null;
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -698,7 +703,6 @@ public class MultipartFilterTest
|
|||
assertTrue(response.getContent().contains("aaaa,bbbbb"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testContentTypeWithCharSet() throws Exception
|
||||
{
|
||||
|
@ -729,7 +733,7 @@ public class MultipartFilterTest
|
|||
assertTrue(response.getContent().indexOf("brown cow")>=0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* see the testParameterMap test
|
||||
*
|
||||
|
@ -786,6 +790,59 @@ public class MultipartFilterTest
|
|||
assertTrue(response.getContent().indexOf("brown cow")>=0);
|
||||
}
|
||||
|
||||
public static class TestServletCharSet extends HttpServlet
|
||||
{
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||
{
|
||||
//test that the multipart content bytes were converted correctly from their charset to unicode
|
||||
String content = (String)req.getParameter("ttt");
|
||||
assertNotNull(content);
|
||||
assertEquals("ttt\u01FCzzz",content);
|
||||
assertEquals("application/octet-stream; charset=UTF-8",req.getParameter("ttt"+MultiPartFilter.CONTENT_TYPE_SUFFIX));
|
||||
|
||||
|
||||
//test that the parameter map retrieves values as String[]
|
||||
Map map = req.getParameterMap();
|
||||
Object o = map.get("ttt");
|
||||
assertTrue(o.getClass().isArray());
|
||||
super.doPost(req, resp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testWithCharSet()
|
||||
throws Exception
|
||||
{
|
||||
// generated and parsed test
|
||||
HttpTester.Request request = HttpTester.newRequest();
|
||||
HttpTester.Response response;
|
||||
tester.addServlet(TestServletCharSet.class,"/test3");
|
||||
|
||||
// test GET
|
||||
request.setMethod("POST");
|
||||
request.setVersion("HTTP/1.0");
|
||||
request.setHeader("Host","tester");
|
||||
request.setURI("/context/test3");
|
||||
|
||||
String boundary="XyXyXy";
|
||||
request.setHeader("Content-Type","multipart/form-data; boundary="+boundary);
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
|
||||
baos.write(("--" + boundary + "\r\n"+
|
||||
"Content-Disposition: form-data; name=\"ttt\"\r\n"+
|
||||
"Content-Type: application/octet-stream; charset=UTF-8\r\n\r\n").getBytes());
|
||||
baos.write("ttt\u01FCzzz".getBytes(StringUtil.__UTF8));
|
||||
baos.write(("\r\n--" + boundary + "--\r\n\r\n").getBytes());
|
||||
|
||||
|
||||
request.setContent(baos.toByteArray());
|
||||
response = HttpTester.parseResponse(tester.getResponses(request.generate()));
|
||||
}
|
||||
|
||||
public static class DumpServlet extends HttpServlet
|
||||
{
|
||||
private static final long serialVersionUID = 201012011130L;
|
||||
|
|
|
@ -60,6 +60,7 @@ public class SPDYClient
|
|||
private volatile SocketAddress bindAddress;
|
||||
private volatile long idleTimeout = -1;
|
||||
private volatile int initialWindowSize;
|
||||
private volatile boolean executeOnFillable;
|
||||
|
||||
protected SPDYClient(short version, Factory factory)
|
||||
{
|
||||
|
@ -125,6 +126,16 @@ public class SPDYClient
|
|||
this.initialWindowSize = initialWindowSize;
|
||||
}
|
||||
|
||||
public boolean isExecuteOnFillable()
|
||||
{
|
||||
return executeOnFillable;
|
||||
}
|
||||
|
||||
public void setExecuteOnFillable(boolean executeOnFillable)
|
||||
{
|
||||
this.executeOnFillable = executeOnFillable;
|
||||
}
|
||||
|
||||
protected String selectProtocol(List<String> serverProtocols)
|
||||
{
|
||||
String protocol = "spdy/" + version;
|
||||
|
|
|
@ -45,7 +45,7 @@ public class SPDYClientConnectionFactory
|
|||
Parser parser = new Parser(compressionFactory.newDecompressor());
|
||||
Generator generator = new Generator(bufferPool, compressionFactory.newCompressor());
|
||||
|
||||
SPDYConnection connection = new ClientSPDYConnection(endPoint, bufferPool, parser, factory);
|
||||
SPDYConnection connection = new ClientSPDYConnection(endPoint, bufferPool, parser, factory, client.isExecuteOnFillable());
|
||||
|
||||
FlowControlStrategy flowControlStrategy = client.newFlowControlStrategy();
|
||||
|
||||
|
@ -66,9 +66,10 @@ public class SPDYClientConnectionFactory
|
|||
{
|
||||
private final Factory factory;
|
||||
|
||||
public ClientSPDYConnection(EndPoint endPoint, ByteBufferPool bufferPool, Parser parser, Factory factory)
|
||||
public ClientSPDYConnection(EndPoint endPoint, ByteBufferPool bufferPool, Parser parser, Factory factory,
|
||||
boolean executeOnFillable)
|
||||
{
|
||||
super(endPoint, bufferPool, parser, factory.getExecutor());
|
||||
super(endPoint, bufferPool, parser, factory.getExecutor(), executeOnFillable);
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,20 +44,26 @@ public class SPDYConnection extends AbstractConnection implements Controller, Id
|
|||
private volatile ISession session;
|
||||
private volatile boolean idle = false;
|
||||
|
||||
|
||||
public SPDYConnection(EndPoint endPoint, ByteBufferPool bufferPool, Parser parser, Executor executor)
|
||||
public SPDYConnection(EndPoint endPoint, ByteBufferPool bufferPool, Parser parser, Executor executor,
|
||||
boolean executeOnFillable)
|
||||
{
|
||||
this(endPoint, bufferPool, parser, executor, 8192);
|
||||
this(endPoint, bufferPool, parser, executor, executeOnFillable, 8192);
|
||||
}
|
||||
|
||||
public SPDYConnection(EndPoint endPoint, ByteBufferPool bufferPool, Parser parser, Executor executor, int bufferSize)
|
||||
public SPDYConnection(EndPoint endPoint, ByteBufferPool bufferPool, Parser parser, Executor executor,
|
||||
boolean executeOnFillable, int bufferSize)
|
||||
{
|
||||
// Since SPDY is multiplexed, onFillable() must never block
|
||||
// while calling application code. In fact, onFillable()
|
||||
// always dispatches to a new thread when calling application
|
||||
// code, so here we can safely pass false as last parameter,
|
||||
// and avoid to dispatch to onFillable().
|
||||
super(endPoint, executor, !EXECUTE_ONFILLABLE);
|
||||
// Since SPDY is multiplexed, onFillable() must never block while calling application code. In fact,
|
||||
// the SPDY code always dispatches to a new thread when calling application code,
|
||||
// so here we can safely pass false as last parameter, and avoid to dispatch to onFillable(). The IO
|
||||
// operation (read, parse, etc.) will not block and will be fast in almost all cases. Big uploads to a server
|
||||
// however might block the Selector thread for a long time and therefore block other connections to be read.
|
||||
// This might be a good reason to set executeOnFillable to true.
|
||||
//
|
||||
// Due to a jvm bug we've had a Selector thread being stuck at
|
||||
// sun.nio.ch.FileDispatcherImpl.preClose0(Native Method). That's why we now default executeOnFillable to
|
||||
// true even if for most use cases it is faster to not dispatch the IO events.
|
||||
super(endPoint, executor, executeOnFillable);
|
||||
this.bufferPool = bufferPool;
|
||||
this.parser = parser;
|
||||
onIdle(true);
|
||||
|
|
|
@ -8,128 +8,150 @@
|
|||
<!-- ============================================================= -->
|
||||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- Enables NPN debugging on System.err -->
|
||||
<!-- ===========================================================
|
||||
<Set class="org.eclipse.jetty.npn.NextProtoNego" name="debug" type="boolean">true</Set>
|
||||
-->
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- Create a push strategy which can be used by reference by -->
|
||||
<!-- individual connection factories below. -->
|
||||
<!-- -->
|
||||
<!-- Consult the javadoc of o.e.j.spdy.server.http.ReferrerPushStrategy -->
|
||||
<!-- for all configuration that may be set here. -->
|
||||
<!-- =========================================================== -->
|
||||
<New id="pushStrategy" class="org.eclipse.jetty.spdy.server.http.ReferrerPushStrategy">
|
||||
<!-- Uncomment to blacklist browsers for this push strategy. If one of the blacklisted Strings occurs in the
|
||||
user-agent header sent by the client, push will be disabled for this browser. This is case insensitive" -->
|
||||
<!--
|
||||
<Set name="UserAgentBlacklist">
|
||||
<Array type="String">
|
||||
<Item>.*(?i)firefox/14.*</Item>
|
||||
<Item>.*(?i)firefox/15.*</Item>
|
||||
<Item>.*(?i)firefox/16.*</Item>
|
||||
</Array>
|
||||
</Set>
|
||||
<!-- =========================================================== -->
|
||||
<!-- Enables NPN debugging on System.err -->
|
||||
<!-- ===========================================================
|
||||
<Set class="org.eclipse.jetty.npn.NextProtoNego" name="debug" type="boolean">true</Set>
|
||||
-->
|
||||
|
||||
<!-- Uncomment to override default file extensions to push -->
|
||||
<!--
|
||||
<Set name="PushRegexps">
|
||||
<Array type="String">
|
||||
<Item>.*\.css</Item>
|
||||
<Item>.*\.js</Item>
|
||||
<Item>.*\.png</Item>
|
||||
<Item>.*\.jpg</Item>
|
||||
<Item>.*\.gif</Item>
|
||||
</Array>
|
||||
</Set>
|
||||
-->
|
||||
<Set name="referrerPushPeriod">5000</Set>
|
||||
<Set name="maxAssociatedResources">32</Set>
|
||||
</New>
|
||||
<!-- =========================================================== -->
|
||||
<!-- Create a push strategy which can be used by reference by -->
|
||||
<!-- individual connection factories below. -->
|
||||
<!-- -->
|
||||
<!-- Consult the javadoc of o.e.j.spdy.server.http.ReferrerPushStrategy -->
|
||||
<!-- for all configuration that may be set here. -->
|
||||
<!-- =========================================================== -->
|
||||
<New id="pushStrategy" class="org.eclipse.jetty.spdy.server.http.ReferrerPushStrategy">
|
||||
<!-- Uncomment to blacklist browsers for this push strategy. If one of the blacklisted Strings occurs in the
|
||||
user-agent header sent by the client, push will be disabled for this browser. This is case insensitive" -->
|
||||
<!--
|
||||
<Set name="UserAgentBlacklist">
|
||||
<Array type="String">
|
||||
<Item>.*(?i)firefox/14.*</Item>
|
||||
<Item>.*(?i)firefox/15.*</Item>
|
||||
<Item>.*(?i)firefox/16.*</Item>
|
||||
</Array>
|
||||
</Set>
|
||||
-->
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- Add a SPDY/HTTPS Connector. -->
|
||||
<!-- Configure an o.e.j.server.ServerConnector with connection -->
|
||||
<!-- factories for TLS (aka SSL), NPN, SPDY and HTTP to provide -->
|
||||
<!-- a connector that can accept HTTPS or SPDY connections. -->
|
||||
<!-- -->
|
||||
<!-- All accepted TLS connections are initially wired to a NPN -->
|
||||
<!-- connection, which attempts to use a TLS extension to -->
|
||||
<!-- negotiation the protocol. If NPN is not supported by -->
|
||||
<!-- the client, then the NPN connection is replaced by a HTTP -->
|
||||
<!-- connection. If a specific protocol version (eg spdy/3) is -->
|
||||
<!-- negotiated by NPN, then the appropriate connection factory -->
|
||||
<!-- is used to create a connection to replace the NPN connection-->
|
||||
<!-- -->
|
||||
<!-- The final result is a SPDY or HTTP connection wired behind -->
|
||||
<!-- a TLS (aka SSL) connection. -->
|
||||
<!-- -->
|
||||
<!-- Consult the javadoc of o.e.j.server.ServerConnector and the -->
|
||||
<!-- specific connection factory types for all configuration -->
|
||||
<!-- that may be set here. -->
|
||||
<!-- =========================================================== -->
|
||||
<Call id="spdyConnector" name="addConnector">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.server.ServerConnector">
|
||||
<Arg name="server"><Ref refid="Server" /></Arg>
|
||||
<Arg name="factories">
|
||||
<Array type="org.eclipse.jetty.server.ConnectionFactory">
|
||||
<!-- Uncomment to override default file extensions to push -->
|
||||
<!--
|
||||
<Set name="PushRegexps">
|
||||
<Array type="String">
|
||||
<Item>.*\.css</Item>
|
||||
<Item>.*\.js</Item>
|
||||
<Item>.*\.png</Item>
|
||||
<Item>.*\.jpg</Item>
|
||||
<Item>.*\.gif</Item>
|
||||
</Array>
|
||||
</Set>
|
||||
-->
|
||||
<Set name="referrerPushPeriod">5000</Set>
|
||||
<Set name="maxAssociatedResources">32</Set>
|
||||
</New>
|
||||
|
||||
<!-- SSL Connection factory with NPN as next protocol -->
|
||||
<Item>
|
||||
<New class="org.eclipse.jetty.server.SslConnectionFactory">
|
||||
<Arg name="next">npn</Arg>
|
||||
<Arg name="sslContextFactory"><Ref refid="sslContextFactory" /></Arg>
|
||||
</New>
|
||||
</Item>
|
||||
<!-- =========================================================== -->
|
||||
<!-- Add a SPDY/HTTPS Connector. -->
|
||||
<!-- Configure an o.e.j.server.ServerConnector with connection -->
|
||||
<!-- factories for TLS (aka SSL), NPN, SPDY and HTTP to provide -->
|
||||
<!-- a connector that can accept HTTPS or SPDY connections. -->
|
||||
<!-- -->
|
||||
<!-- All accepted TLS connections are initially wired to a NPN -->
|
||||
<!-- connection, which attempts to use a TLS extension to -->
|
||||
<!-- negotiation the protocol. If NPN is not supported by -->
|
||||
<!-- the client, then the NPN connection is replaced by a HTTP -->
|
||||
<!-- connection. If a specific protocol version (eg spdy/3) is -->
|
||||
<!-- negotiated by NPN, then the appropriate connection factory -->
|
||||
<!-- is used to create a connection to replace the NPN connection-->
|
||||
<!-- -->
|
||||
<!-- The final result is a SPDY or HTTP connection wired behind -->
|
||||
<!-- a TLS (aka SSL) connection. -->
|
||||
<!-- -->
|
||||
<!-- Consult the javadoc of o.e.j.server.ServerConnector and the -->
|
||||
<!-- specific connection factory types for all configuration -->
|
||||
<!-- that may be set here. -->
|
||||
<!-- =========================================================== -->
|
||||
<Call id="spdyConnector" name="addConnector">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.server.ServerConnector">
|
||||
<Arg name="server">
|
||||
<Ref refid="Server"/>
|
||||
</Arg>
|
||||
<Arg name="factories">
|
||||
<Array type="org.eclipse.jetty.server.ConnectionFactory">
|
||||
|
||||
<!-- NPN Connection factory with HTTP as default protocol -->
|
||||
<Item>
|
||||
<New class="org.eclipse.jetty.spdy.server.NPNServerConnectionFactory">
|
||||
<Arg name="protocols"><Array type="String">
|
||||
<Item>spdy/3</Item>
|
||||
<Item>spdy/2</Item>
|
||||
<Item>http/1.1</Item>
|
||||
</Array></Arg>
|
||||
<Set name="defaultProtocol">http/1.1</Set>
|
||||
</New>
|
||||
</Item>
|
||||
<!-- SSL Connection factory with NPN as next protocol -->
|
||||
<Item>
|
||||
<New class="org.eclipse.jetty.server.SslConnectionFactory">
|
||||
<Arg name="next">npn</Arg>
|
||||
<Arg name="sslContextFactory">
|
||||
<Ref refid="sslContextFactory"/>
|
||||
</Arg>
|
||||
</New>
|
||||
</Item>
|
||||
|
||||
<!-- SPDY/3 Connection factory -->
|
||||
<Item>
|
||||
<New class="org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory">
|
||||
<Arg name="version" type="int">3</Arg>
|
||||
<Arg name="config"><Ref refid="sslHttpConfig" /></Arg>
|
||||
<!-- Uncomment to enable ReferrerPushStrategy -->
|
||||
<!--<Arg name="pushStrategy"><Ref refid="pushStrategy"/></Arg>-->
|
||||
</New>
|
||||
</Item>
|
||||
<!-- NPN Connection factory with HTTP as default protocol -->
|
||||
<Item>
|
||||
<New class="org.eclipse.jetty.spdy.server.NPNServerConnectionFactory">
|
||||
<Arg name="protocols">
|
||||
<Array type="String">
|
||||
<Item>spdy/3</Item>
|
||||
<Item>spdy/2</Item>
|
||||
<Item>http/1.1</Item>
|
||||
</Array>
|
||||
</Arg>
|
||||
<Set name="defaultProtocol">http/1.1</Set>
|
||||
</New>
|
||||
</Item>
|
||||
|
||||
<!-- SPDY/2 Connection factory -->
|
||||
<Item>
|
||||
<New class="org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory">
|
||||
<Arg name="version" type="int">2</Arg>
|
||||
<Arg name="config"><Ref refid="sslHttpConfig" /></Arg>
|
||||
</New>
|
||||
</Item>
|
||||
<!-- SPDY/3 Connection factory -->
|
||||
<Item>
|
||||
<New class="org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory">
|
||||
<Arg name="version" type="int">3</Arg>
|
||||
<Arg name="config">
|
||||
<Ref refid="sslHttpConfig"/>
|
||||
</Arg>
|
||||
<!-- Set the initial window size for this SPDY connector. -->
|
||||
<!-- See: http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3#TOC-2.6.8-WINDOW_UPDATE -->
|
||||
<Set name="initialWindowSize">65536</Set>
|
||||
<!-- Uncomment to enable ReferrerPushStrategy -->
|
||||
<!--<Arg name="pushStrategy"><Ref refid="pushStrategy"/></Arg>-->
|
||||
</New>
|
||||
</Item>
|
||||
|
||||
<!-- HTTP Connection factory -->
|
||||
<Item>
|
||||
<New class="org.eclipse.jetty.server.HttpConnectionFactory">
|
||||
<Arg name="config"><Ref refid="sslHttpConfig" /></Arg>
|
||||
</New>
|
||||
</Item>
|
||||
</Array>
|
||||
<!-- SPDY/2 Connection factory -->
|
||||
<Item>
|
||||
<New class="org.eclipse.jetty.spdy.server.http.HTTPSPDYServerConnectionFactory">
|
||||
<Arg name="version" type="int">2</Arg>
|
||||
<Arg name="config">
|
||||
<Ref refid="sslHttpConfig"/>
|
||||
</Arg>
|
||||
<!-- Set the initial window size for this SPDY connector. -->
|
||||
<!-- See: http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3#TOC-2.6.8-WINDOW_UPDATE -->
|
||||
<Set name="initialWindowSize">65536</Set>
|
||||
</New>
|
||||
</Item>
|
||||
|
||||
<!-- HTTP Connection factory -->
|
||||
<Item>
|
||||
<New class="org.eclipse.jetty.server.HttpConnectionFactory">
|
||||
<Arg name="config">
|
||||
<Ref refid="sslHttpConfig"/>
|
||||
</Arg>
|
||||
</New>
|
||||
</Item>
|
||||
</Array>
|
||||
</Arg>
|
||||
|
||||
<Set name="host">
|
||||
<Property name="jetty.host"/>
|
||||
</Set>
|
||||
<Set name="port">
|
||||
<Property name="jetty.spdy.port" default="8443"/>
|
||||
</Set>
|
||||
<Set name="idleTimeout">30000</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
|
||||
<Set name="host"><Property name="jetty.host" /></Set>
|
||||
<Set name="port"><Property name="jetty.spdy.port" default="8443" /></Set>
|
||||
<Set name="idleTimeout">30000</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
</Call>
|
||||
|
||||
</Configure>
|
||||
|
|
|
@ -98,7 +98,7 @@ public class HTTPSPDYServerConnectionFactory extends SPDYServerConnectionFactory
|
|||
|
||||
Fields headers = synInfo.getHeaders();
|
||||
// According to SPDY/3 spec section 3.2.1 user-agents MUST support gzip compression. Firefox omits the
|
||||
// accep-encoding header as it is redundant to negotiate gzip compression support with the server,
|
||||
// accept-encoding header as it is redundant to negotiate gzip compression support with the server,
|
||||
// if clients have to accept it.
|
||||
// So we inject the accept-encoding header here, even if not set by the client. This will enforce SPDY
|
||||
// clients to follow the spec and enable gzip compression if GzipFilter or the like is enabled.
|
||||
|
|
|
@ -69,6 +69,7 @@ public class SPDYServerConnectionFactory extends AbstractConnectionFactory
|
|||
private final short version;
|
||||
private final ServerSessionFrameListener listener;
|
||||
private int initialWindowSize;
|
||||
private boolean executeOnFillable = true;
|
||||
private final Queue<Session> sessions = new ConcurrentLinkedQueue<>();
|
||||
|
||||
public SPDYServerConnectionFactory(int version)
|
||||
|
@ -103,14 +104,15 @@ public class SPDYServerConnectionFactory extends AbstractConnectionFactory
|
|||
Generator generator = new Generator(connector.getByteBufferPool(), compressionFactory.newCompressor());
|
||||
|
||||
ServerSessionFrameListener listener = provideServerSessionFrameListener(connector, endPoint);
|
||||
SPDYConnection connection = new ServerSPDYConnection(connector, endPoint, parser, listener, getInputBufferSize());
|
||||
SPDYConnection connection = new ServerSPDYConnection(connector, endPoint, parser, listener,
|
||||
executeOnFillable, getInputBufferSize());
|
||||
|
||||
FlowControlStrategy flowControlStrategy = newFlowControlStrategy(version);
|
||||
|
||||
StandardSession session = new StandardSession(getVersion(), connector.getByteBufferPool(),
|
||||
connector.getExecutor(), connector.getScheduler(), connection, endPoint, connection, 2, listener,
|
||||
generator, flowControlStrategy);
|
||||
session.setWindowSize(getInitialWindowSize());
|
||||
session.setWindowSize(initialWindowSize);
|
||||
parser.addListener(session);
|
||||
connection.setSession(session);
|
||||
|
||||
|
@ -140,6 +142,17 @@ public class SPDYServerConnectionFactory extends AbstractConnectionFactory
|
|||
this.initialWindowSize = initialWindowSize;
|
||||
}
|
||||
|
||||
@ManagedAttribute("Execute onFillable")
|
||||
public boolean isExecuteOnFillable()
|
||||
{
|
||||
return executeOnFillable;
|
||||
}
|
||||
|
||||
public void setExecuteOnFillable(boolean executeOnFillable)
|
||||
{
|
||||
this.executeOnFillable = executeOnFillable;
|
||||
}
|
||||
|
||||
protected boolean sessionOpened(Session session)
|
||||
{
|
||||
// Add sessions only if the connector is not stopping
|
||||
|
@ -177,9 +190,11 @@ public class SPDYServerConnectionFactory extends AbstractConnectionFactory
|
|||
private final ServerSessionFrameListener listener;
|
||||
private final AtomicBoolean connected = new AtomicBoolean();
|
||||
|
||||
private ServerSPDYConnection(Connector connector, EndPoint endPoint, Parser parser, ServerSessionFrameListener listener, int bufferSize)
|
||||
private ServerSPDYConnection(Connector connector, EndPoint endPoint, Parser parser,
|
||||
ServerSessionFrameListener listener, boolean executeOnFillable, int bufferSize)
|
||||
{
|
||||
super(endPoint, connector.getByteBufferPool(), parser, connector.getExecutor(), bufferSize);
|
||||
super(endPoint, connector.getByteBufferPool(), parser, connector.getExecutor(),
|
||||
executeOnFillable, bufferSize);
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@ import java.util.concurrent.TimeUnit;
|
|||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.eclipse.jetty.io.EofException;
|
||||
import org.eclipse.jetty.spdy.api.DataInfo;
|
||||
import org.eclipse.jetty.spdy.api.GoAwayInfo;
|
||||
import org.eclipse.jetty.spdy.api.GoAwayResultInfo;
|
||||
|
@ -41,7 +40,6 @@ import org.eclipse.jetty.util.Callback;
|
|||
import org.eclipse.jetty.util.Fields;
|
||||
import org.eclipse.jetty.util.FutureCallback;
|
||||
import org.eclipse.jetty.util.FuturePromise;
|
||||
import org.hamcrest.CoreMatchers;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -223,7 +221,8 @@ public class GoAwayTest extends AbstractTest
|
|||
}
|
||||
catch (ExecutionException x)
|
||||
{
|
||||
Assert.assertThat(x.getCause(), CoreMatchers.instanceOf(EofException.class));
|
||||
// doesn't matter which exception we get, it's important that the data is not been written and the
|
||||
// previous assertion is true
|
||||
}
|
||||
|
||||
// The last good stream is the second, because it was received by the server
|
||||
|
|
|
@ -141,6 +141,21 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
|
|||
return String.format("%s@%x",FlushInvoker.class.getSimpleName(),hashCode());
|
||||
}
|
||||
}
|
||||
|
||||
public class OnDisconnectCallback implements WriteCallback
|
||||
{
|
||||
@Override
|
||||
public void writeFailed(Throwable x)
|
||||
{
|
||||
disconnect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSuccess()
|
||||
{
|
||||
disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Stats
|
||||
{
|
||||
|
@ -233,6 +248,7 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
|
|||
@Override
|
||||
public void disconnect()
|
||||
{
|
||||
LOG.debug("{} disconnect()", policy.getBehavior());
|
||||
synchronized (writeBytes)
|
||||
{
|
||||
if (!writeBytes.isClosed())
|
||||
|
@ -433,7 +449,7 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
|
|||
@Override
|
||||
public void onConnectionStateChange(ConnectionState state)
|
||||
{
|
||||
LOG.debug("Connection State Change: {}",state);
|
||||
LOG.debug("{} Connection State Change: {}",policy.getBehavior(),state);
|
||||
switch (state)
|
||||
{
|
||||
case OPEN:
|
||||
|
@ -446,7 +462,7 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
|
|||
case CLOSING:
|
||||
CloseInfo close = ioState.getCloseInfo();
|
||||
// append close frame
|
||||
outgoingFrame(close.asFrame(),null);
|
||||
outgoingFrame(close.asFrame(),new OnDisconnectCallback());
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -182,11 +182,13 @@ public class IOState
|
|||
*/
|
||||
public void onCloseLocal(CloseInfo close)
|
||||
{
|
||||
LOG.debug("onCloseLocal({})",close);
|
||||
ConnectionState event = null;
|
||||
ConnectionState initialState = this.state;
|
||||
if (initialState == ConnectionState.CLOSED)
|
||||
{
|
||||
// already closed
|
||||
LOG.debug("already closed");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -224,15 +226,19 @@ public class IOState
|
|||
event = this.state;
|
||||
}
|
||||
}
|
||||
|
||||
LOG.debug("event = {}",event);
|
||||
|
||||
// Only notify on state change events
|
||||
if (event != null)
|
||||
{
|
||||
LOG.debug("notifying state listeners: {}",event);
|
||||
notifyStateListeners(event);
|
||||
|
||||
// if SHUTDOWN, we don't expect an answer.
|
||||
if (close.getStatusCode() == StatusCode.SHUTDOWN)
|
||||
// if harsh, we don't expect an answer.
|
||||
if (close.isHarsh())
|
||||
{
|
||||
LOG.debug("Harsh close, disconnecting");
|
||||
synchronized (this.state)
|
||||
{
|
||||
this.state = ConnectionState.CLOSED;
|
||||
|
@ -253,6 +259,7 @@ public class IOState
|
|||
*/
|
||||
public void onCloseRemote(CloseInfo close)
|
||||
{
|
||||
LOG.debug("onCloseRemote({})",close);
|
||||
ConnectionState event = null;
|
||||
synchronized (this.state)
|
||||
{
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.eclipse.jetty.io.EndPoint;
|
|||
import org.eclipse.jetty.util.thread.Scheduler;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
|
||||
import org.eclipse.jetty.websocket.common.ConnectionState;
|
||||
import org.eclipse.jetty.websocket.common.io.AbstractWebSocketConnection;
|
||||
|
||||
public class WebSocketServerConnection extends AbstractWebSocketConnection
|
||||
|
@ -74,7 +75,7 @@ public class WebSocketServerConnection extends AbstractWebSocketConnection
|
|||
}
|
||||
super.onOpen();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setNextIncomingFrames(IncomingFrames incoming)
|
||||
{
|
||||
|
|
|
@ -23,8 +23,12 @@ import static org.hamcrest.Matchers.*;
|
|||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.common.OpCode;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.server.blockhead.BlockheadClient;
|
||||
import org.eclipse.jetty.websocket.server.helper.IncomingFramesCapture;
|
||||
import org.eclipse.jetty.websocket.server.helper.RFCSocket;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
|
||||
|
@ -69,7 +73,7 @@ public class IdleTimeoutTest
|
|||
{
|
||||
BlockheadClient client = new BlockheadClient(server.getServerUri());
|
||||
client.setProtocols("onConnect");
|
||||
client.setTimeout(TimeUnit.MILLISECONDS,1500);
|
||||
client.setTimeout(TimeUnit.MILLISECONDS,2500);
|
||||
try
|
||||
{
|
||||
client.connect();
|
||||
|
@ -83,13 +87,15 @@ public class IdleTimeoutTest
|
|||
// Write to server (the server should be timed out and disconnect now)
|
||||
client.write(WebSocketFrame.text("Hello"));
|
||||
|
||||
// now attempt to read 2 echoed frames from server (shouldn't work)
|
||||
client.readFrames(2,TimeUnit.MILLISECONDS,1500);
|
||||
Assert.fail("Should have resulted in IOException");
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
Assert.assertThat("IOException",e.getMessage(),anyOf(containsString("closed"),containsString("disconnected")));
|
||||
// now read 1 frame from server (should be close frame)
|
||||
IncomingFramesCapture capture = client.readFrames(1,TimeUnit.MILLISECONDS,1500);
|
||||
WebSocketFrame frame = capture.getFrames().poll();
|
||||
Assert.assertThat("Was close frame", frame.getOpCode(), is(OpCode.CLOSE));
|
||||
CloseInfo close = new CloseInfo(frame);
|
||||
Assert.assertThat("Close.code", close.getStatusCode(), is(StatusCode.SHUTDOWN));
|
||||
Assert.assertThat("Close.reason", close.getReason(), containsString("Idle Timeout"));
|
||||
|
||||
client.expectServerDisconnect();
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
@ -25,6 +25,9 @@ import java.util.concurrent.Future;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
||||
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.client.WebSocketClient;
|
||||
import org.eclipse.jetty.websocket.server.helper.CaptureSocket;
|
||||
|
@ -32,10 +35,14 @@ import org.eclipse.jetty.websocket.server.helper.SessionServlet;
|
|||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
public class WebSocketOverSSLTest
|
||||
{
|
||||
@Rule
|
||||
public TestTracker tracker = new TestTracker();
|
||||
|
||||
private static SimpleServletServer server;
|
||||
|
||||
@BeforeClass
|
||||
|
@ -65,7 +72,9 @@ public class WebSocketOverSSLTest
|
|||
client.start();
|
||||
|
||||
CaptureSocket clientSocket = new CaptureSocket();
|
||||
Future<Session> fut = client.connect(clientSocket,server.getServerUri());
|
||||
URI requestUri = server.getServerUri();
|
||||
System.err.printf("Request URI: %s%n",requestUri.toASCIIString());
|
||||
Future<Session> fut = client.connect(clientSocket,requestUri);
|
||||
|
||||
// wait for connect
|
||||
Session session = fut.get(3,TimeUnit.SECONDS);
|
||||
|
@ -142,13 +151,13 @@ public class WebSocketOverSSLTest
|
|||
CaptureSocket clientSocket = new CaptureSocket();
|
||||
URI requestUri = server.getServerUri().resolve("/deep?a=b");
|
||||
System.err.printf("Request URI: %s%n",requestUri.toASCIIString());
|
||||
client.connect(clientSocket,requestUri);
|
||||
Future<Session> fut = client.connect(clientSocket,requestUri);
|
||||
|
||||
// wait for connect
|
||||
clientSocket.awaitConnected(5000);
|
||||
Session session = fut.get(5,TimeUnit.SECONDS);
|
||||
|
||||
// Generate text frame
|
||||
clientSocket.getRemote().sendString("session.upgradeRequest.requestURI");
|
||||
session.getRemote().sendString("session.upgradeRequest.requestURI");
|
||||
|
||||
// Read frame (hopefully text frame)
|
||||
clientSocket.messages.awaitEventCount(1,500,TimeUnit.MILLISECONDS);
|
||||
|
|
|
@ -62,13 +62,18 @@ public class Fuzzer
|
|||
PER_FRAME,
|
||||
SLOW
|
||||
}
|
||||
|
||||
public static enum DisconnectMode
|
||||
{
|
||||
/** Disconnect occurred after a proper close handshake */
|
||||
CLEAN,
|
||||
/** Disconnect occurred in a harsh manner, without a close handshake */
|
||||
UNCLEAN
|
||||
}
|
||||
|
||||
private static final int KBYTE = 1024;
|
||||
private static final int MBYTE = KBYTE * KBYTE;
|
||||
|
||||
public static final boolean CLEAN_CLOSE = true;
|
||||
public static final boolean NOT_CLEAN_CLOSE = false;
|
||||
|
||||
private static final Logger LOG = Log.getLogger(Fuzzer.class);
|
||||
|
||||
// Client side framing mask
|
||||
|
@ -89,6 +94,7 @@ public class Fuzzer
|
|||
|
||||
policy.setMaxTextMessageSize(bigMessageSize);
|
||||
policy.setMaxBinaryMessageSize(bigMessageSize);
|
||||
policy.setIdleTimeout(5000);
|
||||
|
||||
this.client = new BlockheadClient(policy,testcase.getServer().getServerUri());
|
||||
this.generator = testcase.getLaxGenerator();
|
||||
|
@ -184,35 +190,21 @@ public class Fuzzer
|
|||
// TODO Should test for no more frames. success if connection closed.
|
||||
}
|
||||
|
||||
public void expectServerClose(boolean wasClean) throws IOException, InterruptedException
|
||||
public void expectServerDisconnect(DisconnectMode mode)
|
||||
{
|
||||
// we expect that the close handshake to have occurred and the server should have closed the connection
|
||||
try
|
||||
{
|
||||
ByteBuffer buf = ByteBuffer.wrap(new byte[]
|
||||
{ 0x00 });
|
||||
BufferUtil.flipToFill(buf);
|
||||
int len = client.read(buf);
|
||||
|
||||
Assert.assertThat("Server has not closed socket",len,lessThanOrEqualTo(0));
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
// valid path
|
||||
}
|
||||
|
||||
client.expectServerDisconnect();
|
||||
IOState ios = client.getIOState();
|
||||
|
||||
if (wasClean)
|
||||
switch (mode)
|
||||
{
|
||||
Assert.assertTrue(ios.wasRemoteCloseInitiated());
|
||||
Assert.assertTrue(ios.wasCleanClose());
|
||||
case CLEAN:
|
||||
Assert.assertTrue(ios.wasRemoteCloseInitiated());
|
||||
Assert.assertTrue(ios.wasCleanClose());
|
||||
break;
|
||||
case UNCLEAN:
|
||||
Assert.assertTrue(ios.wasRemoteCloseInitiated());
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.assertTrue(ios.wasRemoteCloseInitiated());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public CloseState getCloseState()
|
||||
|
@ -343,20 +335,6 @@ public class Fuzzer
|
|||
}
|
||||
}
|
||||
|
||||
public void sendExpectingIOException(ByteBuffer part3)
|
||||
{
|
||||
try
|
||||
{
|
||||
send(part3);
|
||||
Assert.fail("Expected a IOException on this send");
|
||||
}
|
||||
catch (IOException ignore)
|
||||
{
|
||||
// Send, but expect the send to fail with a IOException.
|
||||
// Usually, this is a SocketException("Socket Closed") condition.
|
||||
}
|
||||
}
|
||||
|
||||
private void setClientMask(WebSocketFrame f)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
|
|
|
@ -51,7 +51,7 @@ public class TestABCase1 extends AbstractABCase
|
|||
fuzzer.setSendMode(SendMode.BULK);
|
||||
fuzzer.send(send);
|
||||
fuzzer.expect(expect);
|
||||
fuzzer.expectServerClose(Fuzzer.CLEAN_CLOSE);
|
||||
fuzzer.expectServerDisconnect(Fuzzer.DisconnectMode.CLEAN);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -83,6 +83,7 @@ public class TestABCase1 extends AbstractABCase
|
|||
fuzzer.setSendMode(SendMode.BULK);
|
||||
fuzzer.send(send);
|
||||
fuzzer.expect(expect);
|
||||
fuzzer.expectServerDisconnect(Fuzzer.DisconnectMode.CLEAN);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -114,6 +115,7 @@ public class TestABCase1 extends AbstractABCase
|
|||
fuzzer.setSendMode(SendMode.BULK);
|
||||
fuzzer.send(send);
|
||||
fuzzer.expect(expect);
|
||||
fuzzer.expectServerDisconnect(Fuzzer.DisconnectMode.CLEAN);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -145,6 +147,7 @@ public class TestABCase1 extends AbstractABCase
|
|||
fuzzer.setSendMode(SendMode.BULK);
|
||||
fuzzer.send(send);
|
||||
fuzzer.expect(expect);
|
||||
fuzzer.expectServerDisconnect(Fuzzer.DisconnectMode.CLEAN);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -176,6 +179,7 @@ public class TestABCase1 extends AbstractABCase
|
|||
fuzzer.setSendMode(SendMode.BULK);
|
||||
fuzzer.send(send);
|
||||
fuzzer.expect(expect);
|
||||
fuzzer.expectServerDisconnect(Fuzzer.DisconnectMode.CLEAN);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -207,6 +211,7 @@ public class TestABCase1 extends AbstractABCase
|
|||
fuzzer.setSendMode(SendMode.BULK);
|
||||
fuzzer.send(send);
|
||||
fuzzer.expect(expect);
|
||||
fuzzer.expectServerDisconnect(Fuzzer.DisconnectMode.CLEAN);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -238,6 +243,7 @@ public class TestABCase1 extends AbstractABCase
|
|||
fuzzer.setSendMode(SendMode.BULK);
|
||||
fuzzer.send(send);
|
||||
fuzzer.expect(expect);
|
||||
fuzzer.expectServerDisconnect(Fuzzer.DisconnectMode.CLEAN);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -275,6 +281,7 @@ public class TestABCase1 extends AbstractABCase
|
|||
fuzzer.setSlowSendSegmentSize(segmentSize);
|
||||
fuzzer.send(send);
|
||||
fuzzer.expect(expect);
|
||||
fuzzer.expectServerDisconnect(Fuzzer.DisconnectMode.CLEAN);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -303,6 +310,7 @@ public class TestABCase1 extends AbstractABCase
|
|||
fuzzer.setSendMode(SendMode.BULK);
|
||||
fuzzer.send(send);
|
||||
fuzzer.expect(expect);
|
||||
fuzzer.expectServerDisconnect(Fuzzer.DisconnectMode.CLEAN);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -334,6 +342,7 @@ public class TestABCase1 extends AbstractABCase
|
|||
fuzzer.setSendMode(SendMode.BULK);
|
||||
fuzzer.send(send);
|
||||
fuzzer.expect(expect);
|
||||
fuzzer.expectServerDisconnect(Fuzzer.DisconnectMode.CLEAN);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -365,6 +374,7 @@ public class TestABCase1 extends AbstractABCase
|
|||
fuzzer.setSendMode(SendMode.BULK);
|
||||
fuzzer.send(send);
|
||||
fuzzer.expect(expect);
|
||||
fuzzer.expectServerDisconnect(Fuzzer.DisconnectMode.CLEAN);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -396,6 +406,7 @@ public class TestABCase1 extends AbstractABCase
|
|||
fuzzer.setSendMode(SendMode.BULK);
|
||||
fuzzer.send(send);
|
||||
fuzzer.expect(expect);
|
||||
fuzzer.expectServerDisconnect(Fuzzer.DisconnectMode.CLEAN);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -427,6 +438,7 @@ public class TestABCase1 extends AbstractABCase
|
|||
fuzzer.setSendMode(SendMode.BULK);
|
||||
fuzzer.send(send);
|
||||
fuzzer.expect(expect);
|
||||
fuzzer.expectServerDisconnect(Fuzzer.DisconnectMode.CLEAN);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -458,6 +470,7 @@ public class TestABCase1 extends AbstractABCase
|
|||
fuzzer.setSendMode(SendMode.BULK);
|
||||
fuzzer.send(send);
|
||||
fuzzer.expect(expect);
|
||||
fuzzer.expectServerDisconnect(Fuzzer.DisconnectMode.CLEAN);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -489,6 +502,7 @@ public class TestABCase1 extends AbstractABCase
|
|||
fuzzer.setSendMode(SendMode.BULK);
|
||||
fuzzer.send(send);
|
||||
fuzzer.expect(expect);
|
||||
fuzzer.expectServerDisconnect(Fuzzer.DisconnectMode.CLEAN);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -526,6 +540,7 @@ public class TestABCase1 extends AbstractABCase
|
|||
fuzzer.setSlowSendSegmentSize(segmentSize);
|
||||
fuzzer.send(send);
|
||||
fuzzer.expect(expect);
|
||||
fuzzer.expectServerDisconnect(Fuzzer.DisconnectMode.CLEAN);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
@ -24,6 +24,7 @@ import java.util.List;
|
|||
|
||||
import org.eclipse.jetty.toolchain.test.AdvancedRunner;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.log.StacklessLogging;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.common.OpCode;
|
||||
|
@ -236,32 +237,32 @@ public class TestABCase2 extends AbstractABCase
|
|||
@Test
|
||||
public void testCase2_5() throws Exception
|
||||
{
|
||||
// Disable Long Stacks from Parser (we know this test will throw an exception)
|
||||
enableStacks(Parser.class,false);
|
||||
|
||||
byte payload[] = new byte[126]; // intentionally too big
|
||||
Arrays.fill(payload,(byte)'5');
|
||||
|
||||
List<WebSocketFrame> send = new ArrayList<>();
|
||||
// trick websocket frame into making extra large payload for ping
|
||||
send.add(WebSocketFrame.binary(payload).setOpCode(OpCode.PING));
|
||||
send.add(new CloseInfo(StatusCode.NORMAL,"Test 2.5").asFrame());
|
||||
|
||||
List<WebSocketFrame> expect = new ArrayList<>();
|
||||
expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
|
||||
|
||||
Fuzzer fuzzer = new Fuzzer(this);
|
||||
try
|
||||
try(StacklessLogging scope = new StacklessLogging(Parser.class))
|
||||
{
|
||||
fuzzer.connect();
|
||||
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||
fuzzer.send(send);
|
||||
fuzzer.expect(expect);
|
||||
}
|
||||
finally
|
||||
{
|
||||
enableStacks(Parser.class,true);
|
||||
fuzzer.close();
|
||||
byte payload[] = new byte[126]; // intentionally too big
|
||||
Arrays.fill(payload,(byte)'5');
|
||||
|
||||
List<WebSocketFrame> send = new ArrayList<>();
|
||||
// trick websocket frame into making extra large payload for ping
|
||||
send.add(WebSocketFrame.binary(payload).setOpCode(OpCode.PING));
|
||||
send.add(new CloseInfo(StatusCode.NORMAL,"Test 2.5").asFrame());
|
||||
|
||||
List<WebSocketFrame> expect = new ArrayList<>();
|
||||
expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
|
||||
|
||||
Fuzzer fuzzer = new Fuzzer(this);
|
||||
try
|
||||
{
|
||||
fuzzer.connect();
|
||||
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||
fuzzer.send(send);
|
||||
fuzzer.expect(expect);
|
||||
fuzzer.expectServerDisconnect(Fuzzer.DisconnectMode.CLEAN);
|
||||
}
|
||||
finally
|
||||
{
|
||||
fuzzer.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ import org.eclipse.jetty.toolchain.test.annotation.Slow;
|
|||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.log.StacklessLogging;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.common.OpCode;
|
||||
|
@ -358,54 +359,55 @@ public class TestABCase6 extends AbstractABCase
|
|||
public void testCase6_4_3() throws Exception
|
||||
{
|
||||
// Disable Long Stacks from Parser (we know this test will throw an exception)
|
||||
enableStacks(Parser.class,false);
|
||||
|
||||
ByteBuffer payload = ByteBuffer.allocate(64);
|
||||
BufferUtil.clearToFill(payload);
|
||||
payload.put(TypeUtil.fromHexString("cebae1bdb9cf83cebcceb5")); // good
|
||||
payload.put(TypeUtil.fromHexString("f4908080")); // INVALID
|
||||
payload.put(TypeUtil.fromHexString("656469746564")); // good
|
||||
BufferUtil.flipToFlush(payload,0);
|
||||
|
||||
List<WebSocketFrame> send = new ArrayList<>();
|
||||
send.add(new WebSocketFrame(OpCode.TEXT).setPayload(payload));
|
||||
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||
|
||||
List<WebSocketFrame> expect = new ArrayList<>();
|
||||
expect.add(new CloseInfo(StatusCode.BAD_PAYLOAD).asFrame());
|
||||
|
||||
Fuzzer fuzzer = new Fuzzer(this);
|
||||
try
|
||||
try(StacklessLogging scope = new StacklessLogging(Parser.class))
|
||||
{
|
||||
fuzzer.connect();
|
||||
ByteBuffer payload = ByteBuffer.allocate(64);
|
||||
BufferUtil.clearToFill(payload);
|
||||
payload.put(TypeUtil.fromHexString("cebae1bdb9cf83cebcceb5")); // good
|
||||
payload.put(TypeUtil.fromHexString("f4908080")); // INVALID
|
||||
payload.put(TypeUtil.fromHexString("656469746564")); // good
|
||||
BufferUtil.flipToFlush(payload,0);
|
||||
|
||||
ByteBuffer net = fuzzer.asNetworkBuffer(send);
|
||||
List<WebSocketFrame> send = new ArrayList<>();
|
||||
send.add(new WebSocketFrame(OpCode.TEXT).setPayload(payload));
|
||||
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||
|
||||
int splits[] =
|
||||
{ 17, 21, net.limit() };
|
||||
List<WebSocketFrame> expect = new ArrayList<>();
|
||||
expect.add(new CloseInfo(StatusCode.BAD_PAYLOAD).asFrame());
|
||||
|
||||
ByteBuffer part1 = net.slice(); // Header + good UTF
|
||||
part1.limit(splits[0]);
|
||||
ByteBuffer part2 = net.slice(); // invalid UTF
|
||||
part2.position(splits[0]);
|
||||
part2.limit(splits[1]);
|
||||
ByteBuffer part3 = net.slice(); // good UTF
|
||||
part3.position(splits[1]);
|
||||
part3.limit(splits[2]);
|
||||
Fuzzer fuzzer = new Fuzzer(this);
|
||||
try
|
||||
{
|
||||
fuzzer.connect();
|
||||
|
||||
fuzzer.send(part1); // the header + good utf
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
fuzzer.send(part2); // the bad UTF
|
||||
ByteBuffer net = fuzzer.asNetworkBuffer(send);
|
||||
|
||||
fuzzer.expect(expect);
|
||||
int splits[] =
|
||||
{ 17, 21, net.limit() };
|
||||
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
fuzzer.sendExpectingIOException(part3); // the rest (shouldn't work)
|
||||
}
|
||||
finally
|
||||
{
|
||||
enableStacks(Parser.class,true);
|
||||
fuzzer.close();
|
||||
ByteBuffer part1 = net.slice(); // Header + good UTF
|
||||
part1.limit(splits[0]);
|
||||
ByteBuffer part2 = net.slice(); // invalid UTF
|
||||
part2.position(splits[0]);
|
||||
part2.limit(splits[1]);
|
||||
ByteBuffer part3 = net.slice(); // good UTF
|
||||
part3.position(splits[1]);
|
||||
part3.limit(splits[2]);
|
||||
|
||||
fuzzer.send(part1); // the header + good utf
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
fuzzer.send(part2); // the bad UTF
|
||||
|
||||
fuzzer.expect(expect);
|
||||
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
fuzzer.send(part3); // the rest (shouldn't work)
|
||||
fuzzer.expectServerDisconnect(Fuzzer.DisconnectMode.UNCLEAN);
|
||||
}
|
||||
finally
|
||||
{
|
||||
fuzzer.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -168,7 +168,7 @@ public class TestABCase6_BadUTF extends AbstractABCase
|
|||
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||
fuzzer.send(send);
|
||||
fuzzer.expect(expect);
|
||||
fuzzer.expectServerClose(Fuzzer.NOT_CLEAN_CLOSE);
|
||||
fuzzer.expectServerDisconnect(Fuzzer.DisconnectMode.UNCLEAN);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
@ -29,6 +29,7 @@ import java.net.InetAddress;
|
|||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
@ -124,10 +125,8 @@ public class BlockheadClient implements IncomingFrames, OutgoingFrames, Connecti
|
|||
{
|
||||
Assert.assertThat("Websocket URI scheme",destWebsocketURI.getScheme(),anyOf(is("ws"),is("wss")));
|
||||
this.destWebsocketURI = destWebsocketURI;
|
||||
String scheme = "http";
|
||||
if (destWebsocketURI.getScheme().equals("wss"))
|
||||
{
|
||||
scheme = "https";
|
||||
throw new RuntimeException("Sorry, BlockheadClient does not support SSL");
|
||||
}
|
||||
this.destHttpURI = WSURI.toHttp(destWebsocketURI);
|
||||
|
@ -414,7 +413,8 @@ public class BlockheadClient implements IncomingFrames, OutgoingFrames, Connecti
|
|||
switch (state)
|
||||
{
|
||||
case CLOSED:
|
||||
this.disconnect();
|
||||
// Per Spec, client should not initiate disconnect on its own
|
||||
// this.disconnect();
|
||||
break;
|
||||
case CLOSING:
|
||||
if (ioState.wasRemoteCloseInitiated())
|
||||
|
@ -464,6 +464,36 @@ public class BlockheadClient implements IncomingFrames, OutgoingFrames, Connecti
|
|||
}
|
||||
}
|
||||
|
||||
public void expectServerDisconnect()
|
||||
{
|
||||
if (eof)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
int len = in.read();
|
||||
if (len == (-1))
|
||||
{
|
||||
// we are disconnected
|
||||
eof = true;
|
||||
return;
|
||||
}
|
||||
|
||||
Assert.assertThat("Expecting no data and proper socket disconnect (issued from server)",len,is(-1));
|
||||
}
|
||||
catch (SocketTimeoutException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
Assert.fail("Expected a server initiated disconnect, instead the read timed out");
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
// acceptable path
|
||||
}
|
||||
}
|
||||
|
||||
public int read(ByteBuffer buf) throws IOException
|
||||
{
|
||||
if (eof)
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.util.concurrent.CountDownLatch;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketAdapter;
|
||||
|
||||
public class CaptureSocket extends WebSocketAdapter
|
||||
|
@ -45,12 +46,10 @@ public class CaptureSocket extends WebSocketAdapter
|
|||
getSession().close();
|
||||
}
|
||||
|
||||
public void onClose(int closeCode, String message)
|
||||
{
|
||||
}
|
||||
|
||||
public void onOpen(Connection connection)
|
||||
@Override
|
||||
public void onWebSocketConnect(Session sess)
|
||||
{
|
||||
super.onWebSocketConnect(sess);
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue