diff --git a/Jenkinsfile b/Jenkinsfile index e7b939fc3f6..a36eb86171e 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -20,7 +20,9 @@ node { { stage 'Compile' withEnv(mvnEnv) { - sh "mvn -B clean install -Dtest=None" + timeout(15) { + sh "mvn -B clean install -Dtest=None" + } } } catch(Exception e) { notifyBuild("Compile Failure") @@ -31,7 +33,9 @@ node { { stage 'Javadoc' withEnv(mvnEnv) { - sh "mvn -B javadoc:javadoc" + timeout(15) { + sh "mvn -B javadoc:javadoc" + } } } catch(Exception e) { notifyBuild("Javadoc Failure") @@ -41,8 +45,8 @@ node { try { stage 'Test' - timeout(60) { - withEnv(mvnEnv) { + withEnv(mvnEnv) { + timeout(60) { // Run test phase / ignore test failures sh "mvn -B install -Dmaven.test.failure.ignore=true" // Report failures in the jenkins UI diff --git a/VERSION.txt b/VERSION.txt index a61b8fb2c63..140808f494d 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1,5 +1,41 @@ jetty-9.4.0-SNAPSHOT +jetty-9.4.0.RC0 - 15 September 2016 + + 131 Improve Connector Statistic names and values + + 572 Don't reject HTTP/2 requests without body in low threads mode + + 725 Provide a private way to report security issues + + 731 Update modules in Jetty 9.4 + + 806 Jetty HttpClient authentication - missing any realm option + + 844 Implement a Thread Limit Handler + + 845 Improve blocking IO for data rate limiting. + + 851 MBeanContainer no longer unregisters MBeans when "stopped" + + 854 If container.destroy() is called, calling container.start() again should + throw an IllegalStateException + + 855 JMXify MBeanContainer + + 856 Add server/port and auth configuration for mongo sessions + + 860 Only TLS 1.2 Supported + + 868 ClassLoader leak with Jetty and Karaf - static instances of + java.lang.Throwable + + 870 TLS protocol exclusion broken for SslContextFactory(String) + + 880 Refactor jetty-http's HostPortHttpField logic into new jetty-util class + + 882 Add IPv6 support to IPAddressMap in jetty-util + + 889 ConstantThrowable.name can be removed + + 890 Review MappedByteBufferPool + + 894 When adding servless class, preserve Class instead of going through + String + + 897 Remove GzipHandler interceptor when out of scope + + 898 GzipHandler adds multiple Vary header + + 899 PathFinderTest fails in jetty-9.2.x + + 902 Expect: 100-Continue does not work with HTTP/2 + + 906 Expose jetty juli log for jasper in osgi + + 909 Path and Domain not properly matched in addCookie() + + 911 Request.getRequestURI() gets decoded after startAsync(req, resp) is + invoked + + 913 Unprotected debug in WebAppClassLoader + + 914 Regularize the naming of the session configuration properties + + 922 Implements methods Connection.getBytes[In|Out]() + + 931 Update gcloud datastore to 0.3.0 + jetty-9.4.0.M1 - 15 August 2016 + 185 Implement RFC 7239 (Forwarded header) + 213 jetty.osgi.boot requires Server services registered before @@ -7,7 +43,7 @@ jetty-9.4.0.M1 - 15 August 2016 + 282 When warning about conflicting servlet mappings, detail where each mapping comes from + 306 Merge jetty-parent into jetty-project - + 388 Add methods to send text frames with pre-encoded strings. + + 388 Add methods to send text frames with pre-encoded strings + 425 Incorrect @ServerEndpoint Encoder/Decoder lifecycle + 487 JDK 9 build compatibility + 515 Alternate start modules @@ -19,9 +55,9 @@ jetty-9.4.0.M1 - 15 August 2016 + 623 Add --gzip suffix to 304 responses with ETAGs + 624 AsyncContext.onCompleted called twice + 627 Use only start.ini or start.d, not both - + 628 IOException: Unable to open root Jar file ... + + 628 IOException: Unable to open root Jar file .. MetaInfConfiguration.getTlds(MetaInfConfiguration.java:406) with Spring boot - loader + WebAppContext + non-expanded war + loader + WebAppContext + non-expanded war + 632 JMX tests rely on fixed port + 638 ConnectHandler responses should have Content-Length + 639 ServerContainer stores WebSocket sessions twice @@ -92,7 +128,7 @@ jetty-9.4.0.M1 - 15 August 2016 + 786 Buffering Response Handler + 788 Attempting to activate a module that is already enabled + 790 AsyncContentListener semantic broken with HTTP/2 transport - + 792 [HTTP/2] Socket seems to be not closed completely + + 792 HTTP/2] Socket seems to be not closed completely + 797 MimeTypes resource loading incorrect on OSGi + 798 async IO Write closed race + 802 Warning for --add-to-startd is not complete in 9.4.x @@ -189,6 +225,68 @@ jetty-9.4.0.M0 - 03 June 2016 + 609 ignore failing test + 610 Ignore failing test +jetty-9.3.13.M0 - 30 September 2016 + + 277 Proxy servlet does not handle HTTP status 100 correctly + + 870 TLS protocol exclusion broken for SslContextFactory(String) + + 915 The jetty-maven-plugin:stop goal doesn't stop everything completely + + 918 Support certificates hot reload + + 930 Add module instructions to SSL section + + 943 Docs: Error in 'Embedding Jetty' page - example 'FileServer' + + 948 9.4.0.RC0 jetty-distribution invalid config etc/jetty-http2c.xml + + 955 Response listeners not invoked when using Connection.send() + + 959 CompleteListener invoked twice for HTTP/2 transport and response content + + 960 Async I/O spin when reading early EOF + + 965 Link from High Load docs to Garbage Collection Tuning is broken + + 966 Remove usages of ConcurrentArrayQueue + +jetty-9.3.12.v20160915 - 15 September 2016 + + 56 Fix authn issues in LdapLoginModule + + 131 Improve Connector Statistic names and values + + 185 Implement RFC 7239 (Forwarded header) + + 700 Bundle org.eclipse.jetty.http.spi not available via p2 repository + + 725 Provide a private way to report security issues + + 752 Implement support for HTTP2 SETTINGS_MAX_HEADER_LIST_SIZE + + 759 Ensure wrapped Responses will close and commit outputstream or writer + + 780 The moved websocket PathSpec is incompatible with cometd 3.0.x + + 783 Report name of broken jar file + + 784 JSP Session updated before sendRedirect() lose their information + + 786 Buffering Response Handler + + 790 AsyncContentListener semantic broken with HTTP/2 transport + + 792 [HTTP/2] Socket seems to be not closed completely + + 797 MimeTypes resource loading incorrect on OSGi + + 798 async IO Write closed race + + 804 setting default Url Encoding broken in Jetty >= 9.3 + + 806 Jetty HttpClient authentication - missing any realm option + + 817 NPE in jndi Resource + + 826 Better default for HTTP/2's max concurrent streams + + 827 HTTPClient fails connecting to HTTPS host through an HTTP proxy + w/authentication + + 830 Test webapp not properly copied to demo-base + + 832 ServerWithJNDI example uses wrong webapp + + 841 support reset in buffering interceptors + + 844 Implement a Thread Limit Handler + + 845 Improve blocking IO for data rate limiting. + + 851 MBeanContainer no longer unregisters MBeans when "stopped" + + 854 If container.destroy() is called, calling container.start() again should + throw an IllegalStateException + + 855 JMXify MBeanContainer + + 860 Only TLS 1.2 Supported + + 868 ClassLoader leak with Jetty and Karaf - static instances of + java.lang.Throwable + + 880 Refactor jetty-http's HostPortHttpField logic into new jetty-util class + + 882 Add IPv6 support to IPAddressMap in jetty-util + + 889 ConstantThrowable.name can be removed + + 894 When adding servless class, preserve Class instead of going through + String + + 897 Remove GzipHandler interceptor when out of scope + + 898 GzipHandler adds multiple Vary header + + 902 Expect: 100-Continue does not work with HTTP/2 + + 909 Path and Domain not properly matched in addCookie() + + 911 Request.getRequestURI() gets decoded after startAsync(req, resp) is + invoked + + 913 Unprotected debug in WebAppClassLoader + + 922 Implements methods Connection.getBytes[In|Out]() + jetty-9.3.11.v20160721 - 21 July 2016 + 230 customize Content-Type in ErrorHandler's default error page + 592 Support no-value Host header in HttpParser @@ -245,6 +343,19 @@ jetty-9.3.11.v20160721 - 21 July 2016 + 755 NPE in HttpChannelOverHTTP2.requestContent() + 756 Filter problematic headers from CGI and FastCGIProxy +jetty-9.2.19.v20160908 - 08 September 2016 + + 817 NPE in jndi Resource + + 830 Test webapp not properly copied to demo-base + + 832 ServerWithJNDI example uses wrong webapp + + 851 MBeanContainer no longer unregisters MBeans when "stopped" + + 868 ClassLoader leak with Jetty and Karaf - static instances of + java.lang.Throwable + + 880 Refactor jetty-http's HostPortHttpField logic into new jetty-util class + + 882 Add IPv6 support to IPAddressMap in jetty-util + + 894 When adding servless class, preserve Class instead of going through + String + + 899 PathFinderTest fails in jetty-9.2.x + jetty-9.2.18.v20160721 - 21 July 2016 + 425 Incorrect @ServerEndpoint Encoder/Decoder lifecycle + 649 LDAPLoginModule should disallow blank username and password @@ -264,7 +375,7 @@ jetty-9.3.11.M0 - 22 June 2016 + 661 JsrExtension is missing hashCode() and equals() jetty-9.3.10.v20160621 - 21 June 2016 - + 388 Add methods to send text frames with pre-encoded strings. + + 388 Add methods to send text frames with pre-encoded strings + 605 Guard concurrent calls to WebSocketSession.close() + 608 reset encoding set from content type? + 609 websocket ClientCloseTest testServerNoCloseHandshake is failing @@ -274,7 +385,7 @@ jetty-9.3.10.v20160621 - 21 June 2016 session.maxInactiveInterval + 623 Add --gzip suffix to 304 responses with ETAGs + 624 AsyncContext.onCompleted called twice - + 628 IOException: Unable to open root Jar file ... + + 628 IOException: Unable to open root Jar file .. MetaInfConfiguration.getTlds(MetaInfConfiguration.java:406) with Spring boot loader + WebAppContext + non-expanded war + 632 JMX tests rely on fixed port @@ -339,7 +450,7 @@ jetty-9.2.16.v20160414 - 14 April 2016 + 365 Potential connection leakage in case of aborted request + 367 Build downloads from git.eclipse.org + 371 jasper dependencies are outdated in 9.2.x - + 377 HttpClient - No supported cipher suites leads to stuck requests. + + 377 HttpClient - No supported cipher suites leads to stuck requests + 418 Javax websocket server impl does not expose all required services as OSGi capabilities + 424 Jetty impl. of Websocket ServerEndpointConfig.Configurator lifecycle out @@ -376,7 +487,7 @@ jetty-9.3.9.M1 - 11 April 2016 failure listener + 451 RFC2616 Compliance mode should support empty headers + 453 Change logging of setting session maxInactiveInterval to DEBUG from WARN - + 454 DoSFilter does not send an error status code when closing a connection, + + 454 DoSFilter does not send an error status code when closing a connection because of timeout + 458 Improve Quality list handling + 467 Compact // rule @@ -3051,9 +3162,11 @@ jetty-7.6.10.v20130312 - 12 March 2013 reason string jetty-9.0.0.RC2 - 24 February 2013 - + Fix etc/jetty.xml TimerScheduler typo that is preventing normal startup - + Fix etc/jetty-https.xml ExcludeCipherSuites typo that prevents SSL startup - + Fix websocket memory use + + fix etc/jetty.xml timerscheduler typo that is preventing normal startu Fix + etc/jetty.xml TimerScheduler typo that is preventing normal startup + + fix etc/jetty-https.xml excludeciphersuites typo that prevents ssl sta Fix + etc/jetty-https.xml ExcludeCipherSuites typo that prevents SSL startup + + fix websocket memory use Fix websocket memory use jetty-9.0.0.RC1 - 22 February 2013 + 227244 Remove import of backport-util-concurrent Arrays class @@ -3523,11 +3636,13 @@ jetty-9.0.0.M0 - 21 September 2012 jetty-8.1.7.v20120910 - 10 September 2012 + 388895 Update dependencies for jetty-jndi - + fix busy logging statement re: sessions + + fix busy logging statement re: sessions fix busy logging statement re: + sessions jetty-7.6.7.v20120910 - 10 September 2012 + 388895 Update dependencies for jetty-jndi - + fix busy logging statement re: sessions + + fix busy logging statement re: sessions fix busy logging statement re: + sessions jetty-8.1.6.v20120903 - 03 September 2012 + 347130 Empty getResourcePaths due to ZipFileClosedException @@ -3811,7 +3926,7 @@ jetty-8.1.2.v20120308 - 08 March 2012 + 373603 NullPointer in WebServletAnnotation + JETTY-1409 GzipFilter will double-compress application/x-gzip content + JETTY-1489 WebAppProvider attempts to deploy .svn folder - + JETTY-1494 + + jetty-1494 JETTY-1494 jetty-7.6.2.v20120308 - 08 March 2012 + 370387 SafariWebsocketDraft0Test failure during build @@ -3832,7 +3947,7 @@ jetty-7.6.2.v20120308 - 08 March 2012 validating turned on fixed + JETTY-1409 GzipFilter will double-compress application/x-gzip content + JETTY-1489 WebAppProvider attempts to deploy .svn folder - + JETTY-1494 + + jetty-1494 JETTY-1494 jetty-8.1.1.v20120215 - 15 February 2012 + 369121 simplified test @@ -4126,7 +4241,8 @@ jetty-7.6.0.RC0 - 29 November 2011 result in close rather than a shutdown output. + 364657 Support HTTP only cookies from standard API + JETTY-1442 add _hostHeader setter for ProxyRule - + Refactored NIO layer for better half close handling + + refactored nio layer for better half close handling Refactored NIO layer for + better half close handling jetty-8.0.4.v20111024 - 24 October 2011 + 358263 JDBCSessionIdManager add setDatasource(DataSource) method @@ -4337,15 +4453,15 @@ jetty-7.5.0.RC1 - 19 August 2011 jetty-8.0.0.RC0 - 16 August 2011 + 352565 cookie httponly flag ignored + 353285 ServletSecurity annotation ignored - + Enable annotations by default - + Merge from jetty-7.4.3 + + enable annotations by default Enable annotations by default + + merge from jetty-7.4.3 Merge from jetty-7.4.3 jetty-8.0.0.M3 - 27 May 2011 + 324505 Implement API login + 335500 request.getParts() throws a NullPointerException + 343472 isUserInRole does not prevent subsequent login call + 346180 jsp-2.2 support - + Updated to jetty-7.4.2.v20110526 + + updated to jetty-7.4.2.v20110526 Updated to jetty-7.4.2.v20110526 jetty-7.5.0.RC0 - 15 August 2011 + 298502 Handle 200 Connect responses with no content-length @@ -4487,7 +4603,8 @@ jetty-7.4.0.v20110414 + 342504 Scanner Listener + 342700 refine websocket API for anticipated changes + JETTY-1362 Set root cause of UnavailableException - + Various test harness cleanups to avoid random failures + + various test harness cleanups to avoid random failures Various test harness + cleanups to avoid random failures jetty-7.4.0.RC0 + 324110 Added test harnesses for merging of QueryStrings @@ -4526,8 +4643,9 @@ jetty-7.4.0.RC0 + 341992 Overlayed context deployer + JETTY-1245 Pooled Buffers implementation + JETTY-1354 Added jetty-nested - + Added extra session removal test - + Ensure generated fragment names are unique + + added extra session removal test Added extra session removal test + + ensure generated fragment names are unique Ensure generated fragment names + are unique jetty-8.0.0.M2 - 16 November 2010 + 320073 Reconsile configuration mechanism @@ -4547,7 +4665,7 @@ jetty-8.0.0.M2 - 16 November 2010 + 330208 Support new wording on servlet-mapping and filter-mapping merging from servlet3.0a + 330292 request.getParts() returns only one part when the name is the same - + Update to jetty-7.2.1.v20101111 + + update to jetty-7.2.1.v20101111 Update to jetty-7.2.1.v20101111 jetty-7.3.1.v20110307 - 07 March 2011 + 316382 Support a more strict SSL option with certificates @@ -4775,9 +4893,10 @@ jetty-7.2.0.RC0 - 01 October 2010 default + JETTY-1281 Create new session after authentication + JETTY-1283 JSONPojoConvertorFactory can turn off fromJSON - + Added ignore to Logger interface - + Fix jetty-plus.xml for new configuration names - + Improved debug dump + + added ignore to logger interface Added ignore to Logger interface + + fix jetty-plus.xml for new configuration names Fix jetty-plus.xml for new + configuration names + + improved debug dump Improved debug dump jetty-7.1.6.v20100715 + 319519 Warn about duplicate configuration files @@ -4791,10 +4910,13 @@ jetty-8.0.0.M1 - 12 July 2010 + 306350 Ensure jars excluded by ordering are not scanned for annotations + JETTY-1224 Change jetty-8 merge rules for fragment descriptors and annotations - + Ensure in web.xml overrides relative in + + ensure in web.xml overrides relative in + Ensure in web.xml overrides relative in fragments - + Ensure empty implies exclusion of all fragments - + Ensure servlet-api jar class inheritance hierarchy is scanned + + ensure empty implies exclusion of all fragments Ensure + empty implies exclusion of all fragments + + ensure servlet-api jar class inheritance hierarchy is scanned Ensure + servlet-api jar class inheritance hierarchy is scanned jetty-7.1.5.v20100705 + 288194 Add blacklist/whitelist to ProxyServlet and ProxyHandler @@ -4820,7 +4942,7 @@ jetty-7.1.5.v20100705 + 318551 Optional uncheck Printwriter + 319060 Support web-bundles that are not expanded (bundle is zipped) + JETTY-1237 Save local/remote address to be available after close - + Update ecj to 3.6 Helios release drop + + update ecj to 3.6 helios release drop Update ecj to 3.6 Helios release drop jetty-6.1.25 - 26 July 2010 + 320264 Removed duplicate mime.property entries @@ -4831,9 +4953,10 @@ jetty-6.1.25 - 26 July 2010 + JETTY-1226 javax.activation needs to be listed in the system classes + JETTY-1237 Remember local/remote details of endpoint + JETTY-1251 protected against closed selector - + COMETD-112 if two threads create the same channel, then create events may + + cometd-112 if two threads create the same channel, then create events + COMETD-112 if two threads create the same channel, then create events may occur after subscribe events - + Jetty-6 is now in maintenance mode. + + jetty-6 is now in maintenance mode. Jetty-6 is now in maintenance mode. jetty-7.1.4.v20100610 + 292326 Stop continuations if server is stopped @@ -4882,7 +5005,8 @@ jetty-7.1.2.v20100523 + 313278 Implement octet ranges in IPAccessHandler + 313336 secure websockets + 314009 updated README.txt - + Update links to jetty website and wiki on test webapp + + update links to jetty website and wiki on test webapp Update links to jetty + website and wiki on test webapp jetty-7.1.1.v20100517 + 302344 Make the list of available contexts if root context is not configured @@ -4960,11 +5084,15 @@ jetty-7.1.0.RC0 - 27 April 2010 + JETTY-1202 Use platform default algorithm for SecureRandom + JETTY-1212 handle long content lengths + JETTY-1214 avoid ISE when scavenging invalid session - + Add AnnotationConfiguration to jetty-plus.xml - + Add NPE protection to ContainerInitializerConfiguration - + Fix jetty-plus.xml reference to addLifeCycle - + Merged 7.0.2.v20100331 - + Temporarily remove jetty-osgi module to clarify jsp version compatibility + + add annotationconfiguration to jetty-plus.xml Add AnnotationConfiguration to + jetty-plus.xml + + add npe protection to containerinitializerconfiguration Add NPE protection + to ContainerInitializerConfiguration + + fix jetty-plus.xml reference to addlifecycle Fix jetty-plus.xml reference to + addLifeCycle + + merged 7.0.2.v20100331 Merged 7.0.2.v20100331 + + temporarily remove jetty-osgi module to clarify jsp version compatibil + Temporarily remove jetty-osgi module to clarify jsp version compatibility jetty-7.0.2.v20100331 - 31 March 2010 + 297552 Don't call Continuation timeouts from acceptor tick @@ -4975,9 +5103,12 @@ jetty-7.0.2.v20100331 - 31 March 2010 + 306880 Support for UPGRADE in HttpClient + 306884 Suspend with timeout <=0 never expires + 307589 updated servlet 3.0 continuations for final API - + Allow Configuration array to be set on Server instance for all web apps - + Ensure webapps with no WEB-INF don't scan WEB-INF/lib - + Take excess logging statements out of startup + + allow configuration array to be set on server instance for all web app Allow + Configuration array to be set on Server instance for all web apps + + ensure webapps with no web-inf don't scan web-inf/lib Ensure webapps with no + WEB-INF don't scan WEB-INF/lib + + take excess logging statements out of startup Take excess logging statements + out of startup jetty-6.1.24 - 21 April 2010 + 308925 Protect the test webapp from remote access @@ -4985,11 +5116,14 @@ jetty-6.1.24 - 21 April 2010 + JETTY-1198 reset idle timeout on request body chunks + JETTY-1200 SSL NIO Endpoint wraps non NIO buffers + JETTY-1211 SetUID loadlibrary name and debug - + COMETD-100 ClientImpl logs "null" as clientId - + COMETD-107 Reloading the application with reload extension does not fire + + cometd-100 clientimpl logs "null" as clientid COMETD-100 ClientImpl logs + "null" as clientId + + cometd-107 reloading the application with reload extension does not fi + COMETD-107 Reloading the application with reload extension does not fire /meta/connect handlers until long poll timeout expires - + COMETD-99 ClientImpl logs exceptions in listeners with "debug" level - + Upgraded to cometd 1.1.1 client + + cometd-99 clientimpl logs exceptions in listeners with "debug" level + COMETD-99 ClientImpl logs exceptions in listeners with "debug" level + + upgraded to cometd 1.1.1 client Upgraded to cometd 1.1.1 client jetty-6.1.23 - 02 April 2010 + 292800 ContextDeployer - recursive setting is undone by FilenameFilter @@ -5037,15 +5171,21 @@ jetty-6.1.23 - 02 April 2010 + JETTY-1202 Use platfrom default algorithm for SecureRandom + JETTY-1205 Memory leak in browser-to-client mapping + JETTY-1207 NPE protection in FormAuthenticator - + COMETD-28 Improved concurrency usage in Bayeux and channel handling - + COMETD-46 reset ContentExchange content on resend - + COMETD-58 Extension.rcv() return null causes NPE in + + cometd-28 improved concurrency usage in bayeux and channel handling + COMETD-28 Improved concurrency usage in Bayeux and channel handling + + cometd-46 reset contentexchange content on resend COMETD-46 reset + ContentExchange content on resend + + cometd-58 extension.rcv() return null causes npe in COMETD-58 + Extension.rcv() return null causes NPE in AbstractBayeux.PublishHandler.publish - + COMETD-59 AcknowledgeExtension does not handle null channel in Message - + COMETD-62 Delay add listeners until after client construction - + JSON parses NaN as null - + Remove references to old content in HttpClient client tests for www.sun.com - + Updated JSP to 2.1.v20091210 + + cometd-59 acknowledgeextension does not handle null channel in message + COMETD-59 AcknowledgeExtension does not handle null channel in Message + + cometd-62 delay add listeners until after client construction COMETD-62 + Delay add listeners until after client construction + + json parses nan as null JSON parses NaN as null + + remove references to old content in httpclient client tests for www.su + Remove references to old content in HttpClient client tests for www.sun.com + + updated jsp to 2.1.v20091210 Updated JSP to 2.1.v20091210 jetty-7.0.2.RC0 + 290765 Reset input for HttpExchange retry @@ -5105,15 +5245,17 @@ jetty-7.0.2.RC0 + JETTY-1184 shrink thread pool even with frequent small jobs + JETTY-1192 Fixed Digested POST + JETTY-1199 FindBugs cleanups - + Added IPAccessHandler - + COMETD-46 reset ContentExchange response content on resend - + JSON parses NaN as null - + Updated Servlet3Continuation to final 3.0.20100224 + + added ipaccesshandler Added IPAccessHandler + + cometd-46 reset contentexchange response content on resend COMETD-46 reset + ContentExchange response content on resend + + json parses nan as null JSON parses NaN as null + + updated servlet3continuation to final 3.0.20100224 Updated + Servlet3Continuation to final 3.0.20100224 jetty-8.0.0.M0 - 28 February 2010 - + Merged 7.0.1.v20091116 - + Updated servlet 3.0 spec 20100224 - + Updated to cometd 1.0.1 + + merged 7.0.1.v20091116 Merged 7.0.1.v20091116 + + updated servlet 3.0 spec 20100224 Updated servlet 3.0 spec 20100224 + + updated to cometd 1.0.1 Updated to cometd 1.0.1 jetty-7.0.1.v20091125 - 25 November 2009 + 274251 DefaultServlet supports exact match mode @@ -5151,16 +5293,23 @@ jetty-7.0.1.v20091125 - 25 November 2009 around + JETTY-1144 fixed multi-byte character overflow + JETTY-1148 Reset partially read request reader - + COMETD-34 Support Baeyux MBean - + CQ-3581 jetty OSGi contribution - + CVE-2009-3555 Prevent SSL renegotiate for SSL vulnerability - + Fixed client abort asocciation - + Fixed XSS issue in CookieDump demo servlet. - + Improved start.jar usage text for properties - + Moved centralized logging and verifier back to sandbox - + Promoted Jetty Centralized Logging from Sandbox - + Promoted Jetty WebApp Verifier from Sandbox - + Refactored continuation test harnessess + + cometd-34 support baeyux mbean COMETD-34 Support Baeyux MBean + + cq-3581 jetty osgi contribution CQ-3581 jetty OSGi contribution + + cve-2009-3555 prevent ssl renegotiate for ssl vulnerability CVE-2009-3555 + Prevent SSL renegotiate for SSL vulnerability + + fixed client abort asocciation Fixed client abort asocciation + + fixed xss issue in cookiedump demo servlet. Fixed XSS issue in CookieDump + demo servlet. + + improved start.jar usage text for properties Improved start.jar usage text + for properties + + moved centralized logging and verifier back to sandbox Moved centralized + logging and verifier back to sandbox + + promoted jetty centralized logging from sandbox Promoted Jetty Centralized + Logging from Sandbox + + promoted jetty webapp verifier from sandbox Promoted Jetty WebApp Verifier + from Sandbox + + refactored continuation test harnessess Refactored continuation test + harnessess jetty-7.0.0.v20091005 - 05 October 2009 + 291340 Race condition in onException() notifications @@ -5192,10 +5341,13 @@ jetty-6.1.21 - 22 September 2009 + JETTY-1113 IllegalStateException when adding servlet filters programmatically + JETTY-1114 Unsynchronize webapp classloader getResource - + Fix DefaultServletTest for windows - + Include tmp directory sweeper in build - + Streamline jetty-jboss build, update sar to QueuedThreadPool - + Update Jetty implementation of com.sun.net.httpserver.* + + fix defaultservlettest for windows Fix DefaultServletTest for windows + + include tmp directory sweeper in build Include tmp directory sweeper in + build + + streamline jetty-jboss build, update sar to queuedthreadpool Streamline + jetty-jboss build, update sar to QueuedThreadPool + + update jetty implementation of com.sun.net.httpserver.* Update Jetty + implementation of com.sun.net.httpserver.* jetty-7.0.0.RC6 - 21 September 2009 + 280723 Add non blocking statistics handler @@ -5234,10 +5386,12 @@ jetty-7.0.0.RC6 - 21 September 2009 + JETTY-1112 Response fails if header exceeds buffer size + JETTY-1113 IllegalStateException when adding servlet filters programmatically - + Copy VERSION.txt to distro - + Fixed XSS issue in CookieDump demo servlet. - + Remove printlns from jetty-plus - + Tweak DefaultServletTest under windows + + copy version.txt to distro Copy VERSION.txt to distro + + fixed xss issue in cookiedump demo servlet. Fixed XSS issue in CookieDump + demo servlet. + + remove printlns from jetty-plus Remove printlns from jetty-plus + + tweak defaultservlettest under windows Tweak DefaultServletTest under + windows jetty-6.1.20 - 27 August 2009 + 283513 Check endp.isOpen when blocking read @@ -5269,14 +5423,21 @@ jetty-6.1.20 - 27 August 2009 + JETTY-1086 Added UncheckedPrintWriter to avoid ignored EOFs + JETTY-1087 Chunked SSL non blocking input + JETTY-1098 Upgrade jsp to SJSAS-9_1_1-B60F-07_Jan_2009 - + Added DebugHandler - + Added getSubscriptions to cometd client - + Clarified cometd interval timeout and allow per client intervals - + COMETD-7 max latency config for lazy messages - + Made unSubscribeAll public on cometd client - + Removed clearing of queue in unSubscribeAll for cometd client - + Update Main.main method to call setWar - + Update test-jndi and test-annotation examples for atomikos 3.5.5 + + added debughandler Added DebugHandler + + added getsubscriptions to cometd client Added getSubscriptions to cometd + client + + clarified cometd interval timeout and allow per client intervals Clarified + cometd interval timeout and allow per client intervals + + cometd-7 max latency config for lazy messages COMETD-7 max latency config + for lazy messages + + made unsubscribeall public on cometd client Made unSubscribeAll public on + cometd client + + removed clearing of queue in unsubscribeall for cometd client Removed + clearing of queue in unSubscribeAll for cometd client + + update main.main method to call setwar Update Main.main method to call + setWar + + update test-jndi and test-annotation examples for atomikos 3.5.5 Update + test-jndi and test-annotation examples for atomikos 3.5.5 jetty-7.0.0.RC5 - 27 August 2009 + 286911 Clean out cache when recycling HTTP fields @@ -5330,7 +5491,7 @@ jetty-7.0.0.RC4 - 18 August 2009 + JETTY-1079 ResourceCollection.toString + JETTY-1080 Ignore files that would be extracted outside the destination directory when unpacking WARs - + Added discoverable start options + + added discoverable start options Added discoverable start options jetty-7.0.0.RC3 - 07 August 2009 + 277403 remove system properties @@ -5341,7 +5502,8 @@ jetty-7.0.0.RC3 - 07 August 2009 + 283513 Check endp.isOpen when blocking read + 285697 extract parameters if dispatch has query + JETTY-1074 JMX thread manipulation - + Improved deferred authentication handling + + improved deferred authentication handling Improved deferred authentication + handling jetty-7.0.0.RC2 - 29 June 2009 + 283375 improved extensibility of SSL connectors @@ -5351,11 +5513,15 @@ jetty-7.0.0.RC2 - 29 June 2009 + 284510 Enhance jetty-start for diagnosis and unit testing + 284981 Implement a cross-origin filter + 285006 fix AbstractConnector NPE during shutdown - + Added DebugHandler - + Added JavaUtilLog for Jetty logging to java.util.logging framework - + backport jetty-8 annotation parsing to jetty-7 - + Disassociate method on IdentityService - + Improved handling of overlays and resourceCollections + + added debughandler Added DebugHandler + + added javautillog for jetty logging to java.util.logging framework Added + JavaUtilLog for Jetty logging to java.util.logging framework + + backport jetty-8 annotation parsing to jetty-7 backport jetty-8 annotation + parsing to jetty-7 + + disassociate method on identityservice Disassociate method on + IdentityService + + improved handling of overlays and resourcecollections Improved handling of + overlays and resourceCollections jetty-7.0.0.RC1 - 15 June 2009 + 283344 Startup on windows is broken @@ -5391,14 +5557,20 @@ jetty-7.0.0.M3 - 20 June 2009 + 279725 Support 100 and 102 expectations + 280707 client.HttpConnection does not catch and handle non-IOExceptions + 281470 Handle the case where request.PathInfo() should be "/*" - + Added ContinuationThrowable - + added WebAppContext.setConfigurationDiscovered for servlet 3.0 features - + fixed race with expired async listeners - + Numerous cleanups from static code analysis - + Portable continuations for jetty6 and servlet3 - + Refactored AbstractBuffers to HttpBuffers for performance - + refactored configuration mechanism - + Refactored continuations to only support response wrapping + + added continuationthrowable Added ContinuationThrowable + + added webappcontext.setconfigurationdiscovered for servlet 3.0 feature added + WebAppContext.setConfigurationDiscovered for servlet 3.0 features + + fixed race with expired async listeners fixed race with expired async + listeners + + numerous cleanups from static code analysis Numerous cleanups from static + code analysis + + portable continuations for jetty6 and servlet3 Portable continuations for + jetty6 and servlet3 + + refactored abstractbuffers to httpbuffers for performance Refactored + AbstractBuffers to HttpBuffers for performance + + refactored configuration mechanism refactored configuration mechanism + + refactored continuations to only support response wrapping Refactored + continuations to only support response wrapping jetty-7.0.0.M2 - 18 May 2009 + 273767 Update to use geronimo annotations spec 1.1.1 @@ -5434,7 +5606,8 @@ jetty-6.1.18 - 16 May 2009 jetty-5.1.15 - 18 May 2009 + JETTY-418 synchronized load class + JETTY-1004 CERT VU402580 Canonical path handling includes ? in path segment - + Fixes for CERT438616-CERT237888-CERT21284 + + fixes for cert438616-cert237888-cert21284 Fixes for + CERT438616-CERT237888-CERT21284 jetty-6.1.17 - 30 April 2009 + JETTY-936 Make optional dispatching to welcome files as servlets @@ -5465,10 +5638,13 @@ jetty-7.0.0.M1 - 22 April 2009 + 273153 Test for Nested references in DispatchServlet + JETTY-695 Handler dump + JETTY-983 DefaultServlet generates accept-ranges for cached/gzip content - + Initial support for LoginService.logout - + Removed HTTPConnection specifics from connection dispatching - + Reworked authentication for deferred authentication - + Reworked JMX for new layout + + initial support for loginservice.logout Initial support for + LoginService.logout + + removed httpconnection specifics from connection dispatching Removed + HTTPConnection specifics from connection dispatching + + reworked authentication for deferred authentication Reworked authentication + for deferred authentication + + reworked jmx for new layout Reworked JMX for new layout jetty-6.1.16 - 01 April 2009 + JETTY-702 Create "jetty-tasks.xml" for the Ant plugin @@ -5582,8 +5758,8 @@ jetty-7.0.0.M0 - 27 March 2009 + JETTY-953 SSL keystore file input stream is not being closed directly + JETTY-956 SslSelectChannelConnector - password should be the default value of keyPassword if not specified - + moved to org.eclipse packages - + simplified HandlerContainer API + + moved to org.eclipse packages moved to org.eclipse packages + + simplified handlercontainer api simplified HandlerContainer API jetty-6.1.15 - 04 March 2009 + JETTY-923 BayeuxClient uses message pools to reduce memory footprint @@ -5635,7 +5811,8 @@ jetty-6.1.15.rc3 - 28 January 2009 jetty-6.1.15.rc2 - 23 January 2009 + JETTY-567 Delay in initial TLS Handshake With FireFox 3 beta5 and SslSelectChannelConnector - + adjustment to jetty-client assembly packaging + + adjustment to jetty-client assembly packaging adjustment to jetty-client + assembly packaging jetty-6.1.15.pre0 - 20 January 2009 + JETTY-600 Automated tests of WADI integration + upgrade to WADI 2.0 @@ -5902,7 +6079,8 @@ jetty-7.0.0pre3 - 06 August 2008 with byte value 0) + JETTY-675 ServletContext.getRealPath("") returns null instead of returning the root dir of the webapp - + Upgrade jsp 2.1 to SJSAS-9_1_02-B04-11_Apr_2008 + + upgrade jsp 2.1 to sjsas-9_1_02-b04-11_apr_2008 Upgrade jsp 2.1 to + SJSAS-9_1_02-B04-11_Apr_2008 jetty-6.1.12rc1 - 01 August 2008 + JETTY-319 Get unavailable exception and added startWithUnavailable option @@ -5953,7 +6131,8 @@ jetty-6.1.12rc1 - 01 August 2008 + JETTY-667 HttpClient handles chunked content + JETTY-669 Http methods other than GET and POST should not have error page content - + Upgrade jsp 2.1 to SJSAS-9_1_02-B04-11_Apr_2008 + + upgrade jsp 2.1 to sjsas-9_1_02-b04-11_apr_2008 Upgrade jsp 2.1 to + SJSAS-9_1_02-B04-11_Apr_2008 jetty-7.0.0pre2 - 30 June 2008 + JETTY-336 413 error for header buffer full @@ -6017,7 +6196,7 @@ jetty-6.1.10 - 20 May 2008 + JETTY-566 allow for non-blocking behavior in jetty maven plugin + JETTY-572 unique cometd client ID + JETTY-579 osgi fixes with management and servlet resources - + Use QueuedThreadPool as default + + use queuedthreadpool as default Use QueuedThreadPool as default jetty-7.0.0pre1 - 03 May 2008 + JETTY-440 allow file name patterns for jsp compilation for jspc plugin @@ -6025,11 +6204,14 @@ jetty-7.0.0pre1 - 03 May 2008 + JETTY-558 optional handling of X-Forwarded-For/Host/Server + JETTY-559 ignore unsupported shutdownOutput + JETTY-566 allow for non-blocking behavior in jetty maven plugin - + address osgi bundling issue relating to build resources - + Allow annotations example to be built regularly, copy to contexts-available - + Improved suspend examples - + Make annotations example consistent with servlet 3.0 - + Refactor JNDI impl to simplify + + address osgi bundling issue relating to build resources address osgi + bundling issue relating to build resources + + allow annotations example to be built regularly, copy to contexts-avai Allow + annotations example to be built regularly, copy to contexts-available + + improved suspend examples Improved suspend examples + + make annotations example consistent with servlet 3.0 Make annotations + example consistent with servlet 3.0 + + refactor jndi impl to simplify Refactor JNDI impl to simplify jetty-7.0.0pre0 - 21 April 2008 + JETTY-282 Support manually-triggered reloading by maven plugin @@ -6069,17 +6251,25 @@ jetty-7.0.0pre0 - 21 April 2008 + JETTY-556 Encode all URI fragments + JETTY-557 Allow ServletContext.setAttribute before start + JETTY-560 Allow decoupling of jndi names in web.xml - + Added option to dispatch to suspended requests. - + BayeuxClient use a single connection for polling - + Delay 100 continues until getInputStream - + Ensure Jotm tx mgr can be found in jetty-env.xml - + HttpClient supports pipelined request - + Jetty-6.1.8 Changes - + Make javax.servlet.jsp optional osgi import for jetty module - + QueuedThreadPool default - + Refactor of Continuation towards servlet 3.0 proposal - + Renamed modules management and naming to jmx and jndi. - + RetryRequest exception now extends ThreadDeath + + added option to dispatch to suspended requests. Added option to dispatch to + suspended requests. + + bayeuxclient use a single connection for polling BayeuxClient use a single + connection for polling + + delay 100 continues until getinputstream Delay 100 continues until + getInputStream + + ensure jotm tx mgr can be found in jetty-env.xml Ensure Jotm tx mgr can be + found in jetty-env.xml + + httpclient supports pipelined request HttpClient supports pipelined request + + jetty-6.1.8 changes Jetty-6.1.8 Changes + + make javax.servlet.jsp optional osgi import for jetty module Make + javax.servlet.jsp optional osgi import for jetty module + + queuedthreadpool default QueuedThreadPool default + + refactor of continuation towards servlet 3.0 proposal Refactor of + Continuation towards servlet 3.0 proposal + + renamed modules management and naming to jmx and jndi. Renamed modules + management and naming to jmx and jndi. + + retryrequest exception now extends threaddeath RetryRequest exception now + extends ThreadDeath jetty-6.1.9 - 26 March 2008 + JETTY-399 update OpenRemoteServiceServlet to gwt 1.4 @@ -6094,8 +6284,10 @@ jetty-6.1.9 - 26 March 2008 + JETTY-535 Fixed Bayeux server side client memory leak + JETTY-538 test harness fix for windows + JETTY-541 Cometd per client timeouts - + Ensure Jotm tx mgr can be found in jetty-env.xml - + Make javax.servlet.jsp optional osgi import for jetty module + + ensure jotm tx mgr can be found in jetty-env.xml Ensure Jotm tx mgr can be + found in jetty-env.xml + + make javax.servlet.jsp optional osgi import for jetty module Make + javax.servlet.jsp optional osgi import for jetty module jetty-6.1.8 - 28 February 2008 + JETTY-350 log ssl errors on SslSocketConnector @@ -6118,25 +6310,33 @@ jetty-6.1.8 - 28 February 2008 + JETTY-513 Terracotta session replication does not work when the initial page on each server does not set any attributes + JETTY-515 Timer is missing scavenging Task in HashSessionManager - + Add "mvn jetty:stop" - + Added BayeuxService - + Added JSON.Convertor and non static JSON instances - + Added QueuedThreadPool - + add removeHandler(Handler) method to HandlerContainer interface - + AJP handles bad mod_jk methods - + Allow code ranges on ErrorPageErrorHandler - + allow sessions to be periodically persisted to disk - + Cookie support in BayeuxClient - + Fixed JSON negative numbers - + further Optimizations and improvements of Cometd - + grizzly fixed for posts - + Improved Bayeux API - + Improved Cometd timeout handling - + JSON unquotes / - + Long cache for JSON - + Optimizations and improvements of Cometd, more pooled objects - + Optimized QuotedStringTokenizer.quote() - + Remove duplicate commons-logging jars and include sslengine in jboss sar + + add "mvn jetty:stop" Add "mvn jetty:stop" + + added bayeuxservice Added BayeuxService + + added json.convertor and non static json instances Added JSON.Convertor and + non static JSON instances + + added queuedthreadpool Added QueuedThreadPool + + add removehandler(handler) method to handlercontainer interface add + removeHandler(Handler) method to HandlerContainer interface + + ajp handles bad mod_jk methods AJP handles bad mod_jk methods + + allow code ranges on errorpageerrorhandler Allow code ranges on + ErrorPageErrorHandler + + allow sessions to be periodically persisted to disk allow sessions to be + periodically persisted to disk + + cookie support in bayeuxclient Cookie support in BayeuxClient + + fixed json negative numbers Fixed JSON negative numbers + + further optimizations and improvements of cometd further Optimizations and + improvements of Cometd + + grizzly fixed for posts grizzly fixed for posts + + improved bayeux api Improved Bayeux API + + improved cometd timeout handling Improved Cometd timeout handling + + json unquotes / JSON unquotes / + + long cache for json Long cache for JSON + + optimizations and improvements of cometd, more pooled objects Optimizations + and improvements of Cometd, more pooled objects + + optimized quotedstringtokenizer.quote() Optimized + QuotedStringTokenizer.quote() + + remove duplicate commons-logging jars and include sslengine in jboss s + Remove duplicate commons-logging jars and include sslengine in jboss sar jetty-6.1.7 - 22 December 2007 + JETTY-386 CERT-553235 backout fix and replaced with @@ -6146,15 +6346,19 @@ jetty-6.1.7 - 22 December 2007 + JETTY-474 Fixed case sensitivity issue with HttpFields + JETTY-486 Improved jetty.sh script + JETTY-487 Handle empty chunked request - + Add "mvn jetty:stop" - + Added BayeuxService - + Added JSON.Convertor and non static JSON instances - + allow sessions to be periodically persisted to disk - + Cookie support in BayeuxClient - + grizzly fixed for posts + + add "mvn jetty:stop" Add "mvn jetty:stop" + + added bayeuxservice Added BayeuxService + + added json.convertor and non static json instances Added JSON.Convertor and + non static JSON instances + + allow sessions to be periodically persisted to disk allow sessions to be + periodically persisted to disk + + cookie support in bayeuxclient Cookie support in BayeuxClient + + grizzly fixed for posts grizzly fixed for posts + jetty-6.1 branch created from 6.1.6 and r593 of jetty-contrib trunk - + Optimizations and improvements of Cometd, more pooled objects - + Update java5 patch + jetty-6.1 branch created from 6.1.6 and r593 of jetty-contrib trunk + + optimizations and improvements of cometd, more pooled objects Optimizations + and improvements of Cometd, more pooled objects + + update java5 patch Update java5 patch jetty-6.1.6 - 18 November 2007 + JETTY-455 Optional cometd id @@ -6162,8 +6366,8 @@ jetty-6.1.6 - 18 November 2007 + JETTY-461 fixed cometd unknown channel + JETTY-464 typo in ErrorHandler + JETTY-465 System.exit() in constructor exception for MultiPartOutputStream - + rudimentary debian packaging - + updated grizzly connector to 1.6.1 + + rudimentary debian packaging rudimentary debian packaging + + updated grizzly connector to 1.6.1 updated grizzly connector to 1.6.1 jetty-6.1.6rc1 - 05 November 2007 + JETTY-388 Handle utf-16 and other multibyte non-utf-8 form content @@ -6180,16 +6384,21 @@ jetty-6.1.6rc1 - 05 November 2007 + JETTY-454 handle exceptions with themselves as root cause + JETTY-456 allow null keystore for osX + JETTY-457 AJP certificate chains - + Added configuration file for capturing stderr and stdout - + CERT VU#38616 handle single quotes in cookie names. - + Give bayeux timer name - + Give Terracotta session scavenger a name - + Housekeeping on poms - + Improved JSON parsing from Readers - + Jetty Eclipse Plugin 1.0.1: force copy of context file on redeploy - + Moved some impl classes from jsp-api-2.1 to jsp-2.1 - + Updated for dojo 1.0(rc) cometd - + Upgrade jsp 2.1 to SJSAS-9_1-B58G-FCS-08_Sept_2007 + + added configuration file for capturing stderr and stdout Added configuration + file for capturing stderr and stdout + + 38616 CERT VU#38616 handle single quotes in cookie names. + + give bayeux timer name Give bayeux timer name + + give terracotta session scavenger a name Give Terracotta session scavenger a + name + + housekeeping on poms Housekeeping on poms + + improved json parsing from readers Improved JSON parsing from Readers + + jetty eclipse plugin 1.0.1: force copy of context file on redeploy Jetty + Eclipse Plugin 1.0.1: force copy of context file on redeploy + + moved some impl classes from jsp-api-2.1 to jsp-2.1 Moved some impl classes + from jsp-api-2.1 to jsp-2.1 + + updated for dojo 1.0(rc) cometd Updated for dojo 1.0(rc) cometd + + upgrade jsp 2.1 to sjsas-9_1-b58g-fcs-08_sept_2007 Upgrade jsp 2.1 to + SJSAS-9_1-B58G-FCS-08_Sept_2007 jetty-6.1.6rc0 - 03 October 2007 + JETTY-259 SystemRoot set for windows CGI @@ -6210,44 +6419,68 @@ jetty-6.1.6rc0 - 03 October 2007 + JETTY-425 Handle duplicate stop calls better + JETTY-430 improved cometd logging + JETTY-431 HttpClient soTimeout - + Add ability to persist sessions with HashSessionManager - + Added ConcatServlet to combine javascript and css - + Added jetty.lib system property to start.config - + Added JPackage RPM support - + Added JSON.Convertable - + Adding setUsername,setGroupname to setuid and mavenizing native build - + Add jetty.host system property - + AJP13 Fix on chunked post - + Allow properties files on the XmlConfiguration command line. - + Allow scan interval to be set after Scanner started - + Avoid FULL exception in window between blockForOutput and remote close - + Cached user agents strings in the /org/mortbay/jetty/useragents resource - + CVE-2007-5615 Added protection for response splitting with bad headers. - + Ensure session is completed only when leaving context. - + Fix cached header optimization for extra characters - + Fix Host header for async client - + Fix patch for java5 to include cometd module - + Fix typo in async client onResponsetHeader method name - + Give deployment file Scanner threads a unique name - + Make default time format for RequestLog match NCSA default - + Make mx4j used only if runtime uses jdk<1.5 - + Moved Grizzly to contrib - + Prevent infinite loop on stopping with temp dir - + Removal of unneeded dependencies from management, maven-plugin, naming & + + add ability to persist sessions with hashsessionmanager Add ability to + persist sessions with HashSessionManager + + added concatservlet to combine javascript and css Added ConcatServlet to + combine javascript and css + + added jetty.lib system property to start.config Added jetty.lib system + property to start.config + + added jpackage rpm support Added JPackage RPM support + + added json.convertable Added JSON.Convertable + + adding setusername,setgroupname to setuid and mavenizing native build Adding + setUsername,setGroupname to setuid and mavenizing native build + + add jetty.host system property Add jetty.host system property + + ajp13 fix on chunked post AJP13 Fix on chunked post + + allow properties files on the xmlconfiguration command line. Allow + properties files on the XmlConfiguration command line. + + allow scan interval to be set after scanner started Allow scan interval to + be set after Scanner started + + avoid full exception in window between blockforoutput and remote close Avoid + FULL exception in window between blockForOutput and remote close + + cached user agents strings in the /org/mortbay/jetty/useragents resour + Cached user agents strings in the /org/mortbay/jetty/useragents resource + + cve-2007-5615 added protection for response splitting with bad headers + CVE-2007-5615 Added protection for response splitting with bad headers. + + ensure session is completed only when leaving context. Ensure session is + completed only when leaving context. + + fix cached header optimization for extra characters Fix cached header + optimization for extra characters + + fix host header for async client Fix Host header for async client + + fix patch for java5 to include cometd module Fix patch for java5 to include + cometd module + + fix typo in async client onresponsetheader method name Fix typo in async + client onResponsetHeader method name + + give deployment file scanner threads a unique name Give deployment file + Scanner threads a unique name + + make default time format for requestlog match ncsa default Make default time + format for RequestLog match NCSA default + + make mx4j used only if runtime uses jdk<1.5 Make mx4j used only if runtime + uses jdk<1.5 + + moved grizzly to contrib Moved Grizzly to contrib + + prevent infinite loop on stopping with temp dir Prevent infinite loop on + stopping with temp dir + + removal of unneeded dependencies from management, maven-plugin, naming + Removal of unneeded dependencies from management, maven-plugin, naming & plus poms - + SetUID option to support setgid - + Tweak OSGi manifests to remove unneeded imports - + Updated README, test index.html file and jetty-plus.xml file - + Update jasper2.1 to tag SJSAS-9_1-B58C-FCS-22_Aug_2007 - + Update terracotta to 2.4.1 and exclude ssl classes - + Use terracotta repo for build; make jetty a terracotta module - + UTF-8 for bayeux client + + setuid option to support setgid SetUID option to support setgid + + tweak osgi manifests to remove unneeded imports Tweak OSGi manifests to + remove unneeded imports + + updated readme, test index.html file and jetty-plus.xml file Updated README, + test index.html file and jetty-plus.xml file + + update jasper2.1 to tag sjsas-9_1-b58c-fcs-22_aug_2007 Update jasper2.1 to + tag SJSAS-9_1-B58C-FCS-22_Aug_2007 + + update terracotta to 2.4.1 and exclude ssl classes Update terracotta to + 2.4.1 and exclude ssl classes + + use terracotta repo for build; make jetty a terracotta module Use terracotta + repo for build; make jetty a terracotta module + + utf-8 for bayeux client UTF-8 for bayeux client jetty-6.1.5 - 19 July 2007 + JETTY-392 updated LikeJettyXml example - + Fixed GzipFilter for dispatchers - + Fixed reset of reason - + Upgrade to Jasper 2.1 tag SJSAS-9_1-B50G-BETA3-27_June_2007 + + fixed gzipfilter for dispatchers Fixed GzipFilter for dispatchers + + fixed reset of reason Fixed reset of reason + + upgrade to jasper 2.1 tag sjsas-9_1-b50g-beta3-27_june_2007 Upgrade to + Jasper 2.1 tag SJSAS-9_1-B50G-BETA3-27_June_2007 jetty-6.1.5rc0 - 15 July 0200 + JETTY-253 Improved graceful shutdown @@ -6261,26 +6494,38 @@ jetty-6.1.5rc0 - 15 July 0200 + JETTY-380 handle pipelines of more than 4 requests + JETTY-385 EncodeURL for new sessions from dispatch + JETTY-386 Allow // in file resources - + Added GzipFilter and UserAgentFilter - + Dispatch SslEngine expiry (non atomic) - + Improved Request log configuration options - + make jetty plus example webapps use ContextDeployer - + make OSGi manifests for jetty jars - + Make SLF4JLog impl public, add mbean descriptors - + Protect SslSelectChannelConnector from exceptions during close - + remove call to open connectors in jetty.xml - + SetUID option to only open connectors before setUID. - + SPR-3682 - dont hide forward attr in include. - + update links on website - + update terracotta configs for tc 2.4 stable1 - + update terracotta session clustering to terracotta 2.4 - + Upgrade to Jasper 2.1 tag SJSAS-9_1-B50G-BETA3-27_June_2007 + + added gzipfilter and useragentfilter Added GzipFilter and UserAgentFilter + + dispatch sslengine expiry (non atomic) Dispatch SslEngine expiry (non + atomic) + + improved request log configuration options Improved Request log + configuration options + + make jetty plus example webapps use contextdeployer make jetty plus example + webapps use ContextDeployer + + make osgi manifests for jetty jars make OSGi manifests for jetty jars + + make slf4jlog impl public, add mbean descriptors Make SLF4JLog impl public, + add mbean descriptors + + protect sslselectchannelconnector from exceptions during close Protect + SslSelectChannelConnector from exceptions during close + + remove call to open connectors in jetty.xml remove call to open connectors + in jetty.xml + + setuid option to only open connectors before setuid. SetUID option to only + open connectors before setUID. + + spr-3682 - dont hide forward attr in include. SPR-3682 - dont hide forward + attr in include. + + update links on website update links on website + + update terracotta configs for tc 2.4 stable1 update terracotta configs for + tc 2.4 stable1 + + update terracotta session clustering to terracotta 2.4 update terracotta + session clustering to terracotta 2.4 + + upgrade to jasper 2.1 tag sjsas-9_1-b50g-beta3-27_june_2007 Upgrade to + Jasper 2.1 tag SJSAS-9_1-B50G-BETA3-27_June_2007 jetty-6.1.4 - 15 June 2007 + JETTY-370 ensure idleTimeout<=0 means connections never expire + JETTY-371 Fixed chunked HEAD response + JETTY-372 make test for cookie caching more rigorous - + fixed early open() call in NIO connectors + + fixed early open() call in nio connectors fixed early open() call in NIO + connectors jetty-6.1.4rc1 - 10 June 2007 + JETTY-310 better exception when no filter file for cometd servlet @@ -6294,12 +6539,16 @@ jetty-6.1.4rc1 - 10 June 2007 + JETTY-362 More object locks + JETTY-365 make needClientAuth work on SslSelectChannelConnector + JETTY-366 JETTY-368 Improved bayeux disconnect - + async client improvements - + fixed handling of large streamed files - + Fixed synchronization conflict SslSelectChannel and SelectChannel - + moved documentation for jetty and jspc maven plugins to wiki - + Optional static content cache - + Work around IBM JVM socket close issue + + async client improvements async client improvements + + fixed handling of large streamed files fixed handling of large streamed + files + + fixed synchronization conflict sslselectchannel and selectchannel Fixed + synchronization conflict SslSelectChannel and SelectChannel + + moved documentation for jetty and jspc maven plugins to wiki moved + documentation for jetty and jspc maven plugins to wiki + + optional static content cache Optional static content cache + + work around ibm jvm socket close issue Work around IBM JVM socket close + issue jetty-6.1.4rc0 - 01 June 2007 + JETTY-257 fixed comet cross domain @@ -6317,46 +6566,57 @@ jetty-6.1.4rc0 - 01 June 2007 + JETTY-345 fixed lost content with blocked NIO + JETTY-347 Fixed type util init + JETTY-352 Object locks - + Add (commented out) jspc precompile to test-webapp - + Add ability to run cometd webapps to maven plugin - + Add slf4j-api for upgraded version - + Allow XmlConfiguration properties to be configured - + Change scope of fields for Session - + Delay ssl handshake until after dispatch in sslSocketConnector - + fixed JSP close handling - + fixed waiting continuation reset - + improved date header handling - + Optional send Date header. Server.setSendDateHeader(boolean) - + Reorganized import of contrib modules - + Set so_timeout during ssl handshake as an option on SslSocketConnector - + Unified JMX configuration - + Updated junit to 3.8.2 - + Updated slf4j version to 1.3.1 - + update etc/jetty-ssl.xml with new handshake timeout setting + + add (commented out) jspc precompile to test-webapp Add (commented out) jspc + precompile to test-webapp + + add ability to run cometd webapps to maven plugin Add ability to run cometd + webapps to maven plugin + + add slf4j-api for upgraded version Add slf4j-api for upgraded version + + allow xmlconfiguration properties to be configured Allow XmlConfiguration + properties to be configured + + change scope of fields for session Change scope of fields for Session + + delay ssl handshake until after dispatch in sslsocketconnector Delay ssl + handshake until after dispatch in sslSocketConnector + + fixed jsp close handling fixed JSP close handling + + fixed waiting continuation reset fixed waiting continuation reset + + improved date header handling improved date header handling + + optional send date header. server.setsenddateheader(boolean) Optional send + Date header. Server.setSendDateHeader(boolean) + + reorganized import of contrib modules Reorganized import of contrib modules + + set so_timeout during ssl handshake as an option on sslsocketconnector Set + so_timeout during ssl handshake as an option on SslSocketConnector + + unified jmx configuration Unified JMX configuration + + updated junit to 3.8.2 Updated junit to 3.8.2 + + updated slf4j version to 1.3.1 Updated slf4j version to 1.3.1 + + update etc/jetty-ssl.xml with new handshake timeout setting update + etc/jetty-ssl.xml with new handshake timeout setting jetty-6.1.3 - 04 May 2007 + JETTY-309 don't clear writable status until dispatch + JETTY-315 suppressed warning + JETTY-322 AJP13 cping and keep alive - + Handle CRLF for content in header optimization + + handle crlf for content in header optimization Handle CRLF for content in + header optimization jetty-6.1.2 - 01 May 2007 + JETTY-322 fix ajp cpong response and close handling + JETTY-324 fix ant plugin + JETTY-328 updated jboss - + Added static member definition in WadiSessionManager - + Fixed session invalidation error in WadiSessionManager - + Improved unavailabile handling - + sendError resets output state - + Updated Wadi to version 2.0-M3 + + added static member definition in wadisessionmanager Added static member + definition in WadiSessionManager + + fixed session invalidation error in wadisessionmanager Fixed session + invalidation error in WadiSessionManager + + improved unavailabile handling Improved unavailabile handling + + senderror resets output state sendError resets output state + + updated wadi to version 2.0-m3 Updated Wadi to version 2.0-M3 jetty-6.1.2rc5 - 24 April 2007 + JETTY-305 delayed connection destroy + JETTY-309 handle close in multivalue connection fields + JETTY-314 fix for possible NPE in Request.isRequestedSessionIdValid - + Allow jsp-file to be / or /* - + removed some compile warnings - + set default keystore for SslSocketConnector + + allow jsp-file to be / or /* Allow jsp-file to be / or /* + + removed some compile warnings removed some compile warnings + + set default keystore for sslsocketconnector set default keystore for + SslSocketConnector jetty-6.1.2rc4 - 19 April 2007 + JETTY-294 Fixed authentication reset @@ -6377,12 +6637,18 @@ jetty-6.1.2rc3 - 16 April 2007 + JETTY-296 Close direct content inputstreams + JETTY-297 Recreate tmp dir on stop/start + JETTY-298 Names in JMX ObjectNames for context, servlets and filters - + AJP redirects https requests correctly - + Fixed writes of unencoded char arrays. - + Improved performance and exclusions for TLD scanning - + Improvements to allow simple setting of Cache-Control headers - + MBean properties assume writeable unless marked RO - + refactor of SessionManager and SessionIdManager for clustering + + ajp redirects https requests correctly AJP redirects https requests + correctly + + fixed writes of unencoded char arrays. Fixed writes of unencoded char + arrays. + + improved performance and exclusions for tld scanning Improved performance + and exclusions for TLD scanning + + improvements to allow simple setting of cache-control headers Improvements + to allow simple setting of Cache-Control headers + + mbean properties assume writeable unless marked ro MBean properties assume + writeable unless marked RO + + refactor of sessionmanager and sessionidmanager for clustering refactor of + SessionManager and SessionIdManager for clustering jetty-6.1.2rc2 - 27 March 2007 + JETTY-125 maven plugin: ensure test dependencies on classpath for @@ -6406,18 +6672,29 @@ jetty-6.1.2rc2 - 27 March 2007 + JETTY-284 Fixed stop connector race + JETTY-286 isIntegral and isConfidential methods overridden in SslSelectChannelConnector - + Added RestFilter for PUT and DELETE from Aleksi Kallio - + AJP13 CPING request and CPONG response implemented - + AJP13 remoteUser, contextPath, servletPath requests implemented - + AJP13 Shutdown Request from peer implemented - + Change some JNDI logging to debug level instead of info - + Enable the SharedStoreContextualiser for the WadiSessionManager(Database + + added restfilter for put and delete from aleksi kallio Added RestFilter for + PUT and DELETE from Aleksi Kallio + + ajp13 cping request and cpong response implemented AJP13 CPING request and + CPONG response implemented + + ajp13 remoteuser, contextpath, servletpath requests implemented AJP13 + remoteUser, contextPath, servletPath requests implemented + + ajp13 shutdown request from peer implemented AJP13 Shutdown Request from + peer implemented + + change some jndi logging to debug level instead of info Change some JNDI + logging to debug level instead of info + + enable the sharedstorecontextualiser for the wadisessionmanager(databa + Enable the SharedStoreContextualiser for the WadiSessionManager(Database store for clustering) - + Make annotations work for maven plugin - + Optimized multi threaded init on startup servlets - + Refactor Scanner to increase code reuse with maven/ant plugins - + Removed unneeded specialized TagLibConfiguration class from maven plugin - + Update jasper to glassfish tag SJSAS-9_1-B39-RC-14_Mar_2007 + + make annotations work for maven plugin Make annotations work for maven + plugin + + optimized multi threaded init on startup servlets Optimized multi threaded + init on startup servlets + + refactor scanner to increase code reuse with maven/ant plugins Refactor + Scanner to increase code reuse with maven/ant plugins + + removed unneeded specialized taglibconfiguration class from maven plug + Removed unneeded specialized TagLibConfiguration class from maven plugin + + update jasper to glassfish tag sjsas-9_1-b39-rc-14_mar_2007 Update jasper to + glassfish tag SJSAS-9_1-B39-RC-14_Mar_2007 jetty-6.1.2rc1 - 08 March 2007 + JETTY-157 make CGI handle binary data @@ -6433,20 +6710,34 @@ jetty-6.1.2rc1 - 08 March 2007 + JETTY-250 protect attribute enumerations from modification + JETTY-252 Fixed stats handling of close connection + JETTY-254 prevent close of jar file by bad JVMs - + add ajp connector jar to jetty-jboss sar - + Added option to allow null pathInfo within context - + Added support for lowResourcesIdleTime to SelectChannelConnector - + BoundedThreadPool queues rather than blocks excess jobs. - + call preDestroy() after servlet/filter destroy() - + Ensure jetty/jboss uses servlet-spec classloading order - + Fix constructor for Constraint to detect wildcard role - + fix Dump servlet to handle primitive array types - + handle comma separated values for the Connection: header - + Improved Context setters for wadi support - + Improved handling of early close in AJP - + Support null pathInfo option for webservices deployed to jetty/jboss - + TagLibConfiguration uses resource input stream - + Workaround to call SecurityAssocation.clear() for jboss webservices calls to + + add ajp connector jar to jetty-jboss sar add ajp connector jar to + jetty-jboss sar + + added option to allow null pathinfo within context Added option to allow + null pathInfo within context + + added support for lowresourcesidletime to selectchannelconnector Added + support for lowResourcesIdleTime to SelectChannelConnector + + boundedthreadpool queues rather than blocks excess jobs. BoundedThreadPool + queues rather than blocks excess jobs. + + call predestroy() after servlet/filter destroy() call preDestroy() after + servlet/filter destroy() + + ensure jetty/jboss uses servlet-spec classloading order Ensure jetty/jboss + uses servlet-spec classloading order + + fix constructor for constraint to detect wildcard role Fix constructor for + Constraint to detect wildcard role + + fix dump servlet to handle primitive array types fix Dump servlet to handle + primitive array types + + handle comma separated values for the connection: header handle comma + separated values for the Connection: header + + improved context setters for wadi support Improved Context setters for wadi + support + + improved handling of early close in ajp Improved handling of early close in + AJP + + support null pathinfo option for webservices deployed to jetty/jboss Support + null pathInfo option for webservices deployed to jetty/jboss + + taglibconfiguration uses resource input stream TagLibConfiguration uses + resource input stream + + workaround to call securityassocation.clear() for jboss webservices ca + Workaround to call SecurityAssocation.clear() for jboss webservices calls to ejbs jetty-6.1.2rc0 - 15 February 2007 @@ -6456,18 +6747,23 @@ jetty-6.1.2rc0 - 15 February 2007 + JETTY-236 Buffer leak + JETTY-237 AJPParser Buffer Data Handling + JETTY-238 prevent form truncation - + Coma separated cookies - + Cometd timeout clients - + Patches from sybase for ClientCertAuthenticator + + coma separated cookies Coma separated cookies + + cometd timeout clients Cometd timeout clients + + patches from sybase for clientcertauthenticator Patches from sybase for + ClientCertAuthenticator jetty-6.1.2pre1 - 05 February 2007 + JETTY-224 run build up to process-test before invoking jetty:run - + Added error handling for incorrect keystore/truststore password in + + added error handling for incorrect keystore/truststore password in Added + error handling for incorrect keystore/truststore password in SslSelectChannelConnector - + added win32service to standard build - + allow ResourceHandler to use resource base from an enclosing ContextHandler - + fixed bug with virtual host handling in ContextHandlerCollection - + refactored cometd to be continuation independent + + added win32service to standard build added win32service to standard build + + allow resourcehandler to use resource base from an enclosing contextha allow + ResourceHandler to use resource base from an enclosing ContextHandler + + fixed bug with virtual host handling in contexthandlercollection fixed bug + with virtual host handling in ContextHandlerCollection + + refactored cometd to be continuation independent refactored cometd to be + continuation independent jetty-6.1.2pre0 - 01 February 2007 + JETTY-213 request.isUserInRole(String) fixed @@ -6477,77 +6773,102 @@ jetty-6.1.2pre0 - 01 February 2007 + JETTY-219 fixed trailing encoded chars in cookies + JETTY-220 fixed AJP content + JETTY-222 fix problem parsing faces-config.xml - + Added cometd jsonp transport from aabeling - + Added terracotta cluster support for cometd - + add support for Annotations in servlet, filter and listener sources - + enable SslSelectChannelConnector to modify the SslEngine's client - authentication settings - + Fixed 1.4 method in jetty plus - + Fixed generation of errors during jsp compilation for jsp-2.1 - + handle virtual hosts in ContextHandlerCollection - + improved writer buffering - + moved JSON parser to util to support reuse + + added cometd jsonp transport from aabeling Added cometd jsonp transport from + aabeling + + added terracotta cluster support for cometd Added terracotta cluster support + for cometd + + add support for annotations in servlet, filter and listener sources add + support for Annotations in servlet, filter and listener sources + + enable sslselectchannelconnector to modify the sslengine's client enable + SslSelectChannelConnector to modify the SslEngine's client authentication + settings + + fixed 1.4 method in jetty plus Fixed 1.4 method in jetty plus + + fixed generation of errors during jsp compilation for jsp-2.1 Fixed + generation of errors during jsp compilation for jsp-2.1 + + handle virtual hosts in contexthandlercollection handle virtual hosts in + ContextHandlerCollection + + improved writer buffering improved writer buffering + + moved json parser to util to support reuse moved JSON parser to util to + support reuse jetty-6.1.1 - 15 January 2007 jetty-6.1.1rc1 - 12 January 2007 + JETTY-210 Build jsp-api-2.0 for java 1.4 - + Use timers for Rollover logs and scanner + + use timers for rollover logs and scanner Use timers for Rollover logs and + scanner jetty-6.1.1rc0 - 10 January 2007 + JETTY-209 Added ServletTester.createSocketConnector + JETTY-210 Build servlet-api-2.5 for java 1.4 + JETTY-211 fixed jboss build - + CGI servlet fails without exception - + ensure response headers on AjaxFilter messsages turn off caching - + extras/win32service download only if no JavaServiceWrapper exist - + Fixed unpacking WAR - + MultiPartFilter deleteFiles option - + simplified chat demo - + start webapps on deployment with jboss, use isDistributed() method from + + cgi servlet fails without exception CGI servlet fails without exception + + ensure response headers on ajaxfilter messsages turn off caching ensure + response headers on AjaxFilter messsages turn off caching + + extras/win32service download only if no javaservicewrapper exist + extras/win32service download only if no JavaServiceWrapper exist + + fixed unpacking war Fixed unpacking WAR + + multipartfilter deletefiles option MultiPartFilter deleteFiles option + + simplified chat demo simplified chat demo + + start webapps on deployment with jboss, use isdistributed() method fro start + webapps on deployment with jboss, use isDistributed() method from WebAppContext jetty-6.1.0 - 09 January 2007 - + Fixed unpacking WAR + + fixed unpacking war Fixed unpacking WAR jetty-6.1.0 - 05 January 2007 + JETTY-206 fixed AJP getServerPort and getRemotePort - + Added extras/win32service - + Added WebAppContext.setCopyWebDir to avoid JVM jar caching issues. - + GERONIMO-2677 refactor of session id handling for clustering - + Improved config of java5 threadpool - + Protect context deployer from Errors - + ServletTester sets content length + + added extras/win32service Added extras/win32service + + added webappcontext.setcopywebdir to avoid jvm jar caching issues. Added + WebAppContext.setCopyWebDir to avoid JVM jar caching issues. + + geronimo-2677 refactor of session id handling for clustering GERONIMO-2677 + refactor of session id handling for clustering + + improved config of java5 threadpool Improved config of java5 threadpool + + protect context deployer from errors Protect context deployer from Errors + + servlettester sets content length ServletTester sets content length jetty-6.1.0rc3 - 02 January 2007 + JETTY-195 fixed ajp ssl_cert handling + JETTY-197 fixed getRemoteHost + JETTY-203 initialize ServletHandler if no Context instance + JETTY-204 setuid fix - + extras/servlet-tester - + implement resource injection and lifecycle callbacks declared in web.xml - + setLocale does not use default content type - + Use standard releases of servlet and jsp APIs. + + extras/servlet-tester extras/servlet-tester + + implement resource injection and lifecycle callbacks declared in web.x + implement resource injection and lifecycle callbacks declared in web.xml + + setlocale does not use default content type setLocale does not use default + content type + + use standard releases of servlet and jsp apis. Use standard releases of + servlet and jsp APIs. jetty-6.1.0rc2 - 20 December 2006 + JETTY-167 cometd refactor + JETTY-194 doubles slashes are significant in URIs + JETTY-201 make run-as work for both web container and ejb container in jboss - + AJP13Parser, throw IllegalStateException on unimplemented AJP13 Requests - + ContextHandlerCollection is noop with no handlers - + ensure classpath passed to jspc contains file paths not urls - + ensure com.sun.el.Messages.properties included in jsp-2.1 jar - + ensure servlets initialized if only using ServletHandler - + fixed Jetty-197 AJP13 getRemoteHost() - + Refactored AbstractSessionManager for ehcache - + remove code to remove SecurityHandler if no constraints present + + ajp13parser, throw illegalstateexception on unimplemented ajp13 reques + AJP13Parser, throw IllegalStateException on unimplemented AJP13 Requests + + contexthandlercollection is noop with no handlers ContextHandlerCollection + is noop with no handlers + + ensure classpath passed to jspc contains file paths not urls ensure + classpath passed to jspc contains file paths not urls + + ensure com.sun.el.messages.properties included in jsp-2.1 jar ensure + com.sun.el.Messages.properties included in jsp-2.1 jar + + ensure servlets initialized if only using servlethandler ensure servlets + initialized if only using ServletHandler + + Jetty-197 AJP13 getRemoteHost() + + refactored abstractsessionmanager for ehcache Refactored + AbstractSessionManager for ehcache + + remove code to remove securityhandler if no constraints present remove code + to remove SecurityHandler if no constraints present jetty-6.1.0rc1 - 14 December 2006 + JETTY-193 MailSessionReference without authentication + JETTY-199 newClassPathResource - + added cache session manager(pre-alpha) - + ensure unique name for ServletHolder instances - + simplified idle timeout handling + + added cache session manager(pre-alpha) added cache session + manager(pre-alpha) + + ensure unique name for servletholder instances ensure unique name for + ServletHolder instances + + simplified idle timeout handling simplified idle timeout handling jetty-6.1.0rc0 - 08 December 2006 + JETTY-123 fix improved @@ -6557,34 +6878,43 @@ jetty-6.1.0rc0 - 08 December 2006 + JETTY-185 tmp filename generation + JETTY-189 ProxyConnection + 403 for BASIC authorization failure - + Added extras/gwt - + Added org.mortbay.thread.concurrent.ThreadPool - + Added spring ejb3 demo example - + DefaultHandler links virtual hosts. - + Dispatcher does not protect javax.servlet attributes - + Fixed cachesize on invalidate - + Fixed idle timeout - + flush if content-length written - + forward query attribute fix - + Handle request content encodings - + null for unknown named dispatches - + Optimization of writers - + ServletHandler allows non REQUEST exceptions to propogate - + Servlet role ref - + session attribute listener - + Support for RFC2518 102-processing response - + TCK fixes from Sybase: - + update jasper to glassfish SJSAS-9_1-B27-EA-07_Dec_2006 + + added extras/gwt Added extras/gwt + + added org.mortbay.thread.concurrent.threadpool Added + org.mortbay.thread.concurrent.ThreadPool + + added spring ejb3 demo example Added spring ejb3 demo example + + defaulthandler links virtual hosts. DefaultHandler links virtual hosts. + + dispatcher does not protect javax.servlet attributes Dispatcher does not + protect javax.servlet attributes + + fixed cachesize on invalidate Fixed cachesize on invalidate + + fixed idle timeout Fixed idle timeout + + flush if content-length written flush if content-length written + + forward query attribute fix forward query attribute fix + + handle request content encodings Handle request content encodings + + null for unknown named dispatches null for unknown named dispatches + + optimization of writers Optimization of writers + + servlethandler allows non request exceptions to propogate ServletHandler + allows non REQUEST exceptions to propogate + + servlet role ref Servlet role ref + + session attribute listener session attribute listener + + support for rfc2518 102-processing response Support for RFC2518 + 102-processing response + + tck fixes from sybase: TCK fixes from Sybase: + + update jasper to glassfish sjsas-9_1-b27-ea-07_dec_2006 update jasper to + glassfish SJSAS-9_1-B27-EA-07_Dec_2006 jetty-6.1.0pre3 - 22 November 2006 + JETTY-154 Cookies are double quotes only + JETTY-180 XBean support for context deploy - + CVE-2006-6969 Upgraded session ID generation to use SecureRandom - + Expose isResumed on Continuations - + fixed NIO endpoint flush. Avoid duplicate sends - + Refactored AJP generator - + Support TLS_DHE_RSA_WITH_AES_256_CBC_SHA - + updated glassfish jasper to tag SJSAS-9_1-B25-EA-08_Nov_2006 + + cve-2006-6969 upgraded session id generation to use securerandom + CVE-2006-6969 Upgraded session ID generation to use SecureRandom + + expose isresumed on continuations Expose isResumed on Continuations + + fixed nio endpoint flush. avoid duplicate sends fixed NIO endpoint flush. + Avoid duplicate sends + + refactored ajp generator Refactored AJP generator + + support tls_dhe_rsa_with_aes_256_cbc_sha Support + TLS_DHE_RSA_WITH_AES_256_CBC_SHA + + updated glassfish jasper to tag sjsas-9_1-b25-ea-08_nov_2006 updated + glassfish jasper to tag SJSAS-9_1-B25-EA-08_Nov_2006 jetty-6.0.2 - 22 November 2006 + JETTY-118 ignore extra content after close @@ -6597,87 +6927,127 @@ jetty-6.0.2 - 22 November 2006 + JETTY-171 Fixed filter mapping + JETTY-172 use getName() instead of toString + JETTY-173 restore servletpath after dispatch - + (re)make JAAS classes available to webapp classloader - + add replacement in jetty xml config files - + Added concept of bufferred endpoint - + Added conversion Object -> ObjectName for the result of method calls made on + + (re)make jaas classes available to webapp classloader (re)make JAAS classes + available to webapp classloader + + add replacement in jetty xml config files add + replacement in jetty xml config files + + added concept of bufferred endpoint Added concept of bufferred endpoint + + added conversion object -> objectname for the result of method calls m Added + conversion Object -> ObjectName for the result of method calls made on MBeans - + Added DataFilter configuration to cometd - + added examples/test-jaas-webapp - + Added extraClassPath to WebAppContext - + Added hierarchical destroy of mbeans - + Added ID constructor to AbstractSessionManager.Session - + added isStopped() in LifeCycle and AbstractLifeCycle - + Added override descriptor for deployment of RO webapps - + Allow session cookie to be refreshed - + alternate optimizations of writer (use -Dbuffer.writers=true) - + Apply queryEncoding to getQueryString - + CGI example in test webapp - + change examples/test-jndi-webapp so it can be regularly built - + Default soLinger is -1 (disabled) - + ensure "" returned for ServletContext.getContextPath() for root context - + ensure sessions nulled out on request recycle; ensure session null after + + added datafilter configuration to cometd Added DataFilter configuration to + cometd + + added examples/test-jaas-webapp added examples/test-jaas-webapp + + added extraclasspath to webappcontext Added extraClassPath to WebAppContext + + added hierarchical destroy of mbeans Added hierarchical destroy of mbeans + + added id constructor to abstractsessionmanager.session Added ID constructor + to AbstractSessionManager.Session + + added isstopped() in lifecycle and abstractlifecycle added isStopped() in + LifeCycle and AbstractLifeCycle + + added override descriptor for deployment of ro webapps Added override + descriptor for deployment of RO webapps + + allow session cookie to be refreshed Allow session cookie to be refreshed + + alternate optimizations of writer (use -dbuffer.writers=true) alternate + optimizations of writer (use -Dbuffer.writers=true) + + apply queryencoding to getquerystring Apply queryEncoding to getQueryString + + cgi example in test webapp CGI example in test webapp + + change examples/test-jndi-webapp so it can be regularly built change + examples/test-jndi-webapp so it can be regularly built + + default solinger is -1 (disabled) Default soLinger is -1 (disabled) + + ensure "" returned for servletcontext.getcontextpath() for root contex + ensure "" returned for ServletContext.getContextPath() for root context + + ensure sessions nulled out on request recycle; ensure session null aft + ensure sessions nulled out on request recycle; ensure session null after invalidate - + ensure setContextPath() works when invoked from jetty-web.xml - + fixed NIO endpoint flush. Avoid duplicate sends - + Fixed NPE in bio.SocketEndPoint.getRemoteAddr() - + Fixed resource cache flushing - + Fixed tld parsing for maven plugin - + HttpGenerator can generate requests - + Improved *-mbean.properties files and specialized some MBean - + Major refactor of SelectChannel EndPoint for client selector - + make .tag files work in packed wars - + Moved all modules updates from 6.1pre2 to 6.0 - + Plugin shutdown context before stopping it. - + Refactored session lifecycle and additional tests - + release resource lookup in Default servlet - + Reverted UnixCrypt to use coersions (that effected results) - + Session IDs can change worker ID - + Simplified ResourceCache and Default servlet - + SocketConnector closes all connections in doStop - + Support TLS_DHE_RSA_WITH_AES_256_CBC_SHA - + updated glassfish jasper to tag SJSAS-9_1-B25-EA-08_Nov_2006 - + Upgraded session ID generation to use SecureRandom + + ensure setcontextpath() works when invoked from jetty-web.xml ensure + setContextPath() works when invoked from jetty-web.xml + + fixed nio endpoint flush. avoid duplicate sends fixed NIO endpoint flush. + Avoid duplicate sends + + fixed npe in bio.socketendpoint.getremoteaddr() Fixed NPE in + bio.SocketEndPoint.getRemoteAddr() + + fixed resource cache flushing Fixed resource cache flushing + + fixed tld parsing for maven plugin Fixed tld parsing for maven plugin + + httpgenerator can generate requests HttpGenerator can generate requests + + improved *-mbean.properties files and specialized some mbean Improved + *-mbean.properties files and specialized some MBean + + major refactor of selectchannel endpoint for client selector Major refactor + of SelectChannel EndPoint for client selector + + make .tag files work in packed wars make .tag files work in packed wars + + moved all modules updates from 6.1pre2 to 6.0 Moved all modules updates from + 6.1pre2 to 6.0 + + plugin shutdown context before stopping it. Plugin shutdown context before + stopping it. + + refactored session lifecycle and additional tests Refactored session + lifecycle and additional tests + + release resource lookup in default servlet release resource lookup in + Default servlet + + reverted unixcrypt to use coersions (that effected results) Reverted + UnixCrypt to use coersions (that effected results) + + session ids can change worker id Session IDs can change worker ID + + simplified resourcecache and default servlet Simplified ResourceCache and + Default servlet + + socketconnector closes all connections in dostop SocketConnector closes all + connections in doStop + + support tls_dhe_rsa_with_aes_256_cbc_sha Support + TLS_DHE_RSA_WITH_AES_256_CBC_SHA + + updated glassfish jasper to tag sjsas-9_1-b25-ea-08_nov_2006 updated + glassfish jasper to tag SJSAS-9_1-B25-EA-08_Nov_2006 + + upgraded session id generation to use securerandom Upgraded session ID + generation to use SecureRandom jetty-5.1.14 - 09 August 2007 + JETTY-155 force close with content length + JETTY-369 failed state in Container - + patched with correct version + + patched with correct version patched with correct version jetty-5.1.13 - + Sourceforge 1648335: problem setting version for AJP13 + + sourceforge 1648335: problem setting version for ajp13 Sourceforge 1648335: + problem setting version for AJP13 jetty-5.1.12 - 22 November 2006 + JETTY-154 Cookies ignore single quotes - + Added support for TLS_DHE_RSA_WITH_AES_256_CBC_SHA - + AJP protected against bad requests from mod_jk - + Quote single quotes in cookies - + Upgraded session ID generation to use SecureRandom + + added support for tls_dhe_rsa_with_aes_256_cbc_sha Added support for + TLS_DHE_RSA_WITH_AES_256_CBC_SHA + + ajp protected against bad requests from mod_jk AJP protected against bad + requests from mod_jk + + quote single quotes in cookies Quote single quotes in cookies + + upgraded session id generation to use securerandom Upgraded session ID + generation to use SecureRandom jetty-4.2.27 - 22 November 2006 - + AJP protected against bad requests from mod_jk - + Upgraded session ID generation to use SecureRandom + + ajp protected against bad requests from mod_jk AJP protected against bad + requests from mod_jk + + upgraded session id generation to use securerandom Upgraded session ID + generation to use SecureRandom jetty-6.1.0pre2 - 20 November 2006 - + Added extraClassPath to WebAppContext - + Clean up jboss module licensing - + Fixed resource cache flushing + + added extraclasspath to webappcontext Added extraClassPath to WebAppContext + + clean up jboss module licensing Clean up jboss module licensing + + fixed resource cache flushing Fixed resource cache flushing jetty-6.1.0pre1 - 19 November 2006 + JETTY-151 Idle timeout only applies to blocking operations + JETTY-171 Fixed filter mapping + JETTY-172 use getName() instead of toString + JETTY-173 restore servletpath after dispatch - + Added extras/jboss - + Added hierarchical destroy of mbeans - + Added override descriptor for deployment of RO webapps - + alternate optimizations of writer (use -Dbuffer.writers=true) - + Fixed NPE in bio.SocketEndPoint.getRemoteAddr() - + Major refactor of SelectChannel EndPoint for client selector - + release resource lookup in Default servlet - + Reverted UnixCrypt to use coersions (that effected results) - + Simplified ResourceCache and Default servlet - + Use ContextDeployer as main deployer in jetty.xml + + added extras/jboss Added extras/jboss + + added hierarchical destroy of mbeans Added hierarchical destroy of mbeans + + added override descriptor for deployment of ro webapps Added override + descriptor for deployment of RO webapps + + alternate optimizations of writer (use -dbuffer.writers=true) alternate + optimizations of writer (use -Dbuffer.writers=true) + + fixed npe in bio.socketendpoint.getremoteaddr() Fixed NPE in + bio.SocketEndPoint.getRemoteAddr() + + major refactor of selectchannel endpoint for client selector Major refactor + of SelectChannel EndPoint for client selector + + release resource lookup in default servlet release resource lookup in + Default servlet + + reverted unixcrypt to use coersions (that effected results) Reverted + UnixCrypt to use coersions (that effected results) + + simplified resourcecache and default servlet Simplified ResourceCache and + Default servlet + + use contextdeployer as main deployer in jetty.xml Use ContextDeployer as + main deployer in jetty.xml jetty-6.1.0pre0 - 21 October 2006 + JETTY-112 ContextHandler checks if started @@ -6691,58 +7061,86 @@ jetty-6.1.0pre0 - 21 October 2006 + JETTY-124 always initialize filter caches + JETTY-126 handle content > Integer.MAX_VALUE + JETTY-129 ServletContextListeners called after servlets are initialized - + (re)make JAAS classes available to webapp classloader - + add replacement in jetty xml config files - + add a maven-jetty-jspc-plugin to do jspc precompilation - + added cometd chat demo - + Added concept of bufferred endpoint - + Added conversion Object -> ObjectName for the result of method calls made on + + (re)make jaas classes available to webapp classloader (re)make JAAS classes + available to webapp classloader + + add replacement in jetty xml config files add + replacement in jetty xml config files + + add a maven-jetty-jspc-plugin to do jspc precompilation add a + maven-jetty-jspc-plugin to do jspc precompilation + + added cometd chat demo added cometd chat demo + + added concept of bufferred endpoint Added concept of bufferred endpoint + + added conversion object -> objectname for the result of method calls m Added + conversion Object -> ObjectName for the result of method calls made on MBeans - + Added DataFilter configuration to cometd - + added examples/test-jaas-webapp - + Added extras/setuid to support start as root - + Added ID constructor to AbstractSessionManager.Session - + added isStopped() in LifeCycle and AbstractLifeCycle - + add hot deployment capability - + AJP Connector - + Allow session cookie to be refreshed - + Apply queryEncoding to getQueryString - + CGI example in test webapp - + change examples/test-jndi-webapp so it can be regularly built - + Default soLinger is -1 (disabled) - + ensure "" returned for ServletContext.getContextPath() for root context - + ensure sessions nulled out on request recycle; ensure session null after + + added datafilter configuration to cometd Added DataFilter configuration to + cometd + + added examples/test-jaas-webapp added examples/test-jaas-webapp + + added extras/setuid to support start as root Added extras/setuid to support + start as root + + added id constructor to abstractsessionmanager.session Added ID constructor + to AbstractSessionManager.Session + + added isstopped() in lifecycle and abstractlifecycle added isStopped() in + LifeCycle and AbstractLifeCycle + + add hot deployment capability add hot deployment capability + + ajp connector AJP Connector + + allow session cookie to be refreshed Allow session cookie to be refreshed + + apply queryencoding to getquerystring Apply queryEncoding to getQueryString + + cgi example in test webapp CGI example in test webapp + + change examples/test-jndi-webapp so it can be regularly built change + examples/test-jndi-webapp so it can be regularly built + + default solinger is -1 (disabled) Default soLinger is -1 (disabled) + + ensure "" returned for servletcontext.getcontextpath() for root contex + ensure "" returned for ServletContext.getContextPath() for root context + + ensure sessions nulled out on request recycle; ensure session null aft + ensure sessions nulled out on request recycle; ensure session null after invalidate - + ensure setContextPath() works when invoked from jetty-web.xml - + Factored ErrorPageErrorHandler out of WebAppContext - + fixed ClassCastException in JAASUserRealm.setRoleClassNames(String[]) - + fixed isUserInRole checking for JAASUserRealm - + Fixed tld parsing for maven plugin - + HttpGenerator can generate requests - + Improved *-mbean.properties files and specialized some MBean - + Improved charset handling in URLs - + JETYY-120 SelectChannelConnector closes all connections on stop - + make .tag files work in packed wars - + minor optimization of bytes to UTF8 strings - + Plugin shutdown context before stopping it. - + Ported HtAccessHandler - + Refactored ErrorHandler to avoid statics - + Refactored session lifecycle and additional tests - + Session IDs can change worker ID - + SocketConnector closes all connections in doStop - + Start of a client API - + Transforming classloader does not transform resources. + + ensure setcontextpath() works when invoked from jetty-web.xml ensure + setContextPath() works when invoked from jetty-web.xml + + factored errorpageerrorhandler out of webappcontext Factored + ErrorPageErrorHandler out of WebAppContext + + fixed classcastexception in jaasuserrealm.setroleclassnames(string[]) fixed + ClassCastException in JAASUserRealm.setRoleClassNames(String[]) + + fixed isuserinrole checking for jaasuserrealm fixed isUserInRole checking + for JAASUserRealm + + fixed tld parsing for maven plugin Fixed tld parsing for maven plugin + + httpgenerator can generate requests HttpGenerator can generate requests + + improved *-mbean.properties files and specialized some mbean Improved + *-mbean.properties files and specialized some MBean + + improved charset handling in urls Improved charset handling in URLs + + jetyy-120 selectchannelconnector closes all connections on stop JETYY-120 + SelectChannelConnector closes all connections on stop + + make .tag files work in packed wars make .tag files work in packed wars + + minor optimization of bytes to utf8 strings minor optimization of bytes to + UTF8 strings + + plugin shutdown context before stopping it. Plugin shutdown context before + stopping it. + + ported htaccesshandler Ported HtAccessHandler + + refactored errorhandler to avoid statics Refactored ErrorHandler to avoid + statics + + refactored session lifecycle and additional tests Refactored session + lifecycle and additional tests + + session ids can change worker id Session IDs can change worker ID + + socketconnector closes all connections in dostop SocketConnector closes all + connections in doStop + + start of a client api Start of a client API + + transforming classloader does not transform resources. Transforming + classloader does not transform resources. jetty-5.1.11 - 08 October 2006 - + Default servlet only uses setContentLength on wrapped responses - + Fixed AJP chunk header (1507377) - + Fixed AJP handling of certificate length (1494939) - + fixed ByteBufferOutputStream capacity calculation - + Fixed order of destruction event calls - + Fix to HttpOutputStream from M.Traverso + + default servlet only uses setcontentlength on wrapped responses Default + servlet only uses setContentLength on wrapped responses + + fixed ajp chunk header (1507377) Fixed AJP chunk header (1507377) + + fixed ajp handling of certificate length (1494939) Fixed AJP handling of + certificate length (1494939) + + fixed bytebufferoutputstream capacity calculation fixed + ByteBufferOutputStream capacity calculation + + fixed order of destruction event calls Fixed order of destruction event + calls + + fix to httpoutputstream from m.traverso Fix to HttpOutputStream from + M.Traverso jetty-4.2.26 - 08 October 2006 - + Backport of AJP fixes + + backport of ajp fixes Backport of AJP fixes jetty-6.0.1 - 24 September 2006 + JETTY-112 ContextHandler checks if started @@ -6751,2776 +7149,4050 @@ jetty-6.0.1 - 24 September 2006 + JETTY-115 Fixed addHeader + JETTY-121 init not called on externally constructed servlets + JETTY-124 always initialize filter caches - + Factored ErrorPageErrorHandler out of WebAppContext - + fixed ClassCastException in JAASUserRealm.setRoleClassNames(String[]) - + fixed isUserInRole checking for JAASUserRealm - + Improved charset handling in URLs - + JETYY-120 SelectChannelConnector closes all connections on stop - + minor optimization of bytes to UTF8 strings - + Refactored ErrorHandler to avoid statics + + factored errorpageerrorhandler out of webappcontext Factored + ErrorPageErrorHandler out of WebAppContext + + fixed classcastexception in jaasuserrealm.setroleclassnames(string[]) fixed + ClassCastException in JAASUserRealm.setRoleClassNames(String[]) + + fixed isuserinrole checking for jaasuserrealm fixed isUserInRole checking + for JAASUserRealm + + improved charset handling in urls Improved charset handling in URLs + + jetyy-120 selectchannelconnector closes all connections on stop JETYY-120 + SelectChannelConnector closes all connections on stop + + minor optimization of bytes to utf8 strings minor optimization of bytes to + UTF8 strings + + refactored errorhandler to avoid statics Refactored ErrorHandler to avoid + statics jetty-6.0.0 - 10 September 2006 - + Conveniance builder methods for listeners and filters - + Plugin shutdown context before stopping it. - + SocketConnector closes all connections in doStop - + Transforming classloader does not transform resources. + + conveniance builder methods for listeners and filters Conveniance builder + methods for listeners and filters + + plugin shutdown context before stopping it. Plugin shutdown context before + stopping it. + + socketconnector closes all connections in dostop SocketConnector closes all + connections in doStop + + transforming classloader does not transform resources. Transforming + classloader does not transform resources. jetty-6.0.0rc4 - 05 September 2006 + JETTY-107 Poor cast in SessionDump demo - + bind jetty-env.xml entries to java:comp/env - + Set charset on error pages + + bind jetty-env.xml entries to java:comp/env bind jetty-env.xml entries to + java:comp/env + + set charset on error pages Set charset on error pages jetty-6.0.0rc3 - 01 September 2006 + JETTY-68 Complete request after sendRedirect + JETTY-104 (raised glassfish ISSUE-1044) hide JSP forced path attribute - + Avoid double error handling of Bad requests - + don't warn for content length on head requests - + JETTY-103 - + Less verbose handling of BadResources from bad URLs - + Move MailSessionReference to org.mortbay.naming.factories - + pulled 6.0.0 branch - + Transferred the sslengine patch from the patches directory to extras + + avoid double error handling of bad requests Avoid double error handling of + Bad requests + + don't warn for content length on head requests don't warn for content length + on head requests + + jetty-103 JETTY-103 + + less verbose handling of badresources from bad urls Less verbose handling of + BadResources from bad URLs + + move mailsessionreference to org.mortbay.naming.factories Move + MailSessionReference to org.mortbay.naming.factories + + pulled 6.0.0 branch pulled 6.0.0 branch + + transferred the sslengine patch from the patches directory to extras + Transferred the sslengine patch from the patches directory to extras jetty-6.0.0rc2 - 25 August 2006 - + added org.apache.commons.logging package to system classes that can't be + + added org.apache.commons.logging package to system classes that can't added + org.apache.commons.logging package to system classes that can't be overridden by a webapp classloader - + Destroy HttpConnection to improve buffer pooling - + Direct buffer useage is optional - + Fixed NPE when no resource cache - + Moved more utility packagtes to the util jar - + mvn -Djetty.port=x jetty:run uses port number given for the default - connector - + Refactored WebXmlConfiguration to allow custom web.xml resource - + Timestamp in StdErrLog - + use mvn -Dslf4j=false jetty:run to disable use of slf4j logging with - jdk1.4/jsp2.0 + + destroy httpconnection to improve buffer pooling Destroy HttpConnection to + improve buffer pooling + + direct buffer useage is optional Direct buffer useage is optional + + fixed npe when no resource cache Fixed NPE when no resource cache + + moved more utility packagtes to the util jar Moved more utility packagtes to + the util jar + + mvn -djetty.port=x jetty:run uses port number given for the default mvn + -Djetty.port=x jetty:run uses port number given for the default connector + + refactored webxmlconfiguration to allow custom web.xml resource Refactored + WebXmlConfiguration to allow custom web.xml resource + + timestamp in stderrlog Timestamp in StdErrLog + + use mvn -dslf4j=false jetty:run to disable use of slf4j logging with use mvn + -Dslf4j=false jetty:run to disable use of slf4j logging with jdk1.4/jsp2.0 jetty-6.0.0rc1 - 16 August 2006 + JETTY-85 JETTY-86 (TrustManager and SecureRandom are now configurable; better handling of null/default values) - + add config param to jetty plugin - + added modules/spring with XmlBeanFactory configuration - + Added simple ResourceHandler and FileServer example - + added start of cometd implementation (JSON only) - + added start of grizzly connector - + Added TransformingWebAppClassLoader for spring 2.0 byte code modification - support - + Allow direct filling of buffers for uncached static content. - + Change path mapping so that a path spec of /foo/* does not match /foo.bar : + + add config param to jetty plugin add config param + to jetty plugin + + added modules/spring with xmlbeanfactory configuration added modules/spring + with XmlBeanFactory configuration + + added simple resourcehandler and fileserver example Added simple + ResourceHandler and FileServer example + + added start of cometd implementation (json only) added start of cometd + implementation (JSON only) + + added start of grizzly connector added start of grizzly connector + + added transformingwebappclassloader for spring 2.0 byte code modificat Added + TransformingWebAppClassLoader for spring 2.0 byte code modification support + + allow direct filling of buffers for uncached static content. Allow direct + filling of buffers for uncached static content. + + change path mapping so that a path spec of /foo/* does not match /foo. + Change path mapping so that a path spec of /foo/* does not match /foo.bar : JETTY-88 - + -DSTOP.PORT must be specified. - + fixed bug that caused Response.setStatus to ignore the provided message - + Fixed FD leak for bad TCP acks. JETTY-63 - + JETTY-87 - + JETTY-90 - + JETTY-91 - + moved optional modules to extras - + parse jsp-property-group in web.xml for additional JSP servlet mappings - + protected setContentType from being set during include - + refactored resource cache - + removed org.mortbay. from context system classes configuration - + removed support for lowResources from SelectChannelConnector - + Support for binding References and Referenceables and javax.mail.Sessions in + + -dstop.port must be specified. -DSTOP.PORT must be specified. + + fixed bug that caused response.setstatus to ignore the provided messag fixed + bug that caused Response.setStatus to ignore the provided message + + fixed fd leak for bad tcp acks. jetty-63 Fixed FD leak for bad TCP acks. + JETTY-63 + + jetty-87 JETTY-87 + + jetty-90 JETTY-90 + + jetty-91 JETTY-91 + + moved optional modules to extras moved optional modules to extras + + parse jsp-property-group in web.xml for additional jsp servlet mapping parse + jsp-property-group in web.xml for additional JSP servlet mappings + + protected setcontenttype from being set during include protected + setContentType from being set during include + + refactored resource cache refactored resource cache + + removed org.mortbay. from context system classes configuration removed + org.mortbay. from context system classes configuration + + removed support for lowresources from selectchannelconnector removed support + for lowResources from SelectChannelConnector + + support for binding references and referenceables and javax.mail.sessi + Support for binding References and Referenceables and javax.mail.Sessions in JNDI jetty-6.0.0rc0 - 07 July 2006 - + add ability to have a lib/ext dir from which to recursively add all jars and + + add ability to have a lib/ext dir from which to recursively add all ja add + ability to have a lib/ext dir from which to recursively add all jars and zips to the classpath - + Added 8 random letters&digits to Jetty-generated tmp work dir name to ensure + + added 8 random letters&digits to jetty-generated tmp work dir name to Added + 8 random letters&digits to Jetty-generated tmp work dir name to ensure uniqueness - + added html module from jetty 5 - but deprecated until maintainer found - + Added maximum limit to filter chain cache. - + added setters and getters on SessionManager API for session related config: - cookie name, url parameter name, domain, max age and path. - + added StatisticsHandler and statistics on Connector. - + Added WebAppContextClassLoader.newInstance to better support exensible - loaders. - + allow or in for plugin - + changed ServletContext.getResourcePaths() to not return paths containing + + added html module from jetty 5 - but deprecated until maintainer found added + html module from jetty 5 - but deprecated until maintainer found + + added maximum limit to filter chain cache. Added maximum limit to filter + chain cache. + + added setters and getters on sessionmanager api for session related co added + setters and getters on SessionManager API for session related config: cookie + name, url parameter name, domain, max age and path. + + added statisticshandler and statistics on connector. added StatisticsHandler + and statistics on Connector. + + added webappcontextclassloader.newinstance to better support exensible Added + WebAppContextClassLoader.newInstance to better support exensible loaders. + + allow or in for plugin allow or + in for plugin + + changed servletcontext.getresourcepaths() to not return paths contain + changed ServletContext.getResourcePaths() to not return paths containing double slashes - + change name of generated tmp directory to be - "Jetty_"+host+"_"+port+"_"+contextpath+"_"+virtualhost - + change prefix from "jetty6" to just "jetty" for plugin: eg is now mvn - jetty:run - + Cleaned up idle expiry. - + ContextHandlerCollection addContext and setContextClass - + Discard excess bytes in header buffer if connection is closing - + Do not wrap EofException with EofException - + ensure explicitly set tmp directory called "work" is not deleted on exit - + Ensure mvn clean cleans the build - + ensure war is only unpacked if war is newer than "work" directory - + fixed classesDirectory param for maven plugin to be configurable - + fixed HttpGenerator convertion of non UTF-8: JETTY-82 - + immutable getParameterMap() - + patch to allow Jetty to use JSP2.1 from Glassfish instead of Jasper from - Tomcat - + refactor HttpChannelEndPoint in preparation for SslEngine - + reverse order for destroy event listeners - + simplified jetty.xml with new constructor injections - + Simplified Servlet Context API - + Simplify runtime resolution of JSP library for plugin - + Ssl algorithm taken from system property - + support for SingleThreadModel - + support graceful shutdown - + Threadpool does not need to be a LifeCycle - + Updated javax code from + + change name of generated tmp directory to be change name of generated tmp + directory to be "Jetty_"+host+"_"+port+"_"+contextpath+"_"+virtualhost + + change prefix from "jetty6" to just "jetty" for plugin: eg is now mvn change + prefix from "jetty6" to just "jetty" for plugin: eg is now mvn jetty:run + + cleaned up idle expiry. Cleaned up idle expiry. + + contexthandlercollection addcontext and setcontextclass + ContextHandlerCollection addContext and setContextClass + + discard excess bytes in header buffer if connection is closing Discard + excess bytes in header buffer if connection is closing + + do not wrap eofexception with eofexception Do not wrap EofException with + EofException + + ensure explicitly set tmp directory called "work" is not deleted on ex + ensure explicitly set tmp directory called "work" is not deleted on exit + + ensure mvn clean cleans the build Ensure mvn clean cleans the build + + ensure war is only unpacked if war is newer than "work" directory ensure war + is only unpacked if war is newer than "work" directory + + fixed classesdirectory param for maven plugin to be configurable fixed + classesDirectory param for maven plugin to be configurable + + fixed httpgenerator convertion of non utf-8: jetty-82 fixed HttpGenerator + convertion of non UTF-8: JETTY-82 + + immutable getparametermap() immutable getParameterMap() + + patch to allow jetty to use jsp2.1 from glassfish instead of jasper fr patch + to allow Jetty to use JSP2.1 from Glassfish instead of Jasper from Tomcat + + refactor httpchannelendpoint in preparation for sslengine refactor + HttpChannelEndPoint in preparation for SslEngine + + reverse order for destroy event listeners reverse order for destroy event + listeners + + simplified jetty.xml with new constructor injections simplified jetty.xml + with new constructor injections + + simplified servlet context api Simplified Servlet Context API + + simplify runtime resolution of jsp library for plugin Simplify runtime + resolution of JSP library for plugin + + ssl algorithm taken from system property Ssl algorithm taken from system + property + + support for singlethreadmodel support + for SingleThreadModel + + support graceful shutdown support graceful shutdown + + threadpool does not need to be a lifecycle Threadpool does not need to be a + LifeCycle + + updated javax code from Updated javax code from http://svn.apache.org/repos/asf/tomcat/tc6.0.x/trunk/java/javax@417727 jetty-6.0.0beta17 - 01 June 2006 - + Added clover reports and enough tests to get >50% coverage - + Added config to disable file memory mapped buffers for windows - + Added Request.isHandled() - + BoundedThreadPool.doStop waits for threads to complete - + Connector lowResourceMaxIdleTime implemented. - + ContextHandler.setConnectors replace setHosts - + Default servlet checks for aliases resources - + don't reset headers during forward - + Fixed IE SSL issue. - + Flush will flush all bytes rather than just some. - + Implemented runAs on servlets - + Protected WEB-INF and META-INF - + Recovered repository from Codehaus crash - + Refactored Synchronization of SelectChannelConnector + + added clover reports and enough tests to get >50% coverage Added clover + reports and enough tests to get >50% coverage + + added config to disable file memory mapped buffers for windows Added config + to disable file memory mapped buffers for windows + + added request.ishandled() Added Request.isHandled() + + boundedthreadpool.dostop waits for threads to complete + BoundedThreadPool.doStop waits for threads to complete + + connector lowresourcemaxidletime implemented. Connector + lowResourceMaxIdleTime implemented. + + contexthandler.setconnectors replace sethosts ContextHandler.setConnectors + replace setHosts + + default servlet checks for aliases resources Default servlet checks for + aliases resources + + don't reset headers during forward don't reset headers during forward + + fixed ie ssl issue. Fixed IE SSL issue. + + flush will flush all bytes rather than just some. Flush will flush all bytes + rather than just some. + + implemented runas on servlets Implemented runAs on servlets + + protected web-inf and meta-inf Protected WEB-INF and META-INF + + recovered repository from codehaus crash Recovered repository from Codehaus + crash + + refactored synchronization of selectchannelconnector Refactored + Synchronization of SelectChannelConnector jetty-6.0.0beta16 - 12 May 2006 - + remove a couple of System.err.printlns - + replace backwards compativle API in UrlEncoded + + remove a couple of system.err.printlns remove a couple of + System.err.printlns + + replace backwards compativle api in urlencoded replace backwards compativle + API in UrlEncoded jetty-6.0.0beta15 - 11 May 2006 - + Added parameter to allow other locations to scan for plugin - + Added automatic scan of all WEB-INF/jetty-*.xml files for plugin - + Added embedded examples - + Added Server attribute org.mortbay.jetty.Request.maxFormContentSize - + Added taglib resources to 2.1 jsp api jar - + Added ThrottlingFilter and fixed race in Continuations - + Added --version to start.jar - + ContextHandler.setContextPath can be called after start. - + don't accept partial authority in request line. - + enforce 204 and 304 have no content - + Fixed handling of params after forward - + Improved HttpException - + improved MBeanContainer object removal - + improved MBean names - + improved support for java5 jconsole - + Major refactor to simplify Server and handler hierarchy - + Moved more resources to resources - + readded BoundedThreadPool shrinking (and then fixed resulting deadlock) - + removed SelectBlockingChannelConnector (unmaintained) - + Renamed NotFoundHandler to DefaultHandler - + Reset of timer task clears expiry - + Session scavenger threads from threadpool - + setSendServerVersion method added to Server to control sending of Server: + + added parameter to allow other locations to scan for plu Added + parameter to allow other locations to scan for plugin + + added automatic scan of all web-inf/jetty-*.xml files for plugin Added + automatic scan of all WEB-INF/jetty-*.xml files for plugin + + added embedded examples Added embedded examples + + added server attribute org.mortbay.jetty.request.maxformcontentsize Added + Server attribute org.mortbay.jetty.Request.maxFormContentSize + + added taglib resources to 2.1 jsp api jar Added taglib resources to 2.1 jsp + api jar + + added throttlingfilter and fixed race in continuations Added + ThrottlingFilter and fixed race in Continuations + + added --version to start.jar Added --version to start.jar + + contexthandler.setcontextpath can be called after start. + ContextHandler.setContextPath can be called after start. + + don't accept partial authority in request line. don't accept partial + authority in request line. + + enforce 204 and 304 have no content enforce 204 and 304 have no content + + fixed handling of params after forward Fixed handling of params after + forward + + improved httpexception Improved HttpException + + improved mbeancontainer object removal improved MBeanContainer object + removal + + improved mbean names improved MBean names + + improved support for java5 jconsole improved support for java5 jconsole + + major refactor to simplify server and handler hierarchy Major refactor to + simplify Server and handler hierarchy + + moved more resources to resources Moved more resources to resources + + readded boundedthreadpool shrinking (and then fixed resulting deadlock + readded BoundedThreadPool shrinking (and then fixed resulting deadlock) + + removed selectblockingchannelconnector (unmaintained) removed + SelectBlockingChannelConnector (unmaintained) + + renamed notfoundhandler to defaulthandler Renamed NotFoundHandler to + DefaultHandler + + reset of timer task clears expiry Reset of timer task clears expiry + + session scavenger threads from threadpool Session scavenger threads from + threadpool + + setsendserverversion method added to server to control sending of serv + setSendServerVersion method added to Server to control sending of Server: http header - + Simplified DefaultServlet static content buffering - + Thread names include URI if debug set + + simplified defaultservlet static content buffering Simplified DefaultServlet + static content buffering + + thread names include uri if debug set Thread names include URI if debug set jetty-6.0.0beta14 - 09 April 2006 - + added configurability for webdefault.xml in maven plugin - + Added Jasper 2.1 as jesper (jasper without JCL) - + added jetty-util.jar module - + Added JSP 2.1 APIs from apache - + added ProxyServlet - + added reset to Continuation - + added support for stopping jetty using "java -jar start.jar --stop" - + adding InvokerServlet - + Change tmp dir of plugin to work to be in line with jetty convention - + fixed forward bug (treated as include) - + fixed HttpField iterator - + fixed priority of port from url over host header - + ignore dirs and files that don't exist in plugin scanner - + implemented request.isUserInRole - + improved contentType handling and test harness - + Modify plugin to select JSP impl at runtime - + moved test webapps to examples directory - + securityHandler removed if not used. - + Started readding logging to jesper using jdk logging - + stop JDBCUserRealm coercing all credentials to String - + Use start.config to select which JSP impl at runtime based on jdk version + + added configurability for webdefault.xml in maven plugin added + configurability for webdefault.xml in maven plugin + + added jasper 2.1 as jesper (jasper without jcl) Added Jasper 2.1 as jesper + (jasper without JCL) + + added jetty-util.jar module added jetty-util.jar module + + added jsp 2.1 apis from apache Added JSP 2.1 APIs from apache + + added proxyservlet added ProxyServlet + + added reset to continuation added reset to Continuation + + added support for stopping jetty using "java -jar start.jar --stop" added + support for stopping jetty using "java -jar start.jar --stop" + + adding invokerservlet adding InvokerServlet + + change tmp dir of plugin to work to be in line with jetty convention Change + tmp dir of plugin to work to be in line with jetty convention + + fixed forward bug (treated as include) fixed forward bug (treated as + include) + + fixed httpfield iterator fixed HttpField iterator + + fixed priority of port from url over host header fixed priority of port from + url over host header + + ignore dirs and files that don't exist in plugin scanner ignore dirs and + files that don't exist in plugin scanner + + implemented request.isuserinrole implemented request.isUserInRole + + improved contenttype handling and test harness improved contentType handling + and test harness + + modify plugin to select jsp impl at runtime Modify plugin to select JSP impl + at runtime + + moved test webapps to examples directory moved test webapps to examples + directory + + securityhandler removed if not used. securityHandler removed if not used. + + started readding logging to jesper using jdk logging Started readding + logging to jesper using jdk logging + + stop jdbcuserrealm coercing all credentials to string stop JDBCUserRealm + coercing all credentials to String + + use start.config to select which jsp impl at runtime based on jdk vers Use + start.config to select which JSP impl at runtime based on jdk version jetty-6.0.0beta12 - 16 March 2006 - + Added JSP2.0 demos to test webapp - + Added provider support to SslListener - + Fixed error handling in error page - + Fixed JettyPlus for root contexts - + Fixed maven plugin JNDI for redeploys - + Fixed tld discovery for plugin (search dependencies) - + Log ERROR for runtimeExceptions - + Upgraded jasper to 5.5.15 + + added jsp2.0 demos to test webapp Added JSP2.0 demos to test webapp + + added provider support to ssllistener Added provider support to SslListener + + fixed error handling in error page Fixed error handling in error page + + fixed jettyplus for root contexts Fixed JettyPlus for root contexts + + fixed maven plugin jndi for redeploys Fixed maven plugin JNDI for redeploys + + fixed tld discovery for plugin (search dependencies) Fixed tld discovery for + plugin (search dependencies) + + log error for runtimeexceptions Log ERROR for runtimeExceptions + + upgraded jasper to 5.5.15 Upgraded jasper to 5.5.15 jetty-6.0.0beta11 - 14 March 2006 - + Added HttpURI and improved UTF-8 parsing. - + added JAAS - + added missing Configurations for maven plugin - + added patch to use joda-time - + added webapp-specific JNDI entries - + fixed ; decoding in URIs - + fixed FORM authentication - + moved dtd and xsd to standard javax location - + refactored configuration files and start() - + refactored session ID management - + refactored writers and improved UTF-8 generation. + + added httpuri and improved utf-8 parsing. Added HttpURI and improved UTF-8 + parsing. + + added jaas added JAAS + + added missing configurations for maven plugin added missing Configurations + for maven plugin + + added patch to use joda-time added patch to use joda-time + + added webapp-specific jndi entries added webapp-specific JNDI entries + + fixed ; decoding in uris fixed ; decoding in URIs + + fixed form authentication fixed FORM authentication + + moved dtd and xsd to standard javax location moved dtd and xsd to standard + javax location + + refactored configuration files and start() refactored configuration files + and start() + + refactored session id management refactored session ID management + + refactored writers and improved utf-8 generation. refactored writers and + improved UTF-8 generation. jetty-6.0.0beta10 - 25 February 2006 - + added getLocalPort() to connector - + Added support for java:comp/env - + Added support for pluggable transaction manager - + Additional accessors for request logging - + Fixed content-type for range requests - + Fixed default servlet handling of includes - + Fix for myfaces and include with close - + Fix for sf1435795 30sec delay from c taylor - + Fix http://jira.codehaus.org/browse/JETTY-6. hi byte reader - + Fix sf1431936 don't chunk the chunk - + Forward masks include attributes and vice versa - + Updates javax to MR2 release + + added getlocalport() to connector added getLocalPort() to connector + + added support for java:comp/env Added support for java:comp/env + + added support for pluggable transaction manager Added support for pluggable + transaction manager + + additional accessors for request logging Additional accessors for request + logging + + fixed content-type for range requests Fixed content-type for range requests + + fixed default servlet handling of includes Fixed default servlet handling of + includes + + fix for myfaces and include with close Fix for myfaces and include with + close + + fix for sf1435795 30sec delay from c taylor Fix for sf1435795 30sec delay + from c taylor + + fix http://jira.codehaus.org/browse/jetty-6. hi byte reader Fix + http://jira.codehaus.org/browse/JETTY-6. hi byte reader + + fix sf1431936 don't chunk the chunk Fix sf1431936 don't chunk the chunk + + forward masks include attributes and vice versa Forward masks include + attributes and vice versa + + updates javax to mr2 release Updates javax to MR2 release jetty-6.0.0beta9 - 09 February 2006 - + Added CGI servlet. - + Added request log. - + Added TLD tag listener handling. - + Continuation cleanup - + Fixed dispatch of wrapped requests. - + Fixed double flush of short content. - + fixed setLocale bug sf1426940 - + Fixed unraw decoding of query string - + Force a tempdir to be set. - + Force jasper scratch dir. - + PathMap for direct context mapping. - + Refactored chat demo and upgraded prototype.js + + added cgi servlet. Added CGI servlet. + + added request log. Added request log. + + added tld tag listener handling. Added TLD tag listener handling. + + continuation cleanup Continuation cleanup + + fixed dispatch of wrapped requests. Fixed dispatch of wrapped requests. + + fixed double flush of short content. Fixed double flush of short content. + + fixed setlocale bug sf1426940 fixed setLocale bug sf1426940 + + fixed unraw decoding of query string Fixed unraw decoding of query string + + force a tempdir to be set. Force a tempdir to be set. + + force jasper scratch dir. Force jasper scratch dir. + + pathmap for direct context mapping. PathMap for direct context mapping. + + refactored chat demo and upgraded prototype.js Refactored chat demo and + upgraded prototype.js jetty-6.0.0beta8 - 24 January 2006 - + conveniance addHandler removeHandler methods - + fixed bug in overloaded write method on HttpConnection (reported against + + conveniance addhandler removehandler methods conveniance addHandler + removeHandler methods + + fixed bug in overloaded write method on httpconnection (reported again fixed + bug in overloaded write method on HttpConnection (reported against Tapestry4.0) - + fixed dispatch of new session problem. sf:1407090 - + Handle pipeline requests without hangs - + hid org.apache.commons.logging and org.slf4j packages from webapp - + improve buffer return mechanism. - + improved caching of content types + + fixed dispatch of new session problem. sf:1407090 fixed dispatch of new + session problem. sf:1407090 + + handle pipeline requests without hangs Handle pipeline requests without + hangs + + hid org.apache.commons.logging and org.slf4j packages from webapp hid + org.apache.commons.logging and org.slf4j packages from webapp + + improve buffer return mechanism. improve buffer return mechanism. + + improved caching of content types improved caching of content types + maven-jetty6-plugin: ensure compile is done before invoking jetty + maven-jetty6-plugin: ensure compile is done before invoking jetty + maven-jetty6-plugin: support all types of artifact dependencies + maven-jetty6-plugin: support all types of artifact dependencies + maven-jetty6-plugin stopped transitive inclusion of log4j and + maven-jetty6-plugin stopped transitive inclusion of log4j and commons-logging from commons-el for jasper - + patch to remove spurious ; in HttpFields - + reinstated rfc2616 test harness - + Removed queue from thread pool. + + patch to remove spurious ; in httpfields patch to remove spurious ; in + HttpFields + + reinstated rfc2616 test harness reinstated rfc2616 test harness + + removed queue from thread pool. Removed queue from thread pool. jetty-6.0.0Beta7 - + Faster header name lookup - + Fixed infinite loop with chunk handling - + maven-jetty6-plugin added tmpDirectory property - + maven-jetty6-plugin stopped throwing an error if there is no target/classes + + faster header name lookup Faster header name lookup + + fixed infinite loop with chunk handling Fixed infinite loop with chunk + handling + + maven-jetty6-plugin added tmpdirectory property maven-jetty6-plugin added + tmpDirectory property + + maven-jetty6-plugin stopped throwing an error if there is no target/cl + maven-jetty6-plugin stopped throwing an error if there is no target/classes directory - + null dispatch attributes not in names - + reduced info verbosity - + removed singleton Container + + null dispatch attributes not in names null dispatch attributes not in names + + reduced info verbosity reduced info verbosity + + removed singleton container removed singleton Container jetty-6.0.0Beta6 - + Fixed issue with blocking reads - + Fixed issue with unknown headers - + optimizations + + fixed issue with blocking reads Fixed issue with blocking reads + + fixed issue with unknown headers Fixed issue with unknown headers + + optimizations optimizations jetty-6.0.0Beta5 - + Added management module for mbeans - + Fixed writer char[] creations - + Moved to SVN + + added management module for mbeans Added management module for mbeans + + fixed writer char[] creations Fixed writer char[] creations + + moved to svn Moved to SVN jetty-6.0.0Beta4 - + CVE-2006-2758 Fixed JSP visibility security issue. - + Improved jetty-web.xml access to org.mortbay classes. - + Jasper 5.5.12 - + System property support in plugin + + cve-2006-2758 fixed jsp visibility security issue. CVE-2006-2758 Fixed JSP + visibility security issue. + + improved jetty-web.xml access to org.mortbay classes. Improved jetty-web.xml + access to org.mortbay classes. + + jasper 5.5.12 Jasper 5.5.12 + + system property support in plugin System property support in plugin jetty-6.0.0Beta3 - + Fixed classloader issue with server classes - + Fixed error in block read - + Named dispatch. + + fixed classloader issue with server classes Fixed classloader issue with + server classes + + fixed error in block read Fixed error in block read + + named dispatch. Named dispatch. jetty-6.0.0Beta2 - + Improved buffer return - + Improved reuse of HttpField values and cookies. - + loosely coupled with JSP servlet - + loosely coupled with SLF4J - + merged util jar back into jetty jar - + Simpler continuation API + + improved buffer return Improved buffer return + + improved reuse of httpfield values and cookies. Improved reuse of HttpField + values and cookies. + + loosely coupled with jsp servlet loosely coupled with JSP servlet + + loosely coupled with slf4j loosely coupled with SLF4J + + merged util jar back into jetty jar merged util jar back into jetty jar + + simpler continuation api Simpler continuation API jetty-6.0.0Beta1 - + Error pages - + Implemented all listeners - + maven2 plugin - + Multiple select sets - + refactored start/stop - + Servlet 2.5 API - + shutdown hook - + SSL connector - + Virtual hosts + + error pages Error pages + + implemented all listeners Implemented all listeners + + maven2 plugin maven2 plugin + + multiple select sets Multiple select sets + + refactored start/stop refactored start/stop + + servlet 2.5 api Servlet 2.5 API + + shutdown hook shutdown hook + + ssl connector SSL connector + + virtual hosts Virtual hosts jetty-6.0.0Beta0 - + Dispatcher parameters - + Fixed blocking read - + Maven 2 build - + UTF-8 encoding for URLs + + dispatcher parameters Dispatcher parameters + + fixed blocking read Fixed blocking read + + maven 2 build Maven 2 build + + utf-8 encoding for urls UTF-8 encoding for URLs jetty-6.0.0APLPA3 - + Added demo for Continuations - + Jasper and associated libraries. + + added demo for continuations Added demo for Continuations + + jasper and associated libraries. Jasper and associated libraries. jetty-6.0.0ALPHA2 - + Continuations - way cool way to suspend a request and retry later. - + Dispatchers - + Security + + continuations - way cool way to suspend a request and retry later. + Continuations - way cool way to suspend a request and retry later. + + dispatchers Dispatchers + + security Security jetty-6.0.0ALPHA1 - + Filters - + web.xml handling + + filters Filters + + web.xml handling web.xml handling jetty-6.0.0ALPHA0 - + file may be sent as sent is a single operation. - + Improved "dependancy injection" and "inversion of control" design of + + file may be sent as sent is a single operation. file may be sent as sent is + a single operation. + + improved "dependancy injection" and "inversion of control" design of + Improved "dependancy injection" and "inversion of control" design of components - + Improved "interceptor" design of handlers - + Missing Request Dispatchers - + Missing Security - + Missing war support - + Missing web.xml based configuration - + Optional use of NIO Buffering so that efficient direct buffers and memory + + improved "interceptor" design of handlers Improved "interceptor" design of + handlers + + missing request dispatchers Missing Request Dispatchers + + missing security Missing Security + + missing war support Missing war support + + missing web.xml based configuration Missing web.xml based configuration + + optional use of nio buffering so that efficient direct buffers and mem + Optional use of NIO Buffering so that efficient direct buffers and memory mapped files can be used. - + Optional use of NIO gather writes, so that for example a HTTP header and a + + optional use of nio gather writes, so that for example a http header a + Optional use of NIO gather writes, so that for example a HTTP header and a memory mapped - + Optional use of NIO non-blocking scheduling so that threads are not - allocated per connection. - + Smart split buffer design allows large buffers to only be allocated to - active connections. The resulting memory savings allow very large buffers to - be used, which increases the chance of efficient asynchronous flushing and - of avoiding chunking. - + Totally rearchitected and rebuilt, so 10 years of cruft could be removed! + + optional use of nio non-blocking scheduling so that threads are not Optional + use of NIO non-blocking scheduling so that threads are not allocated per + connection. + + smart split buffer design allows large buffers to only be allocated to Smart + split buffer design allows large buffers to only be allocated to active + connections. The resulting memory savings allow very large buffers to be + used, which increases the chance of efficient asynchronous flushing and of + avoiding chunking. + + totally rearchitected and rebuilt, so 10 years of cruft could be remov + Totally rearchitected and rebuilt, so 10 years of cruft could be removed! jetty-5.1.11RC0 - 05 April 2006 - + Added provider support to SslListener - + Fixed AJP handling of ;jsessionid. - + force close with shutdownOutput for win32 - + improved contentType param handling - + logging improvements for servlet and runtime exceptions - + NPE protection if desirable client certificates - + stop JDBCUserRealm forcing all credentials to be String + + added provider support to ssllistener Added provider support to SslListener + + fixed ajp handling of ;jsessionid. Fixed AJP handling of ;jsessionid. + + force close with shutdownoutput for win32 force close with shutdownOutput + for win32 + + improved contenttype param handling improved contentType param handling + + logging improvements for servlet and runtime exceptions logging improvements + for servlet and runtime exceptions + + npe protection if desirable client certificates NPE protection if desirable + client certificates + + stop jdbcuserrealm forcing all credentials to be string stop JDBCUserRealm + forcing all credentials to be String jetty-5.1.10 - 05 January 2006 - + Fixed path aliasing with // on windows. - + Fix for AJP13 with encoded path - + Fix for AJP13 with multiple headers - + Put POST content default back to iso_8859_1. GET is UTF-8 still - + Remove null dispatch attributes from getAttributeNames + + fixed path aliasing with // on windows. Fixed path aliasing with // on + windows. + + fix for ajp13 with encoded path Fix for AJP13 with encoded path + + fix for ajp13 with multiple headers Fix for AJP13 with multiple headers + + put post content default back to iso_8859_1. get is utf-8 still Put POST + content default back to iso_8859_1. GET is UTF-8 still + + remove null dispatch attributes from getattributenames Remove null dispatch + attributes from getAttributeNames jetty-4.2.25 - 04 January 2006 - + Fixed aliasing of // for win32 + + fixed aliasing of // for win32 Fixed aliasing of // for win32 jetty-5.1.9 - 07 December 2005 - + Fixed wantClientAuth(false) overriding netClientAuth(true) + + fixed wantclientauth(false) overriding netclientauth(true) Fixed + wantClientAuth(false) overriding netClientAuth(true) jetty-6.0.0betaX - + See http://jetty.mortbay.org/jetty6 for 6.0 releases + + see http://jetty.mortbay.org/jetty6 for 6.0 releases See + http://jetty.mortbay.org/jetty6 for 6.0 releases jetty-5.1.8 - 07 December 2005 - + Fixed space in URL issued created in 5.1.6 + + fixed space in url issued created in 5.1.6 Fixed space in URL issued created + in 5.1.6 jetty-5.1.7 - 07 December 2005 jetty-5.1.7rc0 - 06 December 2005 - + better support for URI character encodings - + char encoding for MultiPartRequest - + fixed merging of POST params in dispatch query string. - + improved server stats - + JSP file servlet mappings copy JspServlet init params. - + Prefix servlet context logs with org.mortbay.jetty.context - + protect from NPE in dispatcher getValues - + Updated to 2.6.2 xerces - + use commons logging jar instead of api jar. + + better support for uri character encodings better support for URI character + encodings + + char encoding for multipartrequest char encoding for MultiPartRequest + + fixed merging of post params in dispatch query string. fixed merging of POST + params in dispatch query string. + + improved server stats improved server stats + + jsp file servlet mappings copy jspservlet init params. JSP file servlet + mappings copy JspServlet init params. + + prefix servlet context logs with org.mortbay.jetty.context Prefix servlet + context logs with org.mortbay.jetty.context + + protect from npe in dispatcher getvalues protect from NPE in dispatcher + getValues + + updated to 2.6.2 xerces Updated to 2.6.2 xerces + + use commons logging jar instead of api jar. use commons logging jar instead + of api jar. jetty-5.1.6 - 18 November 2005 - + CVE-2006-2758 Fixed JSP visibility security issue. - + Improved jetty-web.xml access to org.mortbay classes. + + cve-2006-2758 fixed jsp visibility security issue. CVE-2006-2758 Fixed JSP + visibility security issue. + + improved jetty-web.xml access to org.mortbay classes. Improved jetty-web.xml + access to org.mortbay classes. jetty-5.1.5 - 10 November 2005 - + Improved mapping of JSP files. - + Improved shutdown hook - + Improved URL Decoding + + improved mapping of jsp files. Improved mapping of JSP files. + + improved shutdown hook Improved shutdown hook + + improved url decoding Improved URL Decoding jetty-5.1.5rc2 - 07 October 2005 - + ProxyHandler can handle chained proxies - + public ServerMBean constructor - + ReFixed merge of Dispatcher params - + Response.setLocale will set locale even if getWriter called. - + Reverted dispatcher params to RI rather than spec behaviour. - + unsynchronized ContextLoader - + UTF-8 encoding for URLs + + proxyhandler can handle chained proxies ProxyHandler can handle chained + proxies + + public servermbean constructor public ServerMBean constructor + + refixed merge of dispatcher params ReFixed merge of Dispatcher params + + response.setlocale will set locale even if getwriter called. + Response.setLocale will set locale even if getWriter called. + + reverted dispatcher params to ri rather than spec behaviour. Reverted + dispatcher params to RI rather than spec behaviour. + + unsynchronized contextloader unsynchronized ContextLoader + + utf-8 encoding for urls UTF-8 encoding for URLs jetty-5.1.5rc1 - 23 August 2005 - + Encoded full path in ResourceHandler directory listing - + Fixed 100-continues with chunking and early commit - + Fixed illegal state with chunks and 100 continue - Tony Seebregts - + Fixed merge of Dispatcher parameters - + Fixed PKCS12Import input string method - + handle extra params after charset in header - + Release commons logging factories when stopping context. - + upgraded to commons logging 1.0.4 + + encoded full path in resourcehandler directory listing Encoded full path in + ResourceHandler directory listing + + fixed 100-continues with chunking and early commit Fixed 100-continues with + chunking and early commit + + fixed illegal state with chunks and 100 continue - tony seebregts Fixed + illegal state with chunks and 100 continue - Tony Seebregts + + fixed merge of dispatcher parameters Fixed merge of Dispatcher parameters + + fixed pkcs12import input string method Fixed PKCS12Import input string + method + + handle extra params after charset in header handle extra params after + charset in header + + release commons logging factories when stopping context. Release commons + logging factories when stopping context. + + upgraded to commons logging 1.0.4 upgraded to commons logging 1.0.4 jetty-5.1.5rc0 - 16 August 2005 - + Applied ciphersuite patch from tonyj - + Authenticators use servlet sendError - + CGI sets SCRIPT_FILENAME - + Expect continues only sent if input is read. - + Facade over commons LogFactory so that discovery may be avoided. - + Fixed component remove memory leak for stop/start cycles - + HttpTunnel timeout - + NPE protection for double stop in ThreadedServer + + applied ciphersuite patch from tonyj Applied ciphersuite patch from tonyj + + authenticators use servlet senderror Authenticators use servlet sendError + + cgi sets script_filename CGI sets SCRIPT_FILENAME + + expect continues only sent if input is read. Expect continues only sent if + input is read. + + facade over commons logfactory so that discovery may be avoided. Facade over + commons LogFactory so that discovery may be avoided. + + fixed component remove memory leak for stop/start cycles Fixed component + remove memory leak for stop/start cycles + + httptunnel timeout HttpTunnel timeout + + npe protection for double stop in threadedserver NPE protection for double + stop in ThreadedServer jetty-5.1.4 - 05 June 2005 - + Change JAAS impl to be more flexible on finding roles - + Fixed FTP close issue. - + ModelMBean handles null signatures - + NPE protection in ThreadedServer - + set classloader during webapp doStop - + setup MX4J with JDK1.5 in start.config + + change jaas impl to be more flexible on finding roles Change JAAS impl to be + more flexible on finding roles + + fixed ftp close issue. Fixed FTP close issue. + + modelmbean handles null signatures ModelMBean handles null signatures + + npe protection in threadedserver NPE protection in ThreadedServer + + set classloader during webapp dostop set classloader during webapp doStop + + setup mx4j with jdk1.5 in start.config setup MX4J with JDK1.5 in + start.config jetty-5.1.4rc0 - 19 April 2005 - + Allow ServletHandler in normal HttpContext again. - + HttpServer delegates component handling to Container. - + More protection from null classloaders. - + ServletHttpContext correctly calls super.doStop. - + Stop start.jar putting current directory on classpath. - + Turn off web.xml validation for JBoss. + + allow servlethandler in normal httpcontext again. Allow ServletHandler in + normal HttpContext again. + + httpserver delegates component handling to container. HttpServer delegates + component handling to Container. + + more protection from null classloaders. More protection from null + classloaders. + + servlethttpcontext correctly calls super.dostop. ServletHttpContext + correctly calls super.doStop. + + stop start.jar putting current directory on classpath. Stop start.jar + putting current directory on classpath. + + turn off web.xml validation for jboss. Turn off web.xml validation for + JBoss. jetty-5.1.3 - 07 April 2005 - + Some minor code janitorial services + + some minor code janitorial services Some minor code janitorial services jetty-4.2.24 - 07 April 2005 jetty-5.1.3rc4 - 31 March 2005 - + Allow XmlConfiguration to start with no object. - + make java:comp/env immutable for webapps as per J2EE spec - + Moved servlet request wrapping to enterContextScope for geronimo security - + refixed / mapping for filters - + rework InitialContextFactory to use static 'default' namespace - + updated to mx4j 3.0.1 + + allow xmlconfiguration to start with no object. Allow XmlConfiguration to + start with no object. + + make java:comp/env immutable for webapps as per j2ee spec make java:comp/env + immutable for webapps as per J2EE spec + + moved servlet request wrapping to entercontextscope for geronimo secur Moved + servlet request wrapping to enterContextScope for geronimo security + + refixed / mapping for filters refixed / mapping for filters + + rework initialcontextfactory to use static 'default' namespace rework + InitialContextFactory to use static 'default' namespace + + updated to mx4j 3.0.1 updated to mx4j 3.0.1 jetty-5.1.3rc3 - 20 March 2005 - + fixed "No getter or setter found" mbean errors - + removed accidental enablement of DEBUG for JettyPlus jndi in - log4j.properties + + fixed "no getter or setter found" mbean errors fixed "No getter or setter + found" mbean errors + + removed accidental enablement of debug for jettyplus jndi in removed + accidental enablement of DEBUG for JettyPlus jndi in log4j.properties jetty-5.1.3rc2 - 16 March 2005 - + Fixed context to _context refactory error - + Updated JSR154Filter for ERROR dispatch + + fixed context to _context refactory error Fixed context to _context + refactory error + + updated jsr154filter for error dispatch Updated JSR154Filter for ERROR + dispatch jetty-5.1.3rc1 - 13 March 2005 - + Fixed principal naming in FormAuthenticator - + Fixed typo in context-param handling. - + JettyPlus updated to JOTM 2.0.5, XAPool 1.4.2 - + update to demo site look and feel. + + fixed principal naming in formauthenticator Fixed principal naming in + FormAuthenticator + + fixed typo in context-param handling. Fixed typo in context-param handling. + + jettyplus updated to jotm 2.0.5, xapool 1.4.2 JettyPlus updated to JOTM + 2.0.5, XAPool 1.4.2 + + update to demo site look and feel. update to demo site look and feel. jetty-4.2.24rc1 - + Fixed principal naming in FormAuthenticator + + fixed principal naming in formauthenticator Fixed principal naming in + FormAuthenticator jetty-5.1.3rc0 - 08 March 2005 - + Added logCookie and logLatency support to NCSARequestLog - + Added new JAAS callback to allow extra login form fields in authentication - + Added simple xpath support to XmlParser - + Added SslListener for 1.4 JSSE API. - + Added TagLibConfiguration to search for listeners in TLDs. - + Allow system and server classes to be configured for context loader. - + Fixed HTAccess crypt salt handling. - + Fixed JSR154 error dispatch with explicit pass of type. - + Fixed moderate load preventing ThreadPool shrinking. - + Fixed rollover filename format bug - + Flush filter chain caches on servlet/filter change - + IOException if EOF read during chunk. + + added logcookie and loglatency support to ncsarequestlog Added logCookie and + logLatency support to NCSARequestLog + + added new jaas callback to allow extra login form fields in authentica Added + new JAAS callback to allow extra login form fields in authentication + + added simple xpath support to xmlparser Added simple xpath support to + XmlParser + + added ssllistener for 1.4 jsse api. Added SslListener for 1.4 JSSE API. + + added taglibconfiguration to search for listeners in tlds. Added + TagLibConfiguration to search for listeners in TLDs. + + allow system and server classes to be configured for context loader. Allow + system and server classes to be configured for context loader. + + fixed htaccess crypt salt handling. Fixed HTAccess crypt salt handling. + + fixed jsr154 error dispatch with explicit pass of type. Fixed JSR154 error + dispatch with explicit pass of type. + + fixed moderate load preventing threadpool shrinking. Fixed moderate load + preventing ThreadPool shrinking. + + fixed rollover filename format bug Fixed rollover filename format bug + + flush filter chain caches on servlet/filter change Flush filter chain caches + on servlet/filter change + + ioexception if eof read during chunk. IOException if EOF read during chunk. jetty-4.2.24rc0 - 08 March 2005 - + Added logCookie and logLatency support to NCSARequestLog - + Back ported Jetty 5 ThreadedServer and ThreadPool + + added logcookie and loglatency support to ncsarequestlog Added logCookie and + logLatency support to NCSARequestLog + + back ported jetty 5 threadedserver and threadpool Back ported Jetty 5 + ThreadedServer and ThreadPool jetty-5.1.2 - 18 January 2005 - + Added id and ref support to XmlConfiguration - + Apply patch #1103953 - + Cleaned up AbstractSessionManager synchronization. - + Fixed potential concurrent login problem with JAAS + + added id and ref support to xmlconfiguration Added id and ref support to + XmlConfiguration + + 1103953 Apply patch #1103953 + + cleaned up abstractsessionmanager synchronization. Cleaned up + AbstractSessionManager synchronization. + + fixed potential concurrent login problem with jaas Fixed potential + concurrent login problem with JAAS jetty-4.2.23 - 16 January 2005 - + Cleaned up AbstractSessionManager synchronization. - + Fixed potential concurrent login problem with JAAS + + cleaned up abstractsessionmanager synchronization. Cleaned up + AbstractSessionManager synchronization. + + fixed potential concurrent login problem with jaas Fixed potential + concurrent login problem with JAAS jetty-5.1.2pre0 - 22 December 2004 - + Added global invalidation to AbstractSessionManager - + Fixed case of Cookie parameters - + Fixed suffix filters - + Modified useRequestedID handling to only use IDs from other contexts - + Support Secure and HttpOnly in session cookies - + UnavailableException handling from handle + + added global invalidation to abstractsessionmanager Added global + invalidation to AbstractSessionManager + + fixed case of cookie parameters Fixed case of Cookie parameters + + fixed suffix filters Fixed suffix filters + + modified userequestedid handling to only use ids from other contexts + Modified useRequestedID handling to only use IDs from other contexts + + support secure and httponly in session cookies Support Secure and HttpOnly + in session cookies + + unavailableexception handling from handle UnavailableException handling from + handle jetty-4.2.23RC0 - 17 December 2004 - + Added LogStream to capture stderr and stdout to logging - + Build unsealed jars - + LineInput handles readers with small internal buffer - + Support Secure and HttpOnly in session cookies + + added logstream to capture stderr and stdout to logging Added LogStream to + capture stderr and stdout to logging + + build unsealed jars Build unsealed jars + + lineinput handles readers with small internal buffer LineInput handles + readers with small internal buffer + + support secure and httponly in session cookies Support Secure and HttpOnly + in session cookies jetty-5.1.1 - 01 December 2004 jetty-5.1.1RC1 - + Allow double // within URIs - + Applied patch for MD5 hashed credentials for MD5 - + Fixed ordering of filters with multiple interleaved mappings. - + Made more WebApplicationHandle configuration methods public. - + Some minor findbugs code cleanups + + allow double // within uris Allow double // within URIs + + applied patch for md5 hashed credentials for md5 Applied patch for MD5 + hashed credentials for MD5 + + fixed ordering of filters with multiple interleaved mappings. Fixed ordering + of filters with multiple interleaved mappings. + + made more webapplicationhandle configuration methods public. Made more + WebApplicationHandle configuration methods public. + + some minor findbugs code cleanups Some minor findbugs code cleanups jetty-5.1.1RC0 - 17 November 2004 - + added new contributed shell start/stop script - + excluded ErrorPageHandler from standard build in extra/jdk1.2 build - + fix commons logging imports to IbmJsseListener - + fix for adding recognized EventListeners + + added new contributed shell start/stop script added new contributed shell + start/stop script + + excluded errorpagehandler from standard build in extra/jdk1.2 build excluded + ErrorPageHandler from standard build in extra/jdk1.2 build + + fix commons logging imports to ibmjsselistener fix commons logging imports + to IbmJsseListener + + fix for adding recognized eventlisteners fix for adding recognized + EventListeners jetty-5.1.0 - 14 November 2004 jetty-5.1.RC1 - 24 October 2004 - + Allow JSSE listener to be just confidential or just integral. - + Allow multiple accepting threads - + Build unsealed jars - + default / mapping does not apply to Filters - + Fixed NPE for null contenttype - + improved clean targets - + many minor cleanups suggested from figbug utility - + Partially flush writers on every write so content length can be detected. - + when committed setHeader is a noop rather than IllegalStateException + + allow jsse listener to be just confidential or just integral. Allow JSSE + listener to be just confidential or just integral. + + allow multiple accepting threads Allow multiple accepting threads + + build unsealed jars Build unsealed jars + + default / mapping does not apply to filters default / mapping does not apply + to Filters + + fixed npe for null contenttype Fixed NPE for null contenttype + + improved clean targets improved clean targets + + many minor cleanups suggested from figbug utility many minor cleanups + suggested from figbug utility + + partially flush writers on every write so content length can be detect + Partially flush writers on every write so content length can be detected. + + when committed setheader is a noop rather than illegalstateexception when + committed setHeader is a noop rather than IllegalStateException jetty-5.1.RC0 - 11 October 2004 - + Added filter chain cache - + Added JSR77 servlet statistic support - + Added LifeCycle events and generic container. - + Added LogStream to capture stderr and stdout to logging - + Fixed HTAccessHandler - + Fixed many minor issues from J2EE 1.4 TCK testing See sf.net bugs 1031520 - + + added filter chain cache Added filter chain cache + + added jsr77 servlet statistic support Added JSR77 servlet statistic support + + added lifecycle events and generic container. Added LifeCycle events and + generic container. + + added logstream to capture stderr and stdout to logging Added LogStream to + capture stderr and stdout to logging + + fixed htaccesshandler Fixed HTAccessHandler + + fixed many minor issues from j2ee 1.4 tck testing see sf.net bugs 1031 Fixed + many minor issues from J2EE 1.4 TCK testing See sf.net bugs 1031520 - 1032205 - + JBoss 4.0.0 support - + LineInput handles readers with small internal buffer - + Refactored, simplified and optimized HttpOutputStream - + Refactored webapp context configurations - + Upgraded to ant-1.6 for jasper + + jboss 4.0.0 support JBoss 4.0.0 support + + lineinput handles readers with small internal buffer LineInput handles + readers with small internal buffer + + refactored, simplified and optimized httpoutputstream Refactored, simplified + and optimized HttpOutputStream + + refactored webapp context configurations Refactored webapp context + configurations + + upgraded to ant-1.6 for jasper Upgraded to ant-1.6 for jasper jetty-5.0.0 - 10 September 2004 jetty-5.0.RC4 - 05 September 2004 - + Fixed configuration of URL alias checking - + JettyJBoss: Use realm-name from web.xml if present, otherwise use + + fixed configuration of url alias checking Fixed configuration of URL alias + checking + + jettyjboss: use realm-name from web.xml if present, otherwise use + JettyJBoss: Use realm-name from web.xml if present, otherwise use security-domain from jboss-web.xml jetty-5.0.RC3 - 28 August 2004 - + Added parameters for acceptQueueSize and lowResources level. - + Always say close for HTTP/1.0 non keep alive. - + Changed default URI encoding to UTF-8 - + DIGEST auth handles qop, stale and maxNonceAge. - + fixed deployment of ejb-link elements in web.xml with jboss - + fixed jaas logout for jetty-jboss - + Fixes to work with java 1.5 - + JettyPlus addition of pluggable DataSources - + JettyPlus upgrade to XAPool 1.3.3. and HSQLDB 1.7.2 - + Less verbose warning for non validating xml parser. - + Update to jasper 5.0.27 + + added parameters for acceptqueuesize and lowresources level. Added + parameters for acceptQueueSize and lowResources level. + + always say close for http/1.0 non keep alive. Always say close for HTTP/1.0 + non keep alive. + + changed default uri encoding to utf-8 Changed default URI encoding to UTF-8 + + digest auth handles qop, stale and maxnonceage. DIGEST auth handles qop, + stale and maxNonceAge. + + fixed deployment of ejb-link elements in web.xml with jboss fixed deployment + of ejb-link elements in web.xml with jboss + + fixed jaas logout for jetty-jboss fixed jaas logout for jetty-jboss + + fixes to work with java 1.5 Fixes to work with java 1.5 + + jettyplus addition of pluggable datasources JettyPlus addition of pluggable + DataSources + + jettyplus upgrade to xapool 1.3.3. and hsqldb 1.7.2 JettyPlus upgrade to + XAPool 1.3.3. and HSQLDB 1.7.2 + + less verbose warning for non validating xml parser. Less verbose warning for + non validating xml parser. + + update to jasper 5.0.27 Update to jasper 5.0.27 jetty-4.2.22 - + Added parameters for acceptQueueSize and lowResources level. - + fixed deployment of ejb-link elements in web.xml for jboss - + fixed jaas logout for jetty-jboss integration + + added parameters for acceptqueuesize and lowresources level. Added + parameters for acceptQueueSize and lowResources level. + + fixed deployment of ejb-link elements in web.xml for jboss fixed deployment + of ejb-link elements in web.xml for jboss + + fixed jaas logout for jetty-jboss integration fixed jaas logout for + jetty-jboss integration jetty-5.0.RC2 - 02 July 2004 - + add JMX support for JettyPlus - + add listing of java:comp/env for webapp with JMX - + Default servlet may use only pathInfo for resource - + Error dispatchers are always GET requests. - + Fixed DIGEST challenge delimiters - + Fixed JAAS logout - + Fixed no-role security constraint combination. - + Fixed session leak in j2ee - + Fix to use runas roles during servlet init and destroy - + HTAccess calls UnixCrypt correctly - + HttpContext sendError for authentication errors - + integrated jetty-jboss with jboss-3.2.4 - + make choice of override of JNDI ENC entries: config.xml or web.xml - + OPTIONS works for all URLs on default servlet + + add jmx support for jettyplus add JMX support for JettyPlus + + add listing of java:comp/env for webapp with jmx add listing of + java:comp/env for webapp with JMX + + default servlet may use only pathinfo for resource Default servlet may use + only pathInfo for resource + + error dispatchers are always get requests. Error dispatchers are always GET + requests. + + fixed digest challenge delimiters Fixed DIGEST challenge delimiters + + fixed jaas logout Fixed JAAS logout + + fixed no-role security constraint combination. Fixed no-role security + constraint combination. + + fixed session leak in j2ee Fixed session leak in j2ee + + fix to use runas roles during servlet init and destroy Fix to use runas + roles during servlet init and destroy + + htaccess calls unixcrypt correctly HTAccess calls UnixCrypt correctly + + httpcontext senderror for authentication errors HttpContext sendError for + authentication errors + + integrated jetty-jboss with jboss-3.2.4 integrated jetty-jboss with + jboss-3.2.4 + + make choice of override of jndi enc entries: config.xml or web.xml make + choice of override of JNDI ENC entries: config.xml or web.xml + + options works for all urls on default servlet OPTIONS works for all URLs on + default servlet jetty-4.2.21 - 02 July 2004 - + add JMX support for JettyPlus - + add listing of java:comp/env for webapp with JMX - + Fixed JAAS logout - + integrated jetty-jboss with jboss-3.2.4 - + make choice of override of JNDI ENC entries: config.xml or web.xml + + add jmx support for jettyplus add JMX support for JettyPlus + + add listing of java:comp/env for webapp with jmx add listing of + java:comp/env for webapp with JMX + + fixed jaas logout Fixed JAAS logout + + integrated jetty-jboss with jboss-3.2.4 integrated jetty-jboss with + jboss-3.2.4 + + make choice of override of jndi enc entries: config.xml or web.xml make + choice of override of JNDI ENC entries: config.xml or web.xml jetty-5.0.RC1 - 24 May 2004 - + added extra/etc/start-plus.config to set up main.class for jettyplus - + Changed to apache 2.0 license - + Fixed HTTP tunnel timeout setting. - + FORM auth redirects to context on a re-auth - + Handle multiple virutal hosts from JBoss 3.2.4RC2 - + Improved handling of exception from servlet init. - + maxFormContentLength may be unlimited with <0 value + + added extra/etc/start-plus.config to set up main.class for jettyplus added + extra/etc/start-plus.config to set up main.class for jettyplus + + changed to apache 2.0 license Changed to apache 2.0 license + + fixed http tunnel timeout setting. Fixed HTTP tunnel timeout setting. + + form auth redirects to context on a re-auth FORM auth redirects to context + on a re-auth + + handle multiple virutal hosts from jboss 3.2.4rc2 Handle multiple virutal + hosts from JBoss 3.2.4RC2 + + improved handling of exception from servlet init. Improved handling of + exception from servlet init. + + maxformcontentlength may be unlimited with <0 value maxFormContentLength may + be unlimited with <0 value jetty-4.2.20 - 22 May 2004 - + Fixed HTTP tunnel timeout setting. - + FORM auth redirects to context on a re-auth - + Improved handling of exception from servlet init. - + maxFormContentLength may be unlimited with <0 value + + fixed http tunnel timeout setting. Fixed HTTP tunnel timeout setting. + + form auth redirects to context on a re-auth FORM auth redirects to context + on a re-auth + + improved handling of exception from servlet init. Improved handling of + exception from servlet init. + + maxformcontentlength may be unlimited with <0 value maxFormContentLength may + be unlimited with <0 value jetty-5.0.0RC0 - 07 April 2004 - + Changed dist naming convention to lowercase - + Default servlet respectes servlet path - + Factored out XML based config from WebApplicationContext - + Fixed Default servlet for non empty servlet paths - + Fixed DOS problem - + Fixed j2se 1.3 problem with HttpFields - + Fixed setCharacterEncoding for parameters. - + Forced close of connections over stop/start - + Improved RequestLog performance - + ProxiedFor field support added to NCSARequestLog - + ServletContext attributes wrap HttpContext attributes. - + Updated jasper to 5.0.19 - + Updated JettyPlus to JOTM 1.4.3 (carol-1.5.2, xapool-1.3.1) - + Updated mx4j to V2 - + Worked around bad jboss URL handler in XMLParser + + changed dist naming convention to lowercase Changed dist naming convention + to lowercase + + default servlet respectes servlet path Default servlet respectes servlet + path + + factored out xml based config from webapplicationcontext Factored out XML + based config from WebApplicationContext + + fixed default servlet for non empty servlet paths Fixed Default servlet for + non empty servlet paths + + fixed dos problem Fixed DOS problem + + fixed j2se 1.3 problem with httpfields Fixed j2se 1.3 problem with + HttpFields + + fixed setcharacterencoding for parameters. Fixed setCharacterEncoding for + parameters. + + forced close of connections over stop/start Forced close of connections over + stop/start + + improved requestlog performance Improved RequestLog performance + + proxiedfor field support added to ncsarequestlog ProxiedFor field support + added to NCSARequestLog + + servletcontext attributes wrap httpcontext attributes. ServletContext + attributes wrap HttpContext attributes. + + updated jasper to 5.0.19 Updated jasper to 5.0.19 + + updated jettyplus to jotm 1.4.3 (carol-1.5.2, xapool-1.3.1) Updated + JettyPlus to JOTM 1.4.3 (carol-1.5.2, xapool-1.3.1) + + updated mx4j to v2 Updated mx4j to V2 + + worked around bad jboss url handler in xmlparser Worked around bad jboss URL + handler in XMLParser jetty-4.2.20RC0 - 07 April 2004 - + Changed dist naming convention to lowercase - + Fixed Default servlet for non empty servlet paths - + Forced close of connections over stop/start - + HttpFields protected headers - + ProxiedFor field support added to NCSARequestLog - + Worked around bad jboss URL handler in XMLParser + + changed dist naming convention to lowercase Changed dist naming convention + to lowercase + + fixed default servlet for non empty servlet paths Fixed Default servlet for + non empty servlet paths + + forced close of connections over stop/start Forced close of connections over + stop/start + + httpfields protected headers HttpFields protected headers + + proxiedfor field support added to ncsarequestlog ProxiedFor field support + added to NCSARequestLog + + worked around bad jboss url handler in xmlparser Worked around bad jboss URL + handler in XMLParser jetty-4.2.19 - 19 March 2004 - + Fixed DOS attack problem + + fixed dos attack problem Fixed DOS attack problem jetty-5.0.beta2 - 12 February 2004 - + Added experimental NIO listeners again. - + Added log4j context repository to jettyplus - + Added skeleton JMX MBean for jetty plus - + FileResource better handles non sun JVM - + Fixed busy loop in threadpool run - + fixed filter dispatch configuration. - + Fixed HEAD with empty chunk bug. - + Fixed jetty.home/work handling - + fixed lazy authentication with FORMs - + Fixed SessionManager init - + Fixed setDate thread safety - + Improved low thread handling - + Monitor closes socket before exit - + NPE guard for no-listener junit deployment - + Reorganized ServletHolder init - + RequestDispatcher uses request encoding for query params - + Updated to Japser 5.0.16 + + added experimental nio listeners again. Added experimental NIO listeners + again. + + added log4j context repository to jettyplus Added log4j context repository + to jettyplus + + added skeleton jmx mbean for jetty plus Added skeleton JMX MBean for jetty + plus + + fileresource better handles non sun jvm FileResource better handles non sun + JVM + + fixed busy loop in threadpool run Fixed busy loop in threadpool run + + fixed filter dispatch configuration. fixed filter dispatch configuration. + + fixed head with empty chunk bug. Fixed HEAD with empty chunk bug. + + fixed jetty.home/work handling Fixed jetty.home/work handling + + fixed lazy authentication with forms fixed lazy authentication with FORMs + + fixed sessionmanager init Fixed SessionManager init + + fixed setdate thread safety Fixed setDate thread safety + + improved low thread handling Improved low thread handling + + monitor closes socket before exit Monitor closes socket before exit + + npe guard for no-listener junit deployment NPE guard for no-listener junit + deployment + + reorganized servletholder init Reorganized ServletHolder init + + requestdispatcher uses request encoding for query params RequestDispatcher + uses request encoding for query params + + updated to japser 5.0.16 Updated to Japser 5.0.16 jetty-4.2.18 - 01 March 2004 - + Added log4j context repository to jettyplus - + Default servlet respectes servlet path - + Fixed j2se 1.3 problem with HttpFields - + Improved log performance - + NPE guard for no-listener junit deployment - + Suppress some more IOExceptions + + added log4j context repository to jettyplus Added log4j context repository + to jettyplus + + default servlet respectes servlet path Default servlet respectes servlet + path + + fixed j2se 1.3 problem with httpfields Fixed j2se 1.3 problem with + HttpFields + + improved log performance Improved log performance + + npe guard for no-listener junit deployment NPE guard for no-listener junit + deployment + + suppress some more ioexceptions Suppress some more IOExceptions jetty-4.2.17 - 01 February 2004 - + Fixed busy loop in threadpool run - + Reorganized ServletHolder init + + fixed busy loop in threadpool run Fixed busy loop in threadpool run + + reorganized servletholder init Reorganized ServletHolder init jetty-4.2.16 - 30 January 2004 - + FileResource better handles non sun JVM - + Fixed HttpTunnel for JDK 1.2 - + Fixed setDate multi-cpu race - + Improved low thread handling - + Monitor closes socket before exit - + RequestDispatcher uses request encoding for query params - + Update jasper to 4.1.29 + + fileresource better handles non sun jvm FileResource better handles non sun + JVM + + fixed httptunnel for jdk 1.2 Fixed HttpTunnel for JDK 1.2 + + fixed setdate multi-cpu race Fixed setDate multi-cpu race + + improved low thread handling Improved low thread handling + + monitor closes socket before exit Monitor closes socket before exit + + requestdispatcher uses request encoding for query params RequestDispatcher + uses request encoding for query params + + update jasper to 4.1.29 Update jasper to 4.1.29 jetty-5.0.beta1 - 24 December 2003 - + Added patch for JBoss realm single sign on - + Env variables for CGI - + Fixed UnixCrypt handling in HTAccessHandler - + Removed support for old JBoss clustering - + Reorganized FAQ - + SecurityConstraints not reset by stop() on custom context + + added patch for jboss realm single sign on Added patch for JBoss realm + single sign on + + env variables for cgi Env variables for CGI + + fixed unixcrypt handling in htaccesshandler Fixed UnixCrypt handling in + HTAccessHandler + + removed support for old jboss clustering Removed support for old JBoss + clustering + + reorganized faq Reorganized FAQ + + securityconstraints not reset by stop() on custom context + SecurityConstraints not reset by stop() on custom context jetty-4.2.15 - 24 December 2003 - + Added patch for JBoss realm single sign on - + Environment variables for CGI - + Fixed UnixCrypt handling in HTAccessHandler - + Removed support for old JBoss clustering - + SecurityConstraints not reset by stop() on custom context + + added patch for jboss realm single sign on Added patch for JBoss realm + single sign on + + environment variables for cgi Environment variables for CGI + + fixed unixcrypt handling in htaccesshandler Fixed UnixCrypt handling in + HTAccessHandler + + removed support for old jboss clustering Removed support for old JBoss + clustering + + securityconstraints not reset by stop() on custom context + SecurityConstraints not reset by stop() on custom context jetty-5.0.beta0 - 22 November 2003 - + Added MsieSslHandler to handle browsers that don't grok persistent SSL (msie - 5) - + Added org.mortbay.http.ErrorHandler for error pages. - + Allow per listener handlers - + Expire pages that contain set-cookie as per RFC2109 recommendation - + Fixed init race in HttpFields cache - + JBoss integration uses writer rather than stream for XML config handling - + PathMap uses own Map.Entry impl for IBM JVMs - + Protect ThreadPool.run() from interrupted exceptions - + Removed support for HTTP trailers - + Removed the CMR/CMP distributed session implementation - + Respect content length when decoding form content. - + Updated jasper to 5.0.14beta - + Use ${jetty.home}/work or WEB-INF/work for temp directories if present + + added msiesslhandler to handle browsers that don't grok persistent ssl Added + MsieSslHandler to handle browsers that don't grok persistent SSL (msie 5) + + added org.mortbay.http.errorhandler for error pages. Added + org.mortbay.http.ErrorHandler for error pages. + + allow per listener handlers Allow per listener handlers + + expire pages that contain set-cookie as per rfc2109 recommendation Expire + pages that contain set-cookie as per RFC2109 recommendation + + fixed init race in httpfields cache Fixed init race in HttpFields cache + + jboss integration uses writer rather than stream for xml config handli JBoss + integration uses writer rather than stream for XML config handling + + pathmap uses own map.entry impl for ibm jvms PathMap uses own Map.Entry impl + for IBM JVMs + + protect threadpool.run() from interrupted exceptions Protect + ThreadPool.run() from interrupted exceptions + + removed support for http trailers Removed support for HTTP trailers + + removed the cmr/cmp distributed session implementation Removed the CMR/CMP + distributed session implementation + + respect content length when decoding form content. Respect content length + when decoding form content. + + updated jasper to 5.0.14beta Updated jasper to 5.0.14beta + + use ${jetty.home}/work or web-inf/work for temp directories if present Use + ${jetty.home}/work or WEB-INF/work for temp directories if present jetty-4.2.15rc0 - 22 November 2003 - + Added org.mortbay.http.ErrorHandler for error pages. - + JsseListener checks UserAgent for browsers that can't grok persistent SSL + + added org.mortbay.http.errorhandler for error pages. Added + org.mortbay.http.ErrorHandler for error pages. + + jsselistener checks useragent for browsers that can't grok persistent + JsseListener checks UserAgent for browsers that can't grok persistent SSL (msie5) - + PathMap uses own Map.Entry impl for IBM JVMs - + Protect ThreadPool.run() from interrupted exceptions - + Race in HttpFields cache - + Removed the CMR/CMP distributed session implementation - + Use ${jetty.home}/work or WEB-INF/work for temp directories if present + + pathmap uses own map.entry impl for ibm jvms PathMap uses own Map.Entry impl + for IBM JVMs + + protect threadpool.run() from interrupted exceptions Protect + ThreadPool.run() from interrupted exceptions + + race in httpfields cache Race in HttpFields cache + + removed the cmr/cmp distributed session implementation Removed the CMR/CMP + distributed session implementation + + use ${jetty.home}/work or web-inf/work for temp directories if present Use + ${jetty.home}/work or WEB-INF/work for temp directories if present jetty-4.2.14 - 04 November 2003 - + Expire pages that contain set-cookie as per RFC2109 recommendation - + Fixed NPE in SSO - + JBoss integration uses writer rather than stream for XML config handling - + respect content length when decoding form content. + + expire pages that contain set-cookie as per rfc2109 recommendation Expire + pages that contain set-cookie as per RFC2109 recommendation + + fixed npe in sso Fixed NPE in SSO + + jboss integration uses writer rather than stream for xml config handli JBoss + integration uses writer rather than stream for XML config handling + + respect content length when decoding form content. respect content length + when decoding form content. jetty-5.0.alpha3 - 19 October 2003 - + Allow customization of HttpConnections - + Failed requests excluded from duration stats - + FileClassPath derived from walk of classloader hierarchy. - + Fixed null pointer if no sevices configured for JettyPlus - + Implemented security constraint combinations - + Lazy authentication if no auth constraint. - + Priority added to ThreadPool - + replaced win32 service with http://wrapper.tanukisoftware.org - + Restore servlet handler after dispatch - + Reworked Dispatcher to better support cross context sessions. - + Set TransactionManager on JettyPlus datasources and pools - + Updated jasper and examples to 5.0.12 - + Use File.toURI().toURL() when jdk 1.2 alternative is available. + + allow customization of httpconnections Allow customization of + HttpConnections + + failed requests excluded from duration stats Failed requests excluded from + duration stats + + fileclasspath derived from walk of classloader hierarchy. FileClassPath + derived from walk of classloader hierarchy. + + fixed null pointer if no sevices configured for jettyplus Fixed null pointer + if no sevices configured for JettyPlus + + implemented security constraint combinations Implemented security constraint + combinations + + lazy authentication if no auth constraint. Lazy authentication if no auth + constraint. + + priority added to threadpool Priority added to ThreadPool + + replaced win32 service with http://wrapper.tanukisoftware.org replaced win32 + service with http://wrapper.tanukisoftware.org + + restore servlet handler after dispatch Restore servlet handler after + dispatch + + reworked dispatcher to better support cross context sessions. Reworked + Dispatcher to better support cross context sessions. + + set transactionmanager on jettyplus datasources and pools Set + TransactionManager on JettyPlus datasources and pools + + updated jasper and examples to 5.0.12 Updated jasper and examples to 5.0.12 + + use file.touri().tourl() when jdk 1.2 alternative is available. Use + File.toURI().toURL() when jdk 1.2 alternative is available. jetty-4.2.14RC1 - 19 October 2003 - + Added UserRealm.logout and arrange for form auth - + Allow customization of HttpConnections - + Failed requests excluded from - + Reworked Dispatcher to better support cross context sessions. + + added userrealm.logout and arrange for form auth Added UserRealm.logout and + arrange for form auth + + allow customization of httpconnections Allow customization of + HttpConnections + + failed requests excluded from Failed requests excluded from + + reworked dispatcher to better support cross context sessions. Reworked + Dispatcher to better support cross context sessions. jetty-4.2.14RC0 - 07 October 2003 - + Build fileclasspath from a walk of the classloaders - + cookie timestamps are in GMT - + Correctly setup context classloader in cross context dispatch. - + Fixed comments with embedded double dashes on jettyplus.xml file - + Fixed handling of error pages for IO and Servlet exceptions - + Fixed null pointer if no sevices configured for JettyPlus - + Priority on ThreadedServer - + Put a semi busy loop into proxy tunnels for IE problems - + replaced win32 service with http://wrapper.tanukisoftware.org - + Set TransactionManager on JettyPlus datasources and pools - + updated extra/j2ee to jboss 3.2.1+ - + Use File.toURI().toURL() when jdk 1.2 alternative is available. + + build fileclasspath from a walk of the classloaders Build fileclasspath from + a walk of the classloaders + + cookie timestamps are in gmt cookie timestamps are in GMT + + correctly setup context classloader in cross context dispatch. Correctly + setup context classloader in cross context dispatch. + + fixed comments with embedded double dashes on jettyplus.xml file Fixed + comments with embedded double dashes on jettyplus.xml file + + fixed handling of error pages for io and servlet exceptions Fixed handling + of error pages for IO and Servlet exceptions + + fixed null pointer if no sevices configured for jettyplus Fixed null pointer + if no sevices configured for JettyPlus + + priority on threadedserver Priority on ThreadedServer + + put a semi busy loop into proxy tunnels for ie problems Put a semi busy loop + into proxy tunnels for IE problems + + replaced win32 service with http://wrapper.tanukisoftware.org replaced win32 + service with http://wrapper.tanukisoftware.org + + set transactionmanager on jettyplus datasources and pools Set + TransactionManager on JettyPlus datasources and pools + + updated extra/j2ee to jboss 3.2.1+ updated extra/j2ee to jboss 3.2.1+ + + use file.touri().tourl() when jdk 1.2 alternative is available. Use + File.toURI().toURL() when jdk 1.2 alternative is available. jetty-5.0.alpha2 - 19 September 2003 - + Correctly setup context classloader in cross context dispatch. - + Fixed error page handling of IO and Servlet exceptions. - + Implemented ServletRequestListeners as optional filter. - + Improved JMX start. - + minor doco updates. - + Moved error page mechanism to be webapp only. - + moved mailing lists to sourceforge. - + MultipartRequest supports multi value headers. - + Put a semi busy loop into proxy tunnels for IE problems - + Turn off validation without non-xerces errors - + Update jakarta examples - + Use commons logging. - + Use log4j if extra is present. - + XML entity resolution uses URLs not Resources + + correctly setup context classloader in cross context dispatch. Correctly + setup context classloader in cross context dispatch. + + fixed error page handling of io and servlet exceptions. Fixed error page + handling of IO and Servlet exceptions. + + implemented servletrequestlisteners as optional filter. Implemented + ServletRequestListeners as optional filter. + + improved jmx start. Improved JMX start. + + minor doco updates. minor doco updates. + + moved error page mechanism to be webapp only. Moved error page mechanism to + be webapp only. + + moved mailing lists to sourceforge. moved mailing lists to sourceforge. + + multipartrequest supports multi value headers. MultipartRequest supports + multi value headers. + + put a semi busy loop into proxy tunnels for ie problems Put a semi busy loop + into proxy tunnels for IE problems + + turn off validation without non-xerces errors Turn off validation without + non-xerces errors + + update jakarta examples Update jakarta examples + + use commons logging. Use commons logging. + + use log4j if extra is present. Use log4j if extra is present. + + xml entity resolution uses urls not resources XML entity resolution uses + URLs not Resources jetty-5.0.alpha1 - 12 August 2003 - + Implemented locale encoding mapping. - + Improve combinations of Security Constraints - + Server javadoc from war - + Switched to mx4j - + Synced with 4.2.12 - + Updated to Jasper 5.0.7 + + implemented locale encoding mapping. Implemented locale encoding mapping. + + improve combinations of security constraints Improve combinations of + Security Constraints + + server javadoc from war Server javadoc from war + + switched to mx4j Switched to mx4j + + synced with 4.2.12 Synced with 4.2.12 + + updated to jasper 5.0.7 Updated to Jasper 5.0.7 jetty-5.0.alpha0 - 16 July 2003 - + Compiled against 2.4 servlet spec. - + Implemented Dispatcher forward attributes. - + Implemented filter-mapping element - + Implemented remote/local addr/port methods - + Implemented setCharaterEncoding - + Updated authentication so that a normal Principal is used. - + updated to jasper 5.0.3 + + compiled against 2.4 servlet spec. Compiled against 2.4 servlet spec. + + implemented dispatcher forward attributes. Implemented Dispatcher forward + attributes. + + implemented filter-mapping element Implemented filter-mapping + element + + implemented remote/local addr/port methods Implemented remote/local + addr/port methods + + implemented setcharaterencoding Implemented setCharaterEncoding + + updated authentication so that a normal principal is used. Updated + authentication so that a normal Principal is used. + + updated to jasper 5.0.3 updated to jasper 5.0.3 jetty-4.2.12 - 12 August 2003 - + Added missing S to some OPTIONS strings - + Added open method to threaded server. - + Fixed MIME types for chemicals - + Fixed parameter ordering for a forward request. - + Fixed up HTAccessHandler - + FORMAuthenticator does 403 with empty error page. - + Improved error messages from ProxyHandler - + Padding for IE in RootNotFoundHandler - + Removed protection of org.mortbay.http attributes - + Restore max inactive interval for session manager + + added missing s to some options strings Added missing S to some OPTIONS + strings + + added open method to threaded server. Added open method to threaded server. + + fixed mime types for chemicals Fixed MIME types for chemicals + + fixed parameter ordering for a forward request. Fixed parameter ordering for + a forward request. + + fixed up htaccesshandler Fixed up HTAccessHandler + + formauthenticator does 403 with empty error page. FORMAuthenticator does 403 + with empty error page. + + improved error messages from proxyhandler Improved error messages from + ProxyHandler + + padding for ie in rootnotfoundhandler Padding for IE in RootNotFoundHandler + + removed protection of org.mortbay.http attributes Removed protection of + org.mortbay.http attributes + + restore max inactive interval for session manager Restore max inactive + interval for session manager jetty-4.2.11 - 12 July 2003 - + Branched for Jetty 5 development. - + Cookie params all in lower case. - + Fixed race in servlet initialization code. - + Prevent AJP13 from reordering query. - + Simplified AJP13 connection handling. - + Support separate Monitor class for start + + branched for jetty 5 development. Branched for Jetty 5 development. + + cookie params all in lower case. Cookie params all in lower case. + + fixed race in servlet initialization code. Fixed race in servlet + initialization code. + + prevent ajp13 from reordering query. Prevent AJP13 from reordering query. + + simplified ajp13 connection handling. Simplified AJP13 connection handling. + + support separate monitor class for start Support separate Monitor class for + start jetty-4.2.10 - 07 July 2003 - + Updates to JettyPlus documentation - + Updates to Jetty tutorial for start.jar, jmx etc + + updates to jettyplus documentation Updates to JettyPlus documentation + + updates to jetty tutorial for start.jar, jmx etc Updates to Jetty tutorial + for start.jar, jmx etc jetty-4.2.10pre2 - 04 July 2003 - + Addition of mail service for JettyPlus - + Allow multiple security-role-ref elements per servlet. - + Cleaned up alias handling. - + Confidential redirection includes query - + Fixed cookie handling for old cookies and safari - + handle multiple security role references - + Handle Proxy-Connection better - + Improvement to JettyPlus config of datasources and connection pools - + Many improvements in JettyPlus java:comp handling - + Move to Service-based architecture for JettyPlus features - + Re-implementation of JNDI - + Restricted ports in ProxyHandler. - + Session statistics - + URI always encodes % - + XmlConfiguration can get/set fields. + + addition of mail service for jettyplus Addition of mail service for + JettyPlus + + allow multiple security-role-ref elements per servlet. Allow multiple + security-role-ref elements per servlet. + + cleaned up alias handling. Cleaned up alias handling. + + confidential redirection includes query Confidential redirection includes + query + + fixed cookie handling for old cookies and safari Fixed cookie handling for + old cookies and safari + + handle multiple security role references handle multiple security role + references + + handle proxy-connection better Handle Proxy-Connection better + + improvement to jettyplus config of datasources and connection pools + Improvement to JettyPlus config of datasources and connection pools + + many improvements in jettyplus java:comp handling Many improvements in + JettyPlus java:comp handling + + move to service-based architecture for jettyplus features Move to + Service-based architecture for JettyPlus features + + re-implementation of jndi Re-implementation of JNDI + + restricted ports in proxyhandler. Restricted ports in ProxyHandler. + + session statistics Session statistics + + uri always encodes % URI always encodes % + + xmlconfiguration can get/set fields. XmlConfiguration can get/set fields. jetty-4.2.10pre1 - 02 June 2003 - + Added SSO implementation for FORM authentication. - + Added stop.jar - + Deprecated forced chunking. - + Fixed AJP13 protocol so that request/response header enums are correct. - + Fixed form auth success redirect after retry, introduced in 4.2.9rc1 - + Fixed JSP code visibility problem introduced in Jetty-4.2.10pre0 - + Fixed problem with shared session for inter context dispatching. - + Form authentication remembers URL over 403 - + ProxyHandler has improved test for request content - + Removed support of org.mortbay.http.User role. - + Trace support is now optional (in AbstractHttpHandler). - + WebApplicationContext does not reassign defaults descriptor value. + + added sso implementation for form authentication. Added SSO implementation + for FORM authentication. + + added stop.jar Added stop.jar + + deprecated forced chunking. Deprecated forced chunking. + + fixed ajp13 protocol so that request/response header enums are correct Fixed + AJP13 protocol so that request/response header enums are correct. + + fixed form auth success redirect after retry, introduced in 4.2.9rc1 Fixed + form auth success redirect after retry, introduced in 4.2.9rc1 + + fixed jsp code visibility problem introduced in jetty-4.2.10pre0 Fixed JSP + code visibility problem introduced in Jetty-4.2.10pre0 + + fixed problem with shared session for inter context dispatching. Fixed + problem with shared session for inter context dispatching. + + form authentication remembers url over 403 Form authentication remembers URL + over 403 + + proxyhandler has improved test for request content ProxyHandler has improved + test for request content + + removed support of org.mortbay.http.user role. Removed support of + org.mortbay.http.User role. + + trace support is now optional (in abstracthttphandler). Trace support is now + optional (in AbstractHttpHandler). + + webapplicationcontext does not reassign defaults descriptor value. + WebApplicationContext does not reassign defaults descriptor value. jetty-4.2.10pre0 - 05 May 2003 - + Added ability to override jetty startup class by using -Djetty.server on - runline - + Allow params in form auth URLs - + Allow query params in error page URL. - + Apply the append flag of RolloverFileOutputStream constructor. - + Fixed CRLF bug in MultiPartRequest - + Fixed table refs in JDBCUserRealm. - + FORM Authentication is serializable for session distribution. - + getAuthType maps the HttpServletRequest final strings. - + getAuthType returns CLIENT_CERT instead of CLIENT-CERT. - + Incorporate jetty extra and plus into build - + Incorporate JettyPlus jotm etc into build. - + Integrate with JAAS - + Massive reorg of the CVS tree. - + Merge multivalued parameters in dispatcher. - + Moved Log4JLogSink into JettyPlus - + New look and feel for www site. - + ProxyHandler checks black and white lists for Connect. - + RolloverFileOutputStream manages Rollover thread. - + Updated to jasper jars from tomcat 4.1.24 - + Warn if max form content size is reached. + + added ability to override jetty startup class by using -djetty.server Added + ability to override jetty startup class by using -Djetty.server on runline + + allow params in form auth urls Allow params in form auth URLs + + allow query params in error page url. Allow query params in error page URL. + + apply the append flag of rolloverfileoutputstream constructor. Apply the + append flag of RolloverFileOutputStream constructor. + + fixed crlf bug in multipartrequest Fixed CRLF bug in MultiPartRequest + + fixed table refs in jdbcuserrealm. Fixed table refs in JDBCUserRealm. + + form authentication is serializable for session distribution. FORM + Authentication is serializable for session distribution. + + getauthtype maps the httpservletrequest final strings. getAuthType maps the + HttpServletRequest final strings. + + getauthtype returns client_cert instead of client-cert. getAuthType returns + CLIENT_CERT instead of CLIENT-CERT. + + incorporate jetty extra and plus into build Incorporate jetty extra and plus + into build + + incorporate jettyplus jotm etc into build. Incorporate JettyPlus jotm etc + into build. + + integrate with jaas Integrate with JAAS + + massive reorg of the cvs tree. Massive reorg of the CVS tree. + + merge multivalued parameters in dispatcher. Merge multivalued parameters in + dispatcher. + + moved log4jlogsink into jettyplus Moved Log4JLogSink into JettyPlus + + new look and feel for www site. New look and feel for www site. + + proxyhandler checks black and white lists for connect. ProxyHandler checks + black and white lists for Connect. + + rolloverfileoutputstream manages rollover thread. RolloverFileOutputStream + manages Rollover thread. + + updated to jasper jars from tomcat 4.1.24 Updated to jasper jars from tomcat + 4.1.24 + + warn if max form content size is reached. Warn if max form content size is + reached. jetty-4.2.9 - 19 March 2003 - + Conditional headers check after /dir to /dir/ redirection. + + conditional headers check after /dir to /dir/ redirection. Conditional + headers check after /dir to /dir/ redirection. jetty-4.2.9rc2 - 16 March 2003 - + Added X-Forwarded-For header in ProxyHandler - + Allow dispatch to j_security_check - + Defaults descriptor has context classloader set. - + Fixed build.xml for source release - + Made rfc2068 PUT/POST Continues support optional. - + Updated included jmx jars + + added x-forwarded-for header in proxyhandler Added X-Forwarded-For header in + ProxyHandler + + allow dispatch to j_security_check Allow dispatch to j_security_check + + defaults descriptor has context classloader set. Defaults descriptor has + context classloader set. + + fixed build.xml for source release Fixed build.xml for source release + + made rfc2068 put/post continues support optional. Made rfc2068 PUT/POST + Continues support optional. + + updated included jmx jars Updated included jmx jars jetty-4.2.9rc1 - 06 March 2003 - + Added requestlog to HttpContext. - + Added support for client certs to AJP13. - + Added trust manager support to SunJsseListener. - + Allow delegated creation of WebApplication derivations. - + Check Data contraints before Auth constraints - + Cleaned up includes - + Dump servlet can load resources for testing now. - + Optional 2.4 behaviour for sessionDestroyed notification. - + ProxyHandler has black and white host list. - + Reduced default context cache sizes (Total 1MB file 100KB). - + Removed checking for single valued headers. - + Stop proxy url from doing user interaction. - + Turn request log buffering off by default. - + Work around URLClassloader not handling leading / + + added requestlog to httpcontext. Added requestlog to HttpContext. + + added support for client certs to ajp13. Added support for client certs to + AJP13. + + added trust manager support to sunjsselistener. Added trust manager support + to SunJsseListener. + + allow delegated creation of webapplication derivations. Allow delegated + creation of WebApplication derivations. + + check data contraints before auth constraints Check Data contraints before + Auth constraints + + cleaned up includes Cleaned up includes + + dump servlet can load resources for testing now. Dump servlet can load + resources for testing now. + + optional 2.4 behaviour for sessiondestroyed notification. Optional 2.4 + behaviour for sessionDestroyed notification. + + proxyhandler has black and white host list. ProxyHandler has black and white + host list. + + reduced default context cache sizes (total 1mb file 100kb). Reduced default + context cache sizes (Total 1MB file 100KB). + + removed checking for single valued headers. Removed checking for single + valued headers. + + stop proxy url from doing user interaction. Stop proxy url from doing user + interaction. + + turn request log buffering off by default. Turn request log buffering off by + default. + + work around urlclassloader not handling leading / Work around URLClassloader + not handling leading / jetty-4.2.8_01 - 18 February 2003 - + Added a SetResponseHeadersHandler, can set P3P headers etc. - + Added MBeans for Servlets and Filters - + Added option to resolve remote hostnames. Defaults to off. - + Default servlet can have own resourceBase. - + Fixed AdminServlet to handle changed getServletPath better. - + Fixed CGI servlet to handle multiple headers. - + Moved ProxyHandler to the src1.4 tree - + Patched first release of 4.2.8 with correct version number - + ProxyHandler can handle multiple cookies. - + Rolled back SocketChannelListener to 4.2.5 version + + added a setresponseheadershandler, can set p3p headers etc. Added a + SetResponseHeadersHandler, can set P3P headers etc. + + added mbeans for servlets and filters Added MBeans for Servlets and Filters + + added option to resolve remote hostnames. defaults to off. Added option to + resolve remote hostnames. Defaults to off. + + default servlet can have own resourcebase. Default servlet can have own + resourceBase. + + fixed adminservlet to handle changed getservletpath better. Fixed + AdminServlet to handle changed getServletPath better. + + fixed cgi servlet to handle multiple headers. Fixed CGI servlet to handle + multiple headers. + + moved proxyhandler to the src1.4 tree Moved ProxyHandler to the src1.4 tree + + patched first release of 4.2.8 with correct version number Patched first + release of 4.2.8 with correct version number + + proxyhandler can handle multiple cookies. ProxyHandler can handle multiple + cookies. + + rolled back socketchannellistener to 4.2.5 version Rolled back + SocketChannelListener to 4.2.5 version jetty-4.2.7 - 04 February 2003 - + Changed PathMap to conform to / getServletPath handling. - + Fixed proxy tunnel for non persistent connections. - + Relative sendRedirect handles trailing / correctly. - + Upgraded to JSSE 1.0.3_01 to fix security problem. + + changed pathmap to conform to / getservletpath handling. Changed PathMap to + conform to / getServletPath handling. + + fixed proxy tunnel for non persistent connections. Fixed proxy tunnel for + non persistent connections. + + relative sendredirect handles trailing / correctly. Relative sendRedirect + handles trailing / correctly. + + upgraded to jsse 1.0.3_01 to fix security problem. Upgraded to JSSE 1.0.3_01 + to fix security problem. jetty-4.2.6 - 24 January 2003 - + Added HttpContext.setHosts to restrict context by real interface. - + Added MBeans for session managers - + Added version to HttpServerMBean. - + Allow AJP13 buffers to be resized. - + ClientCertAuthentication updates request. - + Fixed LineInput problem with expanded buffers. - + Fixed rel sendRedirects for root context. - + Improved SocketChannelListener contributed. - + Improved synchronization on AbstractSessionManager. + + added httpcontext.sethosts to restrict context by real interface. Added + HttpContext.setHosts to restrict context by real interface. + + added mbeans for session managers Added MBeans for session managers + + added version to httpservermbean. Added version to HttpServerMBean. + + allow ajp13 buffers to be resized. Allow AJP13 buffers to be resized. + + clientcertauthentication updates request. ClientCertAuthentication updates + request. + + fixed lineinput problem with expanded buffers. Fixed LineInput problem with + expanded buffers. + + fixed rel sendredirects for root context. Fixed rel sendRedirects for root + context. + + improved socketchannellistener contributed. Improved SocketChannelListener + contributed. + + improved synchronization on abstractsessionmanager. Improved synchronization + on AbstractSessionManager. jetty-4.2.5 - 14 January 2003 - + Added Log4jSink in the contrib directory. - + Don't process conditional headers and ranges for includes - + Fixed pathParam bug for ;jsessionid - + Fixed requestedSessionId null bug. + + added log4jsink in the contrib directory. Added Log4jSink in the contrib + directory. + + don't process conditional headers and ranges for includes Don't process + conditional headers and ranges for includes + + fixed pathparam bug for ;jsessionid Fixed pathParam bug for ;jsessionid + + fixed requestedsessionid null bug. Fixed requestedSessionId null bug. jetty-4.2.4 - 04 January 2003 - + Added MBeans for handlers - + Clear context attributes after stop. - + Clear context listeners after stop. - + Fixed stop/start handling of servlet context - + HTAccessHandler checks realm as well as htpassword. - + Reuse empty LogSink slots. - + Upgraded jasper to 4.1.18 - + Use requestedSessionId as default session ID. + + added mbeans for handlers Added MBeans for handlers + + clear context attributes after stop. Clear context attributes after stop. + + clear context listeners after stop. Clear context listeners after stop. + + fixed stop/start handling of servlet context Fixed stop/start handling of + servlet context + + htaccesshandler checks realm as well as htpassword. HTAccessHandler checks + realm as well as htpassword. + + reuse empty logsink slots. Reuse empty LogSink slots. + + upgraded jasper to 4.1.18 Upgraded jasper to 4.1.18 + + use requestedsessionid as default session id. Use requestedSessionId as + default session ID. jetty-4.2.4rc0 - 12 December 2002 - + Added gzip content encoding support to Default and ResourceHandler - + Added HttpContext.flushCache - + Allow empty host header. - + Avoid optional 100 continues. - + Better access to session manager. - + Character encoding handling for GET requests. - + Cheap clear for HttpFields - + Cleaned up some unused listener throws. - + Code logs objects rather than strings. - + Configurable root context. - + Dir listings in UTF8 - + Fixed dir listing from jars. - + Fixed isSecure and getScheme for SSL over AJP13 - + Fixed setBufferSize NPE. - + Handle = in param values. - + Handle chunked form data. - + Implemented RFC2817 CONNECT in ProxyHandler - + Improved ProxyHandler to the point is works well for non SSL. - + Improved setBufferSize handling - + Limit form content size. - + Removed container transfer encoding handling. - + RootNotFoundHandler to help when no context found. - + Simplified ThreadedServer - + Update jasper to 4.1.16beta - + Use ThreadLocals for ByteArrayPool to avoid synchronization. - + Use Version to reset HttpFields + + added gzip content encoding support to default and resourcehandler Added + gzip content encoding support to Default and ResourceHandler + + added httpcontext.flushcache Added HttpContext.flushCache + + allow empty host header. Allow empty host header. + + avoid optional 100 continues. Avoid optional 100 continues. + + better access to session manager. Better access to session manager. + + character encoding handling for get requests. Character encoding handling + for GET requests. + + cheap clear for httpfields Cheap clear for HttpFields + + cleaned up some unused listener throws. Cleaned up some unused listener + throws. + + code logs objects rather than strings. Code logs objects rather than + strings. + + configurable root context. Configurable root context. + + dir listings in utf8 Dir listings in UTF8 + + fixed dir listing from jars. Fixed dir listing from jars. + + fixed issecure and getscheme for ssl over ajp13 Fixed isSecure and getScheme + for SSL over AJP13 + + fixed setbuffersize npe. Fixed setBufferSize NPE. + + handle = in param values. Handle = in param values. + + handle chunked form data. Handle chunked form data. + + implemented rfc2817 connect in proxyhandler Implemented RFC2817 CONNECT in + ProxyHandler + + improved proxyhandler to the point is works well for non ssl. Improved + ProxyHandler to the point is works well for non SSL. + + improved setbuffersize handling Improved setBufferSize handling + + limit form content size. Limit form content size. + + removed container transfer encoding handling. Removed container transfer + encoding handling. + + rootnotfoundhandler to help when no context found. RootNotFoundHandler to + help when no context found. + + simplified threadedserver Simplified ThreadedServer + + update jasper to 4.1.16beta Update jasper to 4.1.16beta + + use threadlocals for bytearraypool to avoid synchronization. Use + ThreadLocals for ByteArrayPool to avoid synchronization. + + use version to reset httpfields Use Version to reset HttpFields jetty-4.2.3 - 02 December 2002 - + Added links to Jetty Powered page - + added main() to org.mortbay.http.Version - + Added PKCS12Import class to import PKCS12 key directly - + Check form authentication config for leading / - + Cleaner servlet stop to avoid extra synchronization on handle - + Clean up of ThreadedServer.stop() - + Fixed some typos - + org.mortbay.http.HttpContext.FileClassPathAttribute - + Removed aggressive threadpool shrinkage to avoid deadlock on SMP machines. - + removed old HttpContext.setDirAllowed() - + Updated bat scripts + + added links to jetty powered page Added links to Jetty Powered page + + added main() to org.mortbay.http.version added main() to + org.mortbay.http.Version + + added pkcs12import class to import pkcs12 key directly Added PKCS12Import + class to import PKCS12 key directly + + check form authentication config for leading / Check form authentication + config for leading / + + cleaner servlet stop to avoid extra synchronization on handle Cleaner + servlet stop to avoid extra synchronization on handle + + clean up of threadedserver.stop() Clean up of ThreadedServer.stop() + + fixed some typos Fixed some typos + + org.mortbay.http.httpcontext.fileclasspathattribute + org.mortbay.http.HttpContext.FileClassPathAttribute + + removed aggressive threadpool shrinkage to avoid deadlock on smp machi + Removed aggressive threadpool shrinkage to avoid deadlock on SMP machines. + + removed old httpcontext.setdirallowed() removed old + HttpContext.setDirAllowed() + + updated bat scripts Updated bat scripts jetty-4.2.2 - 20 November 2002 - + Added EOFException to reduce log verbosity on closed connections. - + Avoided bad buffer status after closed connection. - + Fixed handling of empty headers - + Fixed sendRedirect for non http URLS - + Fixed URI query recycling for persistent connections + + added eofexception to reduce log verbosity on closed connections. Added + EOFException to reduce log verbosity on closed connections. + + avoided bad buffer status after closed connection. Avoided bad buffer status + after closed connection. + + fixed handling of empty headers Fixed handling of empty headers + + fixed sendredirect for non http urls Fixed sendRedirect for non http URLS + + fixed uri query recycling for persistent connections Fixed URI query + recycling for persistent connections jetty-4.2.1 - 18 November 2002 - + Fixed bad optimization in UrlEncoding - + Re-enabled UrlEncoding test harnesses + + fixed bad optimization in urlencoding Fixed bad optimization in UrlEncoding + + re-enabled urlencoding test harnesses Re-enabled UrlEncoding test harnesses jetty-4.2.0 - 16 November 2002 - + Added definitions for RFC2518 WebDav response codes. - + Added upload demo to dump servlet. - + Fixed AJP13 buffer size. - + Fixed include of Invoker servlet. - + Fixed remove listener bug. - + Lowercase jsessionid for URLs only. - + Made NCSARequestLog easier to extend. - + Many more optimizations. - + Removed jasper source and just include jars from 4.1.12 - + Removed remaining non portable getBytes() calls - + Restrict 304 responses to seconds time resolution. - + Use IE date formatting for speed. - + Worked around JVM1.3 bug for JSPs + + added definitions for rfc2518 webdav response codes. Added definitions for + RFC2518 WebDav response codes. + + added upload demo to dump servlet. Added upload demo to dump servlet. + + fixed ajp13 buffer size. Fixed AJP13 buffer size. + + fixed include of invoker servlet. Fixed include of Invoker servlet. + + fixed remove listener bug. Fixed remove listener bug. + + lowercase jsessionid for urls only. Lowercase jsessionid for URLs only. + + made ncsarequestlog easier to extend. Made NCSARequestLog easier to extend. + + many more optimizations. Many more optimizations. + + removed jasper source and just include jars from 4.1.12 Removed jasper + source and just include jars from 4.1.12 + + removed remaining non portable getbytes() calls Removed remaining non + portable getBytes() calls + + restrict 304 responses to seconds time resolution. Restrict 304 responses to + seconds time resolution. + + use ie date formatting for speed. Use IE date formatting for speed. + + worked around jvm1.3 bug for jsps Worked around JVM1.3 bug for JSPs jetty-4.1.4 - 16 November 2002 - + Fixed ContextLoader parent delegation bug - + Fixed Invoker servlet for RD.include - + Fixed remove SocketListener bug. - + Last modified handling uses second resolution. - + Made NCSARequestLog simpler to extend. - + Use IE date formatting for last-modified efficiency + + fixed contextloader parent delegation bug Fixed ContextLoader parent + delegation bug + + fixed invoker servlet for rd.include Fixed Invoker servlet for RD.include + + fixed remove socketlistener bug. Fixed remove SocketListener bug. + + last modified handling uses second resolution. Last modified handling uses + second resolution. + + made ncsarequestlog simpler to extend. Made NCSARequestLog simpler to + extend. + + use ie date formatting for last-modified efficiency Use IE date formatting + for last-modified efficiency jetty-4.2.0rc1 - 02 November 2002 - + Fixed ContextLoader parent delegation bug. - + Fixed directory resource bug in JarFileResource. - + Fixed firstWrite after commit. - + Fixed problem setting the size of chunked buffers. - + Fixed servletpath on invoker for named servlets. - + Improved handling of 2 byte encoded characters within forms. - + Recycling of HttpFields class. - + Removed unused Servlet and Servlet-Engine headers. - + Renamed Filter application methods. - + Support default mime mapping defined by * + + fixed contextloader parent delegation bug. Fixed ContextLoader parent + delegation bug. + + fixed directory resource bug in jarfileresource. Fixed directory resource + bug in JarFileResource. + + fixed firstwrite after commit. Fixed firstWrite after commit. + + fixed problem setting the size of chunked buffers. Fixed problem setting the + size of chunked buffers. + + fixed servletpath on invoker for named servlets. Fixed servletpath on + invoker for named servlets. + + improved handling of 2 byte encoded characters within forms. Improved + handling of 2 byte encoded characters within forms. + + recycling of httpfields class. Recycling of HttpFields class. + + removed unused servlet and servlet-engine headers. Removed unused Servlet + and Servlet-Engine headers. + + renamed filter application methods. Renamed Filter application methods. + + support default mime mapping defined by * Support default mime mapping + defined by * jetty-4.2.0rc0 - 24 October 2002 - + Added authenticator to admin.xml - + Added embedded iso8859 writer to HttpOutputStream. - + Fixed RolloverFileOutputStream without date. - + Fixed SessionManager initialization - + Fixed Session timeout NPE. - + Greg's birthday release! - + Removed duplicate classes from jar + + added authenticator to admin.xml Added authenticator to admin.xml + + added embedded iso8859 writer to httpoutputstream. Added embedded iso8859 + writer to HttpOutputStream. + + fixed rolloverfileoutputstream without date. Fixed RolloverFileOutputStream + without date. + + fixed sessionmanager initialization Fixed SessionManager initialization + + fixed session timeout npe. Fixed Session timeout NPE. + + greg's birthday release! Greg's birthday release! + + removed duplicate classes from jar Removed duplicate classes from jar jetty-4.1.3 - 24 October 2002 - + Added authenticator to admin.xml - + Fixed RolloverFileOutputStream without date. - + Fixed SessionManager initialization - + Fixed Session timeout NPE. + + added authenticator to admin.xml Added authenticator to admin.xml + + fixed rolloverfileoutputstream without date. Fixed RolloverFileOutputStream + without date. + + fixed sessionmanager initialization Fixed SessionManager initialization + + fixed session timeout npe. Fixed Session timeout NPE. jetty-4.0.6 - 24 October 2002 - + Clear interrupted status in ThreadPool - + fixed forward attribute handling for jsp-file servlets - + Fixed forward query string handling - + Fixed handling of relative sendRedirect after forward. - + Fixed setCharacterEncoding to work with getReader - + Fixed virtual hosts temp directories. + + clear interrupted status in threadpool Clear interrupted status in + ThreadPool + + fixed forward attribute handling for jsp-file servlets fixed forward + attribute handling for jsp-file servlets + + fixed forward query string handling Fixed forward query string handling + + fixed handling of relative sendredirect after forward. Fixed handling of + relative sendRedirect after forward. + + fixed setcharacterencoding to work with getreader Fixed setCharacterEncoding + to work with getReader + + fixed virtual hosts temp directories. Fixed virtual hosts temp directories. jetty-4.2.0beta0 - 13 October 2002 + 404 instead of 403 for WEB-INF requests - + Allow %3B encoded ; in URLs - + Allow anonymous realm - + Build without jmx - + Fixed bad log dir detection - + Fixed caching of directories to avoid shared buffers. - + Fix Session invalidation bug - + FORM authentication sets 403 error page - + getNamedDispatcher(null) returns containers default servlet. - + New AJP13 implementation. - + New Buffering implementation. - + New ThreadPool implementation. - + Removed Dispatcher dependancy on ServletHttpContext - + Stop/Start filters in declaration order. - + unquote charset in content type - + Update jasper to 4.1.12 tag - + Use "standard" names for default,jsp & invoker servlets. + + allow %3b encoded ; in urls Allow %3B encoded ; in URLs + + allow anonymous realm Allow anonymous realm + + build without jmx Build without jmx + + fixed bad log dir detection Fixed bad log dir detection + + fixed caching of directories to avoid shared buffers. Fixed caching of + directories to avoid shared buffers. + + fix session invalidation bug Fix Session invalidation bug + + form authentication sets 403 error page FORM authentication sets 403 error + page + + getnameddispatcher(null) returns containers default servlet. + getNamedDispatcher(null) returns containers default servlet. + + new ajp13 implementation. New AJP13 implementation. + + new buffering implementation. New Buffering implementation. + + new threadpool implementation. New ThreadPool implementation. + + removed dispatcher dependancy on servlethttpcontext Removed Dispatcher + dependancy on ServletHttpContext + + stop/start filters in declaration order. Stop/Start filters in declaration + order. + + unquote charset in content type unquote charset in content type + + update jasper to 4.1.12 tag Update jasper to 4.1.12 tag + + use "standard" names for default,jsp & invoker servlets. Use "standard" + names for default,jsp & invoker servlets. jetty-4.1.2 - 13 October 2002 + 404 instead of 403 for WEB-INF requests - + Allow %3B encoded ; in URLs - + Allow anonymous realm - + Build without jmx - + Fixed bad log dir detection - + Fixed caching of directories to avoid shared buffers. - + Fix Session invalidation bug - + FORM authentication sets 403 error page - + getNamedDispatcher(null) returns containers default servlet. - + Some AJP13 optimizations. - + Stop/Start filters in declaration order. - + unquote charset in content type - + Update jasper to 4.1.12 tag - + Use "standard" names for default,jsp & invoker servlets. + + allow %3b encoded ; in urls Allow %3B encoded ; in URLs + + allow anonymous realm Allow anonymous realm + + build without jmx Build without jmx + + fixed bad log dir detection Fixed bad log dir detection + + fixed caching of directories to avoid shared buffers. Fixed caching of + directories to avoid shared buffers. + + fix session invalidation bug Fix Session invalidation bug + + form authentication sets 403 error page FORM authentication sets 403 error + page + + getnameddispatcher(null) returns containers default servlet. + getNamedDispatcher(null) returns containers default servlet. + + some ajp13 optimizations. Some AJP13 optimizations. + + stop/start filters in declaration order. Stop/Start filters in declaration + order. + + unquote charset in content type unquote charset in content type + + update jasper to 4.1.12 tag Update jasper to 4.1.12 tag + + use "standard" names for default,jsp & invoker servlets. Use "standard" + names for default,jsp & invoker servlets. jetty-4.1.1 - 30 September 2002 - + Avoid setting sotimeout for optimization. - + Cache directory listings. - + Deprecated maxReadTime. - + Fixed client scripting vulnerability with jasper2. - + Fixed infinite recursion in JDBCUserRealm - + Fixed space in resource name handling for jdk1.4 - + Merged LimitedNCSARequestLog into NCSARequestLog - + Moved launcher/src to src/org/mortbay/start - + String comparison of If-Modified-Since headers. - + Touch files when expanding jars + + avoid setting sotimeout for optimization. Avoid setting sotimeout for + optimization. + + cache directory listings. Cache directory listings. + + deprecated maxreadtime. Deprecated maxReadTime. + + fixed client scripting vulnerability with jasper2. Fixed client scripting + vulnerability with jasper2. + + fixed infinite recursion in jdbcuserrealm Fixed infinite recursion in + JDBCUserRealm + + fixed space in resource name handling for jdk1.4 Fixed space in resource + name handling for jdk1.4 + + merged limitedncsarequestlog into ncsarequestlog Merged + LimitedNCSARequestLog into NCSARequestLog + + moved launcher/src to src/org/mortbay/start Moved launcher/src to + src/org/mortbay/start + + string comparison of if-modified-since headers. String comparison of + If-Modified-Since headers. + + touch files when expanding jars Touch files when expanding jars jetty-4.1.0 - 22 September 2002 - + Added LimitedNCSARequestLog - + ClientCertAuthenticator protected from null subjectDN - + Context Initparams to control session cookie domain, path and age. - + Fixed AJP13 handling of mod_jk loadbalancing. - + Fixed CGI+windows security hole. - + Handle unremovable tempdir. - + NCSARequest log buffered default - + Sorted directory listings. - + Stop servlets in opposite order to start. - + Use javac -target 1.2 for normal classes - + WEB-INF/classes before WEB-INF/lib + + added limitedncsarequestlog Added LimitedNCSARequestLog + + clientcertauthenticator protected from null subjectdn + ClientCertAuthenticator protected from null subjectDN + + context initparams to control session cookie domain, path and age. Context + Initparams to control session cookie domain, path and age. + + fixed ajp13 handling of mod_jk loadbalancing. Fixed AJP13 handling of mod_jk + loadbalancing. + + fixed cgi+windows security hole. Fixed CGI+windows security hole. + + handle unremovable tempdir. Handle unremovable tempdir. + + ncsarequest log buffered default NCSARequest log buffered default + + sorted directory listings. Sorted directory listings. + + stop servlets in opposite order to start. Stop servlets in opposite order to + start. + + use javac -target 1.2 for normal classes Use javac -target 1.2 for normal + classes + + web-inf/classes before web-inf/lib WEB-INF/classes before WEB-INF/lib jetty-4.1.0RC6 - 14 September 2002 - + Added logon.jsp for no cookie form authentication. - + Added redirect to welcome file option. - + Cleaned up old debug. - + Don't URL encode FileURLS. - + Encode URLs of Authentication redirections. - + Extended Session API to pass request for jvmRoute handling - + Fixed problem with AJP 304 responses. - + FormAuthenticator uses normal redirections now. - + Improved HashUserRealm doco - + Improved look and feel of demo + + added logon.jsp for no cookie form authentication. Added logon.jsp for no + cookie form authentication. + + added redirect to welcome file option. Added redirect to welcome file + option. + + cleaned up old debug. Cleaned up old debug. + + don't url encode fileurls. Don't URL encode FileURLS. + + encode urls of authentication redirections. Encode URLs of Authentication + redirections. + + extended session api to pass request for jvmroute handling Extended Session + API to pass request for jvmRoute handling + + fixed problem with ajp 304 responses. Fixed problem with AJP 304 responses. + + formauthenticator uses normal redirections now. FormAuthenticator uses + normal redirections now. + + improved hashuserrealm doco Improved HashUserRealm doco + + improved look and feel of demo Improved look and feel of demo jetty-4.1.0RC5 - 08 September 2002 - + Added commandPrefix init param to CGI - + AJP13Listener caught up with HttpConnection changes. - + Implemented security-role-ref for isUserInRole. - + Improved errors for misconfigured realms. - + More cleanup in ThreadPool for idle death. + + added commandprefix init param to cgi Added commandPrefix init param to CGI + + ajp13listener caught up with httpconnection changes. AJP13Listener caught up + with HttpConnection changes. + + implemented security-role-ref for isuserinrole. Implemented + security-role-ref for isUserInRole. + + improved errors for misconfigured realms. Improved errors for misconfigured + realms. + + more cleanup in threadpool for idle death. More cleanup in ThreadPool for + idle death. jetty-4.1.0RC4 - 30 August 2002 - + Created statsLock sync objects to avoid deadlock when stopping. - + Included IbmJsseListener in the contrib directory. - + Reverted to 302 for all redirections as all clients do not understand 303 - + Updated jasper2 to 4.1.10 tag. + + created statslock sync objects to avoid deadlock when stopping. Created + statsLock sync objects to avoid deadlock when stopping. + + included ibmjsselistener in the contrib directory. Included IbmJsseListener + in the contrib directory. + + reverted to 302 for all redirections as all clients do not understand + Reverted to 302 for all redirections as all clients do not understand 303 + + updated jasper2 to 4.1.10 tag. Updated jasper2 to 4.1.10 tag. jetty-4.1.0RC3 - 28 August 2002 - + Added buffering to request log - + Added defaults descriptor to addWebApplications. - + addWebApplications encodes paths to allow for spaces in file names. - + Allow FORM auth pages to be within security constraint. - + Allow WebApplicationHandler to be used with other handlers. - + Created and integrated the Jetty Launcher - + Fixed security problem for suffix matching with trailing "/" - + Improved handling of path encoding in Resources for bad JVMs - + Improved handling of PUT,DELETE & MOVE. - + Made Resource canonicalize it's base path for directories + + added buffering to request log Added buffering to request log + + added defaults descriptor to addwebapplications. Added defaults descriptor + to addWebApplications. + + addwebapplications encodes paths to allow for spaces in file names. + addWebApplications encodes paths to allow for spaces in file names. + + allow form auth pages to be within security constraint. Allow FORM auth + pages to be within security constraint. + + allow webapplicationhandler to be used with other handlers. Allow + WebApplicationHandler to be used with other handlers. + + created and integrated the jetty launcher Created and integrated the Jetty + Launcher + + fixed security problem for suffix matching with trailing "/" Fixed security + problem for suffix matching with trailing "/" + + improved handling of path encoding in resources for bad jvms Improved + handling of path encoding in Resources for bad JVMs + + improved handling of put,delete & move. Improved handling of PUT,DELETE & + MOVE. + + made resource canonicalize it's base path for directories Made Resource + canonicalize it's base path for directories jetty-4.1.0RC2 - 20 August 2002 - + Added HttpListener.bufferReserve - + Build ant, src and zip versions with the release - + Clear interrupted status in ThreadPool - + Conveninace setClassLoaderJava2Compliant method. - + Fixed HttpFields cache overflow - + Improved ByteArrayPool to handle multiple sizes. - + Updated to Jasper2 (4_1_9 tag) - + Use system line separator for log files. + + added httplistener.bufferreserve Added HttpListener.bufferReserve + + build ant, src and zip versions with the release Build ant, src and zip + versions with the release + + clear interrupted status in threadpool Clear interrupted status in + ThreadPool + + conveninace setclassloaderjava2compliant method. Conveninace + setClassLoaderJava2Compliant method. + + fixed httpfields cache overflow Fixed HttpFields cache overflow + + improved bytearraypool to handle multiple sizes. Improved ByteArrayPool to + handle multiple sizes. + + updated to jasper2 (4_1_9 tag) Updated to Jasper2 (4_1_9 tag) + + use system line separator for log files. Use system line separator for log + files. jetty-4.1.0RC1 - 11 August 2002 - + Fixed forward query string handling - + Fixed forward to jsp-file servlet - + Fixed getContext to use canonical contextPathSpec - + Fixed handling of relative sendRedirect after forward. - + Fixed setCharacterEncoding to work with getReader - + Improved the return codes for PUT - + Made HttpServer serializable - + Updated international URI doco - + Updated jasper to CVS snapshot 200208011920 + + fixed forward query string handling Fixed forward query string handling + + fixed forward to jsp-file servlet Fixed forward to jsp-file servlet + + fixed getcontext to use canonical contextpathspec Fixed getContext to use + canonical contextPathSpec + + fixed handling of relative sendredirect after forward. Fixed handling of + relative sendRedirect after forward. + + fixed setcharacterencoding to work with getreader Fixed setCharacterEncoding + to work with getReader + + improved the return codes for put Improved the return codes for PUT + + made httpserver serializable Made HttpServer serializable + + updated international uri doco Updated international URI doco + + updated jasper to cvs snapshot 200208011920 Updated jasper to CVS snapshot + 200208011920 jetty-4.1.0RC0 - 31 July 2002 - + Added DigestAuthenticator - + Added ExpiryHandler which can set a default Expires header. - + Added link to a Jetty page in Korean. - + Changed URI default charset back to ISO_8859_1 - + Fixed getRealPath for packed war files. - + Restructured Password into Password and Credentials + + added digestauthenticator Added DigestAuthenticator + + added expiryhandler which can set a default expires header. Added + ExpiryHandler which can set a default Expires header. + + added link to a jetty page in korean. Added link to a Jetty page in Korean. + + changed uri default charset back to iso_8859_1 Changed URI default charset + back to ISO_8859_1 + + fixed getrealpath for packed war files. Fixed getRealPath for packed war + files. + + restructured password into password and credentials Restructured Password + into Password and Credentials jetty-4.0.5 - 31 July 2002 - + Fixed getRealPath for packed war files. - + Fixed getRequestURI for RD.forward to return new URI. - + Reversed order of ServletContextListener.contextDestroyed calls + + fixed getrealpath for packed war files. Fixed getRealPath for packed war + files. + + fixed getrequesturi for rd.forward to return new uri. Fixed getRequestURI + for RD.forward to return new URI. + + reversed order of servletcontextlistener.contextdestroyed calls Reversed + order of ServletContextListener.contextDestroyed calls jetty-4.1.B1 - 19 July 2002 - + Added 2.4 Filter dispatching support. - + Added PUT,DELETE,MOVE support to webapps. - + CGI Servlet, catch and report program invocation failure status. - + CGI Servlet, fixed suffix mapping problem. - + CGI Servlet, pass all HTTP headers through. - + CGI Servlet, set working directory for exec - + Moved dynamic servlet handling to Invoker servlet. - + Moved webapp resource handling to Default servlet. - + Reversed order of ServletContextListener.contextDestroyed calls - + Sessions create attribute map lazily. - + Support HTTP/0.9 requests again - + Updated mini.http.jar target + + added 2.4 filter dispatching support. Added 2.4 Filter dispatching support. + + added put,delete,move support to webapps. Added PUT,DELETE,MOVE support to + webapps. + + cgi servlet, catch and report program invocation failure status. CGI + Servlet, catch and report program invocation failure status. + + cgi servlet, fixed suffix mapping problem. CGI Servlet, fixed suffix mapping + problem. + + cgi servlet, pass all http headers through. CGI Servlet, pass all HTTP + headers through. + + cgi servlet, set working directory for exec CGI Servlet, set working + directory for exec + + moved dynamic servlet handling to invoker servlet. Moved dynamic servlet + handling to Invoker servlet. + + moved webapp resource handling to default servlet. Moved webapp resource + handling to Default servlet. + + reversed order of servletcontextlistener.contextdestroyed calls Reversed + order of ServletContextListener.contextDestroyed calls + + sessions create attribute map lazily. Sessions create attribute map lazily. + + support http/0.9 requests again Support HTTP/0.9 requests again + + updated mini.http.jar target Updated mini.http.jar target jetty-3.1.9 - 15 July 2002 - + Allow doHead requests to be forwarded. - + Fixed race in ThreadPool for minThreads <= CPUs + + allow dohead requests to be forwarded. Allow doHead requests to be + forwarded. + + fixed race in threadpool for minthreads <= cpus Fixed race in ThreadPool for + minThreads <= CPUs jetty-4.1.B0 - 13 July 2002 - + Added work around of JDK1.4 bug with NIO listener - + Allow filter init to access servlet context methods. - + close rather than disable stream after forward - + Fixed close problem with load balancer. - + Fixed ThreadPool bug when minThreads <= CPUs - + Keep notFoundContext out of context mapping lists. - + mod_jk FAQ - + Moved 3rd party jars to $JETTY_HOME/ext - + NCSARequestLog can log to stderr - + RD.forward changes getRequestURI. - + Stopped RD.includes closing response. + + added work around of jdk1.4 bug with nio listener Added work around of + JDK1.4 bug with NIO listener + + allow filter init to access servlet context methods. Allow filter init to + access servlet context methods. + + close rather than disable stream after forward close rather than disable + stream after forward + + fixed close problem with load balancer. Fixed close problem with load + balancer. + + fixed threadpool bug when minthreads <= cpus Fixed ThreadPool bug when + minThreads <= CPUs + + keep notfoundcontext out of context mapping lists. Keep notFoundContext out + of context mapping lists. + + mod_jk faq mod_jk FAQ + + moved 3rd party jars to $jetty_home/ext Moved 3rd party jars to + $JETTY_HOME/ext + + ncsarequestlog can log to stderr NCSARequestLog can log to stderr + + rd.forward changes getrequesturi. RD.forward changes getRequestURI. + + stopped rd.includes closing response. Stopped RD.includes closing response. jetty-4.1.D2 - 24 June 2002 - + Added AJP13 listener for apache integration. - + Allow comma separated cookies and headers - + Back out Don't chunk 30x empty responses. - + Better recycling of HttpRequests. - + Conditional header tested against welcome file not directory. - + Fixed ChunkableOutputStream close propagation - + Improved ThreadedServer stopping on bad networks - + Moved jmx classes from JettyExtra to here. - + Protect session.getAttributeNames from concurrent modifications. - + Set contextloader during webapplicationcontext.start - + Support trusted external authenticators. - + Use ThreadLocals to avoid unwrapping in Dispatcher. + + added ajp13 listener for apache integration. Added AJP13 listener for apache + integration. + + allow comma separated cookies and headers Allow comma separated cookies and + headers + + back out don't chunk 30x empty responses. Back out Don't chunk 30x empty + responses. + + better recycling of httprequests. Better recycling of HttpRequests. + + conditional header tested against welcome file not directory. Conditional + header tested against welcome file not directory. + + fixed chunkableoutputstream close propagation Fixed ChunkableOutputStream + close propagation + + improved threadedserver stopping on bad networks Improved ThreadedServer + stopping on bad networks + + moved jmx classes from jettyextra to here. Moved jmx classes from JettyExtra + to here. + + protect session.getattributenames from concurrent modifications. Protect + session.getAttributeNames from concurrent modifications. + + set contextloader during webapplicationcontext.start Set contextloader + during webapplicationcontext.start + + support trusted external authenticators. Support trusted external + authenticators. + + use threadlocals to avoid unwrapping in dispatcher. Use ThreadLocals to + avoid unwrapping in Dispatcher. jetty-4.0.4 - 23 June 2002 - + Back out change: Don't chunk 30x empty responses. - + Conditional header tested against welcome file not directory. - + Improved ThreadedServer stopping on bad networks + + back out change: don't chunk 30x empty responses. Back out change: Don't + chunk 30x empty responses. + + conditional header tested against welcome file not directory. Conditional + header tested against welcome file not directory. + + improved threadedserver stopping on bad networks Improved ThreadedServer + stopping on bad networks jetty-4.0.3 - 20 June 2002 - + Allow comma separated cookies and headers - + Allow session manager to be initialized when set. - + Better recycling of HttpRequests. - + Fixed close propagation of on-chunked output streams - + Fixed japanese locale - + Force security disassociation. - + Protect session.getAttributeNames from concurrent modifications. - + WebapplicationContext.start sets context loader + + allow comma separated cookies and headers Allow comma separated cookies and + headers + + allow session manager to be initialized when set. Allow session manager to + be initialized when set. + + better recycling of httprequests. Better recycling of HttpRequests. + + fixed close propagation of on-chunked output streams Fixed close propagation + of on-chunked output streams + + fixed japanese locale Fixed japanese locale + + force security disassociation. Force security disassociation. + + protect session.getattributenames from concurrent modifications. Protect + session.getAttributeNames from concurrent modifications. + + webapplicationcontext.start sets context loader WebapplicationContext.start + sets context loader jetty-4.1.D1 - 08 June 2002 - + Added simple buffer pool. - + Don't chunk 30x empty responses. - + Fixed /foo/../bar// bug in canonical path. - + Fixed "" contextPaths in Dispatcher. - + Merged ResourceBase and SecurityBase into HttpContext - + Recycle servlet requests and responses - + Removed race for the starting of session scavaging - + Reworked output buffering to keep constant sized buffers. + + added simple buffer pool. Added simple buffer pool. + + don't chunk 30x empty responses. Don't chunk 30x empty responses. + + fixed /foo/../bar// bug in canonical path. Fixed /foo/../bar// bug in + canonical path. + + fixed "" contextpaths in dispatcher. Fixed "" contextPaths in Dispatcher. + + merged resourcebase and securitybase into httpcontext Merged ResourceBase + and SecurityBase into HttpContext + + recycle servlet requests and responses Recycle servlet requests and + responses + + removed race for the starting of session scavaging Removed race for the + starting of session scavaging + + reworked output buffering to keep constant sized buffers. Reworked output + buffering to keep constant sized buffers. jetty-4.0.2 - 06 June 2002 - + Added OptimizeIt plug - + Don't chunk 30x empty responses. - + Fixed /foo/../bar// bug in canonical path. - + Fixed "" contextPaths in Dispatcher. - + Fixed handler/context start order. - + Fixed web.dtd references. - + Removed race for the starting of session scavaging + + added optimizeit plug Added OptimizeIt plug + + don't chunk 30x empty responses. Don't chunk 30x empty responses. + + fixed /foo/../bar// bug in canonical path. Fixed /foo/../bar// bug in + canonical path. + + fixed "" contextpaths in dispatcher. Fixed "" contextPaths in Dispatcher. + + fixed handler/context start order. Fixed handler/context start order. + + fixed web.dtd references. Fixed web.dtd references. + + removed race for the starting of session scavaging Removed race for the + starting of session scavaging jetty-3.1.8 - 06 June 2002 - + Fixed /foo/../bar// bug in canonical path. - + Fixed no slash context redirection. - + Fixed singled threaded dynamic servlets - + Made SecurityConstraint.addRole() require authentication. + + fixed /foo/../bar// bug in canonical path. Fixed /foo/../bar// bug in + canonical path. + + fixed no slash context redirection. Fixed no slash context redirection. + + fixed singled threaded dynamic servlets Fixed singled threaded dynamic + servlets + + made securityconstraint.addrole() require authentication. Made + SecurityConstraint.addRole() require authentication. jetty-4.1.D0 - 05 June 2002 - + Added OptimizeIt plug. - + Added TypeUtil to reduce Integer creation. - + BRAND NEW WebApplicationHandler & WebApplicationContext - + Experimental CLIENT-CERT Authenticator - + Fixed handler/context start order. - + Fixed web.dtd references. - + General clean up of the API for for MBean getters/setters. - + Removed the HttpMessage facade mechanism - + Restructured ResourceHandler into ResourceBase - + The 4.1 Series started looking for even more performance within the 2.3 + + added optimizeit plug. Added OptimizeIt plug. + + added typeutil to reduce integer creation. Added TypeUtil to reduce Integer + creation. + + brand new webapplicationhandler & webapplicationcontext BRAND NEW + WebApplicationHandler & WebApplicationContext + + experimental client-cert authenticator Experimental CLIENT-CERT + Authenticator + + fixed handler/context start order. Fixed handler/context start order. + + fixed web.dtd references. Fixed web.dtd references. + + general clean up of the api for for mbean getters/setters. General clean up + of the API for for MBean getters/setters. + + removed the httpmessage facade mechanism Removed the HttpMessage facade + mechanism + + restructured resourcehandler into resourcebase Restructured ResourceHandler + into ResourceBase + + the 4.1 series started looking for even more performance within the 2. The + 4.1 Series started looking for even more performance within the 2.3 specification. jetty-4.0.1 - 22 May 2002 - + Fixed "null" return from getRealPath - + Fixed contextclassloader on ServletContextEvents. - + OutputStreamLogSink config improvements - + Support graceful stopping of context and server. - + Updated jasper to 16 May snapshot + + fixed "null" return from getrealpath Fixed "null" return from getRealPath + + fixed contextclassloader on servletcontextevents. Fixed contextclassloader + on ServletContextEvents. + + outputstreamlogsink config improvements OutputStreamLogSink config + improvements + + support graceful stopping of context and server. Support graceful stopping + of context and server. + + updated jasper to 16 may snapshot Updated jasper to 16 May snapshot jetty-4.0.1RC2 - 14 May 2002 - + 3DES Keylength was being reported as 0. Now reports 168 bits. - + Added confidential and integral redirections to HttpListener - + Better error for jre1.3 with 1.4 classes - + Cleaned up RD query string regeneration. - + Fixed ServletResponse.reset() to resetBuffer. - + Implemented the run-as servlet tag. + + 3des keylength was being reported as 0. now reports 168 bits. 3DES Keylength + was being reported as 0. Now reports 168 bits. + + added confidential and integral redirections to httplistener Added + confidential and integral redirections to HttpListener + + better error for jre1.3 with 1.4 classes Better error for jre1.3 with 1.4 + classes + + cleaned up rd query string regeneration. Cleaned up RD query string + regeneration. + + fixed servletresponse.reset() to resetbuffer. Fixed ServletResponse.reset() + to resetBuffer. + + implemented the run-as servlet tag. Implemented the run-as servlet tag. jetty-4.0.1RC1 - 29 April 2002 - + Avoid flushes during RequestDispatcher.includes - + Better handling if no realm configured. - + Expand ByteBuffer full limit with capacity. - + Fixed double filtering of welcome files. - + Fixed FORM authentication auth of login page bug. - + Fixed setTempDirectory creation bug - + Improved flushing of chunked responses + + avoid flushes during requestdispatcher.includes Avoid flushes during + RequestDispatcher.includes + + better handling if no realm configured. Better handling if no realm + configured. + + expand bytebuffer full limit with capacity. Expand ByteBuffer full limit + with capacity. + + fixed double filtering of welcome files. Fixed double filtering of welcome + files. + + fixed form authentication auth of login page bug. Fixed FORM authentication + auth of login page bug. + + fixed settempdirectory creation bug Fixed setTempDirectory creation bug + + improved flushing of chunked responses Improved flushing of chunked + responses jetty-4.0.1RC0 - 18 April 2002 - + AbstractSessionManager sets contextClassLoader for scavanging - + Added extract arg to addWebApplications - + DTD allows static "Get" and "Set" methods to be invoked. - + Extended facade interfaces to HttpResponse.sendError - + Fixed delayed response bug: Stopped HttpConnection consuming input from - timedout connection. - + Moved basic auth handling to HttpRequest - + Pass pathParams via welcome file forward for jsessionid - + Set thread context classloader for webapp load-on-startup inits - + Updated Jasper to CVS snapshot from Apr 18 18:50:59 BST 2002 + + abstractsessionmanager sets contextclassloader for scavanging + AbstractSessionManager sets contextClassLoader for scavanging + + added extract arg to addwebapplications Added extract arg to + addWebApplications + + dtd allows static "get" and "set" methods to be invoked. DTD allows static + "Get" and "Set" methods to be invoked. + + extended facade interfaces to httpresponse.senderror Extended facade + interfaces to HttpResponse.sendError + + fixed delayed response bug: stopped httpconnection consuming input fro Fixed + delayed response bug: Stopped HttpConnection consuming input from timedout + connection. + + moved basic auth handling to httprequest Moved basic auth handling to + HttpRequest + + pass pathparams via welcome file forward for jsessionid Pass pathParams via + welcome file forward for jsessionid + + set thread context classloader for webapp load-on-startup inits Set thread + context classloader for webapp load-on-startup inits + + updated jasper to cvs snapshot from apr 18 18:50:59 bst 2002 Updated Jasper + to CVS snapshot from Apr 18 18:50:59 BST 2002 jetty-4.0.0 - 22 March 2002 - + Added IPAddressHandler for IP restrictions - + Jetty.sh cygwin support - + Minor documentation updates. - + Updated contributors. - + Updated tutorial configure version + + added ipaddresshandler for ip restrictions Added IPAddressHandler for IP + restrictions + + jetty.sh cygwin support Jetty.sh cygwin support + + minor documentation updates. Minor documentation updates. + + updated contributors. Updated contributors. + + updated tutorial configure version Updated tutorial configure version jetty-4.0.RC3 - 20 March 2002 - + Changed html attribute order for mozilla quirk. - + ContextInitialized notified before load-on-startup servlets. - + Fixed ZZZ offset format to +/-HHMM - + JDBCUserRealm instantiates JDBC driver - + Suppress WriterOutputStream warning. - + Updated history + + changed html attribute order for mozilla quirk. Changed html attribute order + for mozilla quirk. + + contextinitialized notified before load-on-startup servlets. + ContextInitialized notified before load-on-startup servlets. + + fixed zzz offset format to +/-hhmm Fixed ZZZ offset format to +/-HHMM + + jdbcuserrealm instantiates jdbc driver JDBCUserRealm instantiates JDBC + driver + + suppress writeroutputstream warning. Suppress WriterOutputStream warning. + + updated history Updated history jetty-4.0.RC2 - 12 March 2002 - + Added experimental nio SocketChannelListener - + Added skeleton load balancer - + Disabled the Password EXEC mechanism by default - + Dont try to extract directories - + Fixed column name in JDBCUserRealm - + Fixed empty referrer in NCSA log. - + Fixed security constraint problem with // - + Fixed version for String XmlConfigurations - + Removed redundant sessionID check. - + Remove last of the Class.forName calls. - + Security FAQ + + added experimental nio socketchannellistener Added experimental nio + SocketChannelListener + + added skeleton load balancer Added skeleton load balancer + + disabled the password exec mechanism by default Disabled the Password EXEC + mechanism by default + + dont try to extract directories Dont try to extract directories + + fixed column name in jdbcuserrealm Fixed column name in JDBCUserRealm + + fixed empty referrer in ncsa log. Fixed empty referrer in NCSA log. + + fixed security constraint problem with // Fixed security constraint problem + with // + + fixed version for string xmlconfigurations Fixed version for String + XmlConfigurations + + removed redundant sessionid check. Removed redundant sessionID check. + + remove last of the class.forname calls. Remove last of the Class.forName + calls. + + security faq Security FAQ jetty-3.1.7 - 12 March 2002 - + Fixed security problem with constraints being bypassed with // in URLs + + fixed security problem with constraints being bypassed with // in urls Fixed + security problem with constraints being bypassed with // in URLs jetty-4.0.RC1 - 06 March 2002 - + Added ContentEncodingHandler for compression. - + Call response.flushBuffer after service to flush wrappers. - + contextDestroyed event sent before destruction. - + Contributors list as an image to prevent SPAM! - + Empty suffix for temp directory. - + FileResource depends less on FilePermissions. - + Fixed filter vs forward bug. - + Fixed recursive DEBUG loop in Logging. - + Improved efficiency of quality list handling - + Minor changes to make HttpServer work on J2ME CVM - + Simplified filter API to chunkable streams - + Updated jetty.sh to always respect arguments. - + Warn if jdk 1.4 classes used on JVM <1.4 - + WebApplication will use ContextLoader even without WEB-INF directory. - + XmlParser is validating by default. use o.m.x.XmlParser.NotValidating + + added contentencodinghandler for compression. Added ContentEncodingHandler + for compression. + + call response.flushbuffer after service to flush wrappers. Call + response.flushBuffer after service to flush wrappers. + + contextdestroyed event sent before destruction. contextDestroyed event sent + before destruction. + + contributors list as an image to prevent spam! Contributors list as an image + to prevent SPAM! + + empty suffix for temp directory. Empty suffix for temp directory. + + fileresource depends less on filepermissions. FileResource depends less on + FilePermissions. + + fixed filter vs forward bug. Fixed filter vs forward bug. + + fixed recursive debug loop in logging. Fixed recursive DEBUG loop in + Logging. + + improved efficiency of quality list handling Improved efficiency of quality + list handling + + minor changes to make httpserver work on j2me cvm Minor changes to make + HttpServer work on J2ME CVM + + simplified filter api to chunkable streams Simplified filter API to + chunkable streams + + updated jetty.sh to always respect arguments. Updated jetty.sh to always + respect arguments. + + warn if jdk 1.4 classes used on jvm <1.4 Warn if jdk 1.4 classes used on JVM + <1.4 + + webapplication will use contextloader even without web-inf directory. + WebApplication will use ContextLoader even without WEB-INF directory. + + xmlparser is validating by default. use o.m.x.xmlparser.notvalidating + XmlParser is validating by default. use o.m.x.XmlParser.NotValidating property to change. jetty-3.1.6 - 28 February 2002 - + Dispatcher.forward dispatches directly to ServletHolder to avoid premature + + dispatcher.forward dispatches directly to servletholder to avoid prema + Dispatcher.forward dispatches directly to ServletHolder to avoid premature exception handling. - + Empty suffix for temp directory. - + Fixed HttpFields remove bug - + HttpResponse.sendError makes a better attempt at finding an error page. - + Implemented 2.3 clarifications to security constraint semantics PLEASE + + empty suffix for temp directory. Empty suffix for temp directory. + + fixed httpfields remove bug Fixed HttpFields remove bug + + httpresponse.senderror makes a better attempt at finding an error page + HttpResponse.sendError makes a better attempt at finding an error page. + + implemented 2.3 clarifications to security constraint semantics please + Implemented 2.3 clarifications to security constraint semantics PLEASE REVIEW YOUR SECURITY CONSTRAINTS (see README). - + LineInput can handle any sized marks - + Set Listeners default scheme + + lineinput can handle any sized marks LineInput can handle any sized marks + + set listeners default scheme Set Listeners default scheme jetty-4.0.B2 - 25 February 2002 - + Accept jetty-web.xml or web-jetty.xml in WEB-INF - + Added LoggerLogSink to direct Jetty Logs to JDK1.4 Log. - + Added optional JDK 1.4 src tree - + Added org.mortbay.http.JDBCUserRealm - + Added String constructor to XmlConfiguration. - + Adjust servlet facades for welcome redirection - + Improved default jetty.xml - + Improve handling of unknown URL protocols. - + Init classloader for JspServlet - + Minor Jasper updates - + o.m.u.Frame uses JDK1.4 stack frame handling - + Simplified addWebApplication - + Slightly more agressive eating unused input from non persistent connection. - + Start ServletHandler as part of the FilterHandler start. - + User / mapping rather than /* for servlet requests to static content + + accept jetty-web.xml or web-jetty.xml in web-inf Accept jetty-web.xml or + web-jetty.xml in WEB-INF + + added loggerlogsink to direct jetty logs to jdk1.4 log. Added LoggerLogSink + to direct Jetty Logs to JDK1.4 Log. + + added optional jdk 1.4 src tree Added optional JDK 1.4 src tree + + added org.mortbay.http.jdbcuserrealm Added org.mortbay.http.JDBCUserRealm + + added string constructor to xmlconfiguration. Added String constructor to + XmlConfiguration. + + adjust servlet facades for welcome redirection Adjust servlet facades for + welcome redirection + + improved default jetty.xml Improved default jetty.xml + + improve handling of unknown url protocols. Improve handling of unknown URL + protocols. + + init classloader for jspservlet Init classloader for JspServlet + + minor jasper updates Minor Jasper updates + + o.m.u.frame uses jdk1.4 stack frame handling o.m.u.Frame uses JDK1.4 stack + frame handling + + simplified addwebapplication Simplified addWebApplication + + slightly more agressive eating unused input from non persistent connec + Slightly more agressive eating unused input from non persistent connection. + + start servlethandler as part of the filterhandler start. Start + ServletHandler as part of the FilterHandler start. + + user / mapping rather than /* for servlet requests to static content User / + mapping rather than /* for servlet requests to static content jetty-4.0.B1 - 13 February 2002 - + Added setClassLoader and moved getFileClassPath to HttpContext - + getRequestURI returns encoded path - + HttpConnection always eats unused bodies - + LineInput waits for LF after CF if seen CRLF before. - + Merged HttpMessage and Message - + Servlet request destined for static content returns paths as default servlet - + Suppress error only for IOExceptions not derivitives. - + Updated examples webapp from tomcat - + WriterOutputStream so JSPs can include static resources. + + added setclassloader and moved getfileclasspath to httpcontext Added + setClassLoader and moved getFileClassPath to HttpContext + + getrequesturi returns encoded path getRequestURI returns encoded path + + httpconnection always eats unused bodies HttpConnection always eats unused + bodies + + lineinput waits for lf after cf if seen crlf before. LineInput waits for LF + after CF if seen CRLF before. + + merged httpmessage and message Merged HttpMessage and Message + + servlet request destined for static content returns paths as default s + Servlet request destined for static content returns paths as default servlet + + suppress error only for ioexceptions not derivitives. Suppress error only + for IOExceptions not derivitives. + + updated examples webapp from tomcat Updated examples webapp from tomcat + + writeroutputstream so jsps can include static resources. WriterOutputStream + so JSPs can include static resources. jetty-4.0.B0 - 04 February 2002 - + Added AbstractSessionManager - + Added Array element to XMLConfiguration - + Added hack for compat tests in watchdog for old tomcat stuff - + Added index links to tutorial - + Allow listener schemes to be set. - + Common handling of TRACE - + Factor out RolloverFileOutputStream from OutputStreamLogSink - + Fixed HttpFields remove bug - + Handle special characters in resource file names better. - + HttpContext destroy - + Implemented 2.3 security constraint semantics PLEASE REVIEW YOUR SECURITY + + added abstractsessionmanager Added AbstractSessionManager + + added array element to xmlconfiguration Added Array element to + XMLConfiguration + + added hack for compat tests in watchdog for old tomcat stuff Added hack for + compat tests in watchdog for old tomcat stuff + + added index links to tutorial Added index links to tutorial + + allow listener schemes to be set. Allow listener schemes to be set. + + common handling of trace Common handling of TRACE + + factor out rolloverfileoutputstream from outputstreamlogsink Factor out + RolloverFileOutputStream from OutputStreamLogSink + + fixed httpfields remove bug Fixed HttpFields remove bug + + handle special characters in resource file names better. Handle special + characters in resource file names better. + + httpcontext destroy HttpContext destroy + + implemented 2.3 security constraint semantics please review your secur + Implemented 2.3 security constraint semantics PLEASE REVIEW YOUR SECURITY CONSTRAINTS (see README). - + Reduce object count and add hash width to StringMap - + Release process builds JettyExtra - + Removed triggers from Code. - + Remove request logSink and replace with RequestLog using - RolloverFileOutputStream - + Renamed getHttpServers and added setAnonymous - + Stop and remove NotFound context for HttpServer - + Support Random Session IDs in HashSessionManager. - + Updated crimson to 1.1.3 - + Updated tutorial and FAQ - + Welcome file dispatch sets requestURI. - + Welcome files may be relative + + reduce object count and add hash width to stringmap Reduce object count and + add hash width to StringMap + + release process builds jettyextra Release process builds JettyExtra + + removed triggers from code. Removed triggers from Code. + + remove request logsink and replace with requestlog using Remove request + logSink and replace with RequestLog using RolloverFileOutputStream + + renamed gethttpservers and added setanonymous Renamed getHttpServers and + added setAnonymous + + stop and remove notfound context for httpserver Stop and remove NotFound + context for HttpServer + + support random session ids in hashsessionmanager. Support Random Session IDs + in HashSessionManager. + + updated crimson to 1.1.3 Updated crimson to 1.1.3 + + updated tutorial and faq Updated tutorial and FAQ + + welcome file dispatch sets requesturi. Welcome file dispatch sets + requestURI. + + welcome files may be relative Welcome files may be relative jetty-4.0.D4 - 14 January 2002 - + Added BlueRibbon campaign. - + Added isAuthenticated to UserPrincipal - + Extract WAR files to standard temp directory - + Fixed noaccess auth demo. - + FORM auth caches UserPrincipal - + Handle ServletRequestWrappers for Generic Servlets - + Improved handling of UnavailableException - + Improved HttpResponsse.sendError error page matching. - + Prevent output after forward - + RequestDispatcher uses cached resources for include - + URI uses UTF8 for % encodings. + + added blueribbon campaign. Added BlueRibbon campaign. + + added isauthenticated to userprincipal Added isAuthenticated to + UserPrincipal + + extract war files to standard temp directory Extract WAR files to standard + temp directory + + fixed noaccess auth demo. Fixed noaccess auth demo. + + form auth caches userprincipal FORM auth caches UserPrincipal + + handle servletrequestwrappers for generic servlets Handle + ServletRequestWrappers for Generic Servlets + + improved handling of unavailableexception Improved handling of + UnavailableException + + improved httpresponsse.senderror error page matching. Improved + HttpResponsse.sendError error page matching. + + prevent output after forward Prevent output after forward + + requestdispatcher uses cached resources for include RequestDispatcher uses + cached resources for include + + uri uses utf8 for % encodings. URI uses UTF8 for % encodings. jetty-4.0.D3 - 31 December 2001 - + cookies with maxAge==0 expire on 1 jan 1970 - + Corrected name to HTTP_REFERER in CGI Servlet. - + DateCache handles misses better. - + Fixed cached filter wrapping. - + Fixed ContextLoader lib handling. - + Fixed getLocale again - + Fixed UrlEncoding for % + combination. - + Generalized temp file handling - + HttpFields uses DateCache more. - + Made Frame members private and fixed test harness - + Moved admin port to 8081 to avoid JBuilder - + Patch jasper to 20011229101000 - + Removed limits on mark in LineInput. - + setCookie always has equals + + cookies with maxage==0 expire on 1 jan 1970 cookies with maxAge==0 expire on + 1 jan 1970 + + corrected name to http_referer in cgi servlet. Corrected name to + HTTP_REFERER in CGI Servlet. + + datecache handles misses better. DateCache handles misses better. + + fixed cached filter wrapping. Fixed cached filter wrapping. + + fixed contextloader lib handling. Fixed ContextLoader lib handling. + + fixed getlocale again Fixed getLocale again + + fixed urlencoding for % + combination. Fixed UrlEncoding for % + + combination. + + generalized temp file handling Generalized temp file handling + + httpfields uses datecache more. HttpFields uses DateCache more. + + made frame members private and fixed test harness Made Frame members private + and fixed test harness + + moved admin port to 8081 to avoid jbuilder Moved admin port to 8081 to avoid + JBuilder + + patch jasper to 20011229101000 Patch jasper to 20011229101000 + + removed limits on mark in lineinput. Removed limits on mark in LineInput. + + setcookie always has equals setCookie always has equals jetty-3.1.5 - 11 December 2001 - + Allow POSTs to static resources. - + Branched at Jetty_3_1 - + cookies with maxage==0 expired 1 jan 1970 - + Fixed ChunableInputStream.resetStream bug. - + Fixed formatting of redirectURLs for NS4.08 - + Ignore IO errors when trying to persist connections. - + setCookie always has equals for cookie value - + stopJob/killStop in ThreadPool to improve stopping ThreadedServer on some + + allow posts to static resources. Allow POSTs to static resources. + + branched at jetty_3_1 Branched at Jetty_3_1 + + cookies with maxage==0 expired 1 jan 1970 cookies with maxage==0 expired 1 + jan 1970 + + fixed chunableinputstream.resetstream bug. Fixed + ChunableInputStream.resetStream bug. + + fixed formatting of redirecturls for ns4.08 Fixed formatting of redirectURLs + for NS4.08 + + ignore io errors when trying to persist connections. Ignore IO errors when + trying to persist connections. + + setcookie always has equals for cookie value setCookie always has equals for + cookie value + + stopjob/killstop in threadpool to improve stopping threadedserver on s + stopJob/killStop in ThreadPool to improve stopping ThreadedServer on some platforms. jetty-4.0.D2 - 02 December 2001 - + added addWebApplications auto discovery - + Allow POSTs to static resources. - + Better handling of charset in form encoding. - + Disabled last forwarding by setPath() - + Fixed ChunableInputStream.resetStream bug. - + Fixed formatting of redirect URLs. - + Ignore IO errors when trying to persist connections. - + Made the root context a webapplication. - + Moved demo docroot/servlets to demo directory - + New event model to decouple from beans container. - + Removed Demo.java (until updated). - + Removed ForwardHandler. - + Removed most of the old doco, which needs to be rewritten and added again. - + Removed Request set methods (will be replaced) - + Restructured for demo and test hierarchies - + stopJob/killStop in ThreadPool to improve stopping ThreadedServer on some + + added addwebapplications auto discovery added addWebApplications auto + discovery + + allow posts to static resources. Allow POSTs to static resources. + + better handling of charset in form encoding. Better handling of charset in + form encoding. + + disabled last forwarding by setpath() Disabled last forwarding by setPath() + + fixed chunableinputstream.resetstream bug. Fixed + ChunableInputStream.resetStream bug. + + fixed formatting of redirect urls. Fixed formatting of redirect URLs. + + ignore io errors when trying to persist connections. Ignore IO errors when + trying to persist connections. + + made the root context a webapplication. Made the root context a + webapplication. + + moved demo docroot/servlets to demo directory Moved demo docroot/servlets to + demo directory + + new event model to decouple from beans container. New event model to + decouple from beans container. + + removed demo.java (until updated). Removed Demo.java (until updated). + + removed forwardhandler. Removed ForwardHandler. + + removed most of the old doco, which needs to be rewritten and added ag + Removed most of the old doco, which needs to be rewritten and added again. + + removed request set methods (will be replaced) Removed Request set methods + (will be replaced) + + restructured for demo and test hierarchies Restructured for demo and test + hierarchies + + stopjob/killstop in threadpool to improve stopping threadedserver on s + stopJob/killStop in ThreadPool to improve stopping ThreadedServer on some platforms. jetty-4.0.D1 - 14 November 2001 - + Added Context and Session Event Handling - + Added FilterHandler - + Added FilterHolder - + Changed HandlerContext to HttpContext - + Fixed bug with request dispatcher parameters - + Fixed ServletHandler with no servlets - + New ContextLoader implementation. - + New Dispatcher implementation - + Removed destroy methods - + Simplified MultiMap - + Simplified ServletHandler + + added context and session event handling Added Context and Session Event + Handling + + added filterhandler Added FilterHandler + + added filterholder Added FilterHolder + + changed handlercontext to httpcontext Changed HandlerContext to HttpContext + + fixed bug with request dispatcher parameters Fixed bug with request + dispatcher parameters + + fixed servlethandler with no servlets Fixed ServletHandler with no servlets + + new contextloader implementation. New ContextLoader implementation. + + new dispatcher implementation New Dispatcher implementation + + removed destroy methods Removed destroy methods + + simplified multimap Simplified MultiMap + + simplified servlethandler Simplified ServletHandler jetty-4.0.D0 - 06 November 2001 - + 1.2 JSP API - + 2.3 Servlet API - + Added examples webapp from tomcat4 - + Branched at Jetty_3_1 - + Branched from Jetty_3_1 == Jetty_3_1_4 - + Jasper from tomcat4 - + Start SessionManager abstraction. + + 1.2 jsp api 1.2 JSP API + + 2.3 servlet api 2.3 Servlet API + + added examples webapp from tomcat4 Added examples webapp from tomcat4 + + branched at jetty_3_1 Branched at Jetty_3_1 + + branched from jetty_3_1 == jetty_3_1_4 Branched from Jetty_3_1 == + Jetty_3_1_4 + + jasper from tomcat4 Jasper from tomcat4 + + start sessionmanager abstraction. Start SessionManager abstraction. jetty-3.1.4 - 06 November 2001 - + Added RequestLogFormat to allow extensible request logs. - + Default PathMap separator changed to ":," - + Generate session unbind events on a context.stop() - + getRealPath accepts \ URI separator on platforms using \ file separator. - + HTAccessHandler made stricter on misconfiguration - + PathMap now ignores paths after ; or ? characters. - + Remove old stuff from contrib that had been moved to extra - + Support the ZZZ timezone offset format in DateCache + + added requestlogformat to allow extensible request logs. Added + RequestLogFormat to allow extensible request logs. + + default pathmap separator changed to ":," Default PathMap separator changed + to ":," + + generate session unbind events on a context.stop() Generate session unbind + events on a context.stop() + + getrealpath accepts \ uri separator on platforms using \ file separato + getRealPath accepts \ URI separator on platforms using \ file separator. + + htaccesshandler made stricter on misconfiguration HTAccessHandler made + stricter on misconfiguration + + pathmap now ignores paths after ; or ? characters. PathMap now ignores paths + after ; or ? characters. + + remove old stuff from contrib that had been moved to extra Remove old stuff + from contrib that had been moved to extra + + support the zzz timezone offset format in datecache Support the ZZZ timezone + offset format in DateCache jetty-3.1.3 - 26 October 2001 - + Allow a per context UserRealm instance. - + Correct dispatch to error pages with javax attributes set. - + Fixed binary files in CVS - + Fixed several problems with external role authentication. Role - authentication in JBoss was not working correctly and there were possible - object leaks. The fix required an API change to UserPrinciple and UserRealm. - + Fixed Virtual hosts to case insensitive. - + Fix security problem with trailing special characters. Trailing %00 enabled - JSP source to be viewed or other servlets to be bypassed. - + Improved FORM auth handling of role failure. - + Improved Jasper debug output. - + Improved ThreadedServer timeout defaults - + PathMap spec separator changed from ',' to ':'. May be set with + + allow a per context userrealm instance. Allow a per context UserRealm + instance. + + correct dispatch to error pages with javax attributes set. Correct dispatch + to error pages with javax attributes set. + + fixed binary files in cvs Fixed binary files in CVS + + fixed several problems with external role authentication. role Fixed several + problems with external role authentication. Role authentication in JBoss was + not working correctly and there were possible object leaks. The fix required + an API change to UserPrinciple and UserRealm. + + fixed virtual hosts to case insensitive. Fixed Virtual hosts to case + insensitive. + + fix security problem with trailing special characters. trailing %00 en Fix + security problem with trailing special characters. Trailing %00 enabled JSP + source to be viewed or other servlets to be bypassed. + + improved form auth handling of role failure. Improved FORM auth handling of + role failure. + + improved jasper debug output. Improved Jasper debug output. + + improved threadedserver timeout defaults Improved ThreadedServer timeout + defaults + + pathmap spec separator changed from ',' to ':'. may be set with PathMap spec + separator changed from ',' to ':'. May be set with org.mortbay.http.PathMap.separators system property. - + Upgraded JSSE to 1.0.2 + + upgraded jsse to 1.0.2 Upgraded JSSE to 1.0.2 jetty-3.1.2 - 13 October 2001 - + Added run target to ant - + Added ServletHandler.sessionCount() - + Added short delay to shutdown hook for JVM bug. - + Changed 304 responses for Opera browser. - + Changed JSESSIONID to jsessionid - + Changed unsatisfiable range warnings to debug. - + Fixed attr handling in XmlParser.toString - + Fixed authentication role handling in FORM auth. - + Fixed double entry on PathMap.getMatches - + Fixed FORM Authentication username. - + Fixed NotFoundHandler handling of unknown methods - + Fixed request log date formatting - + Fixed servlet handling of non session url params. - + FORM authentication passes query params. - + Further improvements in handling of shutdown. - + Log OK state after thread low warnings. + + added run target to ant Added run target to ant + + added servlethandler.sessioncount() Added ServletHandler.sessionCount() + + added short delay to shutdown hook for jvm bug. Added short delay to + shutdown hook for JVM bug. + + changed 304 responses for opera browser. Changed 304 responses for Opera + browser. + + changed jsessionid to jsessionid Changed JSESSIONID to jsessionid + + changed unsatisfiable range warnings to debug. Changed unsatisfiable range + warnings to debug. + + fixed attr handling in xmlparser.tostring Fixed attr handling in + XmlParser.toString + + fixed authentication role handling in form auth. Fixed authentication role + handling in FORM auth. + + fixed double entry on pathmap.getmatches Fixed double entry on + PathMap.getMatches + + fixed form authentication username. Fixed FORM Authentication username. + + fixed notfoundhandler handling of unknown methods Fixed NotFoundHandler + handling of unknown methods + + fixed request log date formatting Fixed request log date formatting + + fixed servlet handling of non session url params. Fixed servlet handling of + non session url params. + + form authentication passes query params. FORM authentication passes query + params. + + further improvements in handling of shutdown. Further improvements in + handling of shutdown. + + log ok state after thread low warnings. Log OK state after thread low + warnings. jetty-3.1.1 - 27 September 2001 - + Correctly ignore auth-constraint descriptions. - + Fixed jar manifest format - patched 28 Sep 2001 - + Fixed ServletRequest.getLocale(). - + Handle requestdispatcher during init. - + Reduced verbosity of bad URL errors from IIS virus attacks - + Removed incorrect warning for WEB-INF/lib jar files. - + Removed JDK 1.3 dependancy - + Use lowercase tags in html package to be XHTML-like. + + correctly ignore auth-constraint descriptions. Correctly ignore + auth-constraint descriptions. + + fixed jar manifest format - patched 28 sep 2001 Fixed jar manifest format - + patched 28 Sep 2001 + + fixed servletrequest.getlocale(). Fixed ServletRequest.getLocale(). + + handle requestdispatcher during init. Handle requestdispatcher during init. + + reduced verbosity of bad url errors from iis virus attacks Reduced verbosity + of bad URL errors from IIS virus attacks + + removed incorrect warning for web-inf/lib jar files. Removed incorrect + warning for WEB-INF/lib jar files. + + removed jdk 1.3 dependancy Removed JDK 1.3 dependancy + + use lowercase tags in html package to be xhtml-like. Use lowercase tags in + html package to be XHTML-like. jetty-3.1.0 - 21 September 2001 - + Added HandlerContext.registerHost - + Added long overdue Tutorial documentation. - + Fix .. handling in URI - + Fix flush on stop bug in logs. - + Fix FORM authentication on exact patterns - + Fix Jetty.bat for spaces. - + Fix param reading on CGI servlet - + Fix REFFERER in CGI - + Fix ResourceHandler cache invalidate. - + Fix reuse of Resource - + Fix ServletResponse.setLocale() - + Improved closing of listeners. - + Improved some other documentation. - + New simplified jetty.bat - + Optimized List creation - + Removed win32 service.exe + + added handlercontext.registerhost Added HandlerContext.registerHost + + added long overdue tutorial documentation. Added long overdue Tutorial + documentation. + + fix .. handling in uri Fix .. handling in URI + + fix flush on stop bug in logs. Fix flush on stop bug in logs. + + fix form authentication on exact patterns Fix FORM authentication on exact + patterns + + fix jetty.bat for spaces. Fix Jetty.bat for spaces. + + fix param reading on cgi servlet Fix param reading on CGI servlet + + fix refferer in cgi Fix REFFERER in CGI + + fix resourcehandler cache invalidate. Fix ResourceHandler cache invalidate. + + fix reuse of resource Fix reuse of Resource + + fix servletresponse.setlocale() Fix ServletResponse.setLocale() + + improved closing of listeners. Improved closing of listeners. + + improved some other documentation. Improved some other documentation. + + new simplified jetty.bat New simplified jetty.bat + + optimized list creation Optimized List creation + + removed win32 service.exe Removed win32 service.exe jetty-3.1.rc9 - 02 September 2001 - + Added bin/orgPackage.sh script to change package names. - + Added handlerContext.setClassPaths - + Added lowResourcePersistTimeMs for more graceful degradation when we run out - of threads. - + Added support for Nonblocking listener. - + Changed to org.mortbay domain names. - + Fixed bug with non cookie sessions. - + Fixed handling of rel form authentication URLs - + Format cookies in HttpFields. - + Form auth login and error pages relative to context path. - + Patched Jasper to 3.2.3. + + added bin/orgpackage.sh script to change package names. Added + bin/orgPackage.sh script to change package names. + + added handlercontext.setclasspaths Added handlerContext.setClassPaths + + added lowresourcepersisttimems for more graceful degradation when we r Added + lowResourcePersistTimeMs for more graceful degradation when we run out of + threads. + + added support for nonblocking listener. Added support for Nonblocking + listener. + + changed to org.mortbay domain names. Changed to org.mortbay domain names. + + fixed bug with non cookie sessions. Fixed bug with non cookie sessions. + + fixed handling of rel form authentication urls Fixed handling of rel form + authentication URLs + + format cookies in httpfields. Format cookies in HttpFields. + + form auth login and error pages relative to context path. Form auth login + and error pages relative to context path. + + patched jasper to 3.2.3. Patched Jasper to 3.2.3. jetty-3.1.rc8 - 22 August 2001 - + Added HttpServer statistics - + Allow contextpaths without leading / - + Allow per context log files. - + Buffer allocation - + Don't add notfound context. - + Fixed handling of default mime types - + ISO8859 conversion - + Many major and minor optimizations: - + OutputStreamLogSink replaces WriterLogSink - + Removed race from dynamic servlet initialization. - + Separation of URL params in HttpHandler API. - + StringMap - + Support WEB-INF/web-jetty.xml configuration extension for webapps - + Updated sponsors page - + URI canonicalPath - + URI pathAdd + + added httpserver statistics Added HttpServer statistics + + allow contextpaths without leading / Allow contextpaths without leading / + + allow per context log files. Allow per context log files. + + buffer allocation Buffer allocation + + don't add notfound context. Don't add notfound context. + + fixed handling of default mime types Fixed handling of default mime types + + iso8859 conversion ISO8859 conversion + + many major and minor optimizations: Many major and minor optimizations: + + outputstreamlogsink replaces writerlogsink OutputStreamLogSink replaces + WriterLogSink + + removed race from dynamic servlet initialization. Removed race from dynamic + servlet initialization. + + separation of url params in httphandler api. Separation of URL params in + HttpHandler API. + + stringmap StringMap + + support web-inf/web-jetty.xml configuration extension for webapps Support + WEB-INF/web-jetty.xml configuration extension for webapps + + updated sponsors page Updated sponsors page + + uri canonicalpath URI canonicalPath + + uri pathadd URI pathAdd jetty-3.1.rc7 - 09 August 2001 - + Added doco for Linux port redirection. - + Added FORM authentication. - + Added method handling to HTAccessHandler. - + Added shutdown hooks to Jetty.Server to trap Ctl-C - + Added UML diagrams to Jetty architecture documentation. - + Added utility methods to ServletHandler for wrapping req/res pairs. - + Don't persist connections if low on threads. - + Dump Servlet displays cert chains - + Fix bug in sendRedirect for HTTP/1.1 - + Fixed bug with session ID generation. - + Fixed redirect handling by the CGI Servlet. - + Fixed request.getPort for redirections from 80 - + Optimized HttpField handling to reduce object creatiyon. - + Remove old context path specs - + ServletRequest SSL attributes in line with 2.2 and 2.3 specs. - + ServletResponse.sendRedirect puts URLs into absolute format. - + Use Enumerations to reduce conversions for servlet API. + + added doco for linux port redirection. Added doco for Linux port + redirection. + + added form authentication. Added FORM authentication. + + added method handling to htaccesshandler. Added method handling to + HTAccessHandler. + + added shutdown hooks to jetty.server to trap ctl-c Added shutdown hooks to + Jetty.Server to trap Ctl-C + + added uml diagrams to jetty architecture documentation. Added UML diagrams + to Jetty architecture documentation. + + added utility methods to servlethandler for wrapping req/res pairs. Added + utility methods to ServletHandler for wrapping req/res pairs. + + don't persist connections if low on threads. Don't persist connections if + low on threads. + + dump servlet displays cert chains Dump Servlet displays cert chains + + fix bug in sendredirect for http/1.1 Fix bug in sendRedirect for HTTP/1.1 + + fixed bug with session id generation. Fixed bug with session ID generation. + + fixed redirect handling by the cgi servlet. Fixed redirect handling by the + CGI Servlet. + + fixed request.getport for redirections from 80 Fixed request.getPort for + redirections from 80 + + optimized httpfield handling to reduce object creatiyon. Optimized HttpField + handling to reduce object creatiyon. + + remove old context path specs Remove old context path specs + + servletrequest ssl attributes in line with 2.2 and 2.3 specs. ServletRequest + SSL attributes in line with 2.2 and 2.3 specs. + + servletresponse.sendredirect puts urls into absolute format. + ServletResponse.sendRedirect puts URLs into absolute format. + + use enumerations to reduce conversions for servlet api. Use Enumerations to + reduce conversions for servlet API. jetty-3.1.rc6 - 10 July 2001 - + Added Client authentication to the JsseListener - + Added debug and logging config example to demo.xml - + Added Get element to the XmlConfiguration class. - + Added getResource to HandleContext. - + Added Static calls to the XmlConfiguration class. - + Avoid script vulnerability in error pages. - + Cleaned up destroy handling of listeners and contexts. - + Cleaned up Win32 Service server creation. - + Close persistent HTTP/1.0 connections on missing Content-Length - + Fixed a problem with Netscape and the acrobat plugin. - + Fixed bug in B64Code. Optimised B64Code. - + Fixed XmlParser to handle xerces1.3 OK - + Improved debug output for IOExceptions. - + Improved SSL debugging information. - + KeyPairTool can now load cert chains. - + KeyPairTool is more robust to provider setup. - + Moved gimp image files to Jetty3Extra - + Moved mime types and encodings to property bundles. - + Removed getConfiguration from LifeCycleThread to avoid JMX clash. - + RequestDispatch.forward() uses normal HandlerContext.handle() path if + + added client authentication to the jsselistener Added Client authentication + to the JsseListener + + added debug and logging config example to demo.xml Added debug and logging + config example to demo.xml + + added get element to the xmlconfiguration class. Added Get element to the + XmlConfiguration class. + + added getresource to handlecontext. Added getResource to HandleContext. + + added static calls to the xmlconfiguration class. Added Static calls to the + XmlConfiguration class. + + avoid script vulnerability in error pages. Avoid script vulnerability in + error pages. + + cleaned up destroy handling of listeners and contexts. Cleaned up destroy + handling of listeners and contexts. + + cleaned up win32 service server creation. Cleaned up Win32 Service server + creation. + + close persistent http/1.0 connections on missing content-length Close + persistent HTTP/1.0 connections on missing Content-Length + + fixed a problem with netscape and the acrobat plugin. Fixed a problem with + Netscape and the acrobat plugin. + + fixed bug in b64code. optimised b64code. Fixed bug in B64Code. Optimised + B64Code. + + fixed xmlparser to handle xerces1.3 ok Fixed XmlParser to handle xerces1.3 + OK + + improved debug output for ioexceptions. Improved debug output for + IOExceptions. + + improved ssl debugging information. Improved SSL debugging information. + + keypairtool can now load cert chains. KeyPairTool can now load cert chains. + + keypairtool is more robust to provider setup. KeyPairTool is more robust to + provider setup. + + moved gimp image files to jetty3extra Moved gimp image files to Jetty3Extra + + moved mime types and encodings to property bundles. Moved mime types and + encodings to property bundles. + + removed getconfiguration from lifecyclethread to avoid jmx clash. Removed + getConfiguration from LifeCycleThread to avoid JMX clash. + + requestdispatch.forward() uses normal handlercontext.handle() path if + RequestDispatch.forward() uses normal HandlerContext.handle() path if possible. - + Updated to JSSE-1.0.2, giving full strength crypto. - + Use exec for jetty.sh run - + WebApps initialize resourceBase before start. - + Win32 Service uses Jetty.Server instead of HttpServer. + + updated to jsse-1.0.2, giving full strength crypto. Updated to JSSE-1.0.2, + giving full strength crypto. + + use exec for jetty.sh run Use exec for jetty.sh run + + webapps initialize resourcebase before start. WebApps initialize + resourceBase before start. + + win32 service uses jetty.server instead of httpserver. Win32 Service uses + Jetty.Server instead of HttpServer. jetty-3.1.rc5 - 01 May 2001 - + Added build target for mini.jetty.jar - see README. - + Added HTaccessHandler to authenitcate against apache .htaccess files. - + Added query param handling to ForwardHandler - + Added ServletHandler().setUsingCookies(). - + Added UnixCrypt support to c.m.U.Password - + Fixed EOF handling in MultiPartRequest. - + Fixed forwarding to null pathInfo requests. - + Fixed handling of empty responses at header commit. - + Fixed handling of multiple cookies. - + Fixed jetty.bat classpath problems. - + Fixed ResourceHandler handling of ;JSESSIONID - + Fixed sync of ThreadPool idleSet. - + Major restructing of packages to separate servlet dependancies. c.m.XML - - moved XML dependant classes from c.m.Util c.m.HTTP - No servlet or XML - dependant classes: c.m.Jetty.Servlet - moved from c.m.HTTP.Handler.Servlet - c.m.Servlet - received some servlet dependant classes from HTTP. - + Optimized canonical path calculations. - + Request log contains bytes actually returned. - + Warn and close connections if content-length is incorrectly set. + + added build target for mini.jetty.jar - see readme. Added build target for + mini.jetty.jar - see README. + + added htaccesshandler to authenitcate against apache .htaccess files. Added + HTaccessHandler to authenitcate against apache .htaccess files. + + added query param handling to forwardhandler Added query param handling to + ForwardHandler + + added servlethandler().setusingcookies(). Added + ServletHandler().setUsingCookies(). + + added unixcrypt support to c.m.u.password Added UnixCrypt support to + c.m.U.Password + + fixed eof handling in multipartrequest. Fixed EOF handling in + MultiPartRequest. + + fixed forwarding to null pathinfo requests. Fixed forwarding to null + pathInfo requests. + + fixed handling of empty responses at header commit. Fixed handling of empty + responses at header commit. + + fixed handling of multiple cookies. Fixed handling of multiple cookies. + + fixed jetty.bat classpath problems. Fixed jetty.bat classpath problems. + + fixed resourcehandler handling of ;jsessionid Fixed ResourceHandler handling + of ;JSESSIONID + + fixed sync of threadpool idleset. Fixed sync of ThreadPool idleSet. + + major restructing of packages to separate servlet dependancies. c.m.xm Major + restructing of packages to separate servlet dependancies. c.m.XML - moved + XML dependant classes from c.m.Util c.m.HTTP - No servlet or XML dependant + classes: c.m.Jetty.Servlet - moved from c.m.HTTP.Handler.Servlet c.m.Servlet + - received some servlet dependant classes from HTTP. + + optimized canonical path calculations. Optimized canonical path + calculations. + + request log contains bytes actually returned. Request log contains bytes + actually returned. + + warn and close connections if content-length is incorrectly set. Warn and + close connections if content-length is incorrectly set. jetty-3.0.6 - 26 April 2001 - + Fixed EOF handlding in MultiPartRequest. - + Fixed forwarding to null pathInfo requests. - + Fixed handling of empty responses at header commit. - + Fixed ResourceHandler handling of ;JSESSIONID - + Fixed sync of ThreadPool idleSet. - + Load-on-startup the JspServlet so that precompiled servlets work. + + fixed eof handlding in multipartrequest. Fixed EOF handlding in + MultiPartRequest. + + fixed forwarding to null pathinfo requests. Fixed forwarding to null + pathInfo requests. + + fixed handling of empty responses at header commit. Fixed handling of empty + responses at header commit. + + fixed resourcehandler handling of ;jsessionid Fixed ResourceHandler handling + of ;JSESSIONID + + fixed sync of threadpool idleset. Fixed sync of ThreadPool idleSet. + + load-on-startup the jspservlet so that precompiled servlets work. + Load-on-startup the JspServlet so that precompiled servlets work. jetty-3.1.rc4 - 14 April 2001 - + Added idle thread getter to ThreadPool. - + Include full versions of JAXP and Crimson - + Load-on-startup the JspServlet so that precompiled servlets work. - + Removed stray debug println from the Frame class. + + added idle thread getter to threadpool. Added idle thread getter to + ThreadPool. + + include full versions of jaxp and crimson Include full versions of JAXP and + Crimson + + load-on-startup the jspservlet so that precompiled servlets work. + Load-on-startup the JspServlet so that precompiled servlets work. + + removed stray debug println from the frame class. Removed stray debug + println from the Frame class. jetty-3.0.5 - 14 April 2001 - + Branched from 3.1 trunk to fix major errors - + Created better random session ID - + Don't chunk if content length is known. - + fixed getLocales handling of quality params - + Fixed LineInput bug EOF - + Fixed session invalidation unbind notification to conform with spec - + Improved flush ordering for forwarded requests. - + Load-on-startup the JspServlet so that precompiled servlets work. - + Resource handler strips URL params like JSESSION. - + Turned off range handling by default until bugs resolved + + branched from 3.1 trunk to fix major errors Branched from 3.1 trunk to fix + major errors + + created better random session id Created better random session ID + + don't chunk if content length is known. Don't chunk if content length is + known. + + fixed getlocales handling of quality params fixed getLocales handling of + quality params + + fixed lineinput bug eof Fixed LineInput bug EOF + + fixed session invalidation unbind notification to conform with spec Fixed + session invalidation unbind notification to conform with spec + + improved flush ordering for forwarded requests. Improved flush ordering for + forwarded requests. + + load-on-startup the jspservlet so that precompiled servlets work. + Load-on-startup the JspServlet so that precompiled servlets work. + + resource handler strips url params like jsession. Resource handler strips + URL params like JSESSION. + + turned off range handling by default until bugs resolved Turned off range + handling by default until bugs resolved jetty-3.1.rc3 - 09 April 2001 - + Added ContentHandler Observer to XmlParser. - + Allow webapp XmlParser to be observed for ejb-ref tags etc. - + Cleaned up handling of exceptions thrown by servlets. - + Created better random session ID - + Frame handles more JIT stacks. - + Handle zero length POSTs - + Implemented multi-part ranges so that acrobat is happy. - + Improved flush ordering for forwarded requests. - + Improved ThreadPool stop handling - + Simplified multipart response class. - + Start session scavenger if needed. + + added contenthandler observer to xmlparser. Added ContentHandler Observer to + XmlParser. + + allow webapp xmlparser to be observed for ejb-ref tags etc. Allow webapp + XmlParser to be observed for ejb-ref tags etc. + + cleaned up handling of exceptions thrown by servlets. Cleaned up handling of + exceptions thrown by servlets. + + created better random session id Created better random session ID + + frame handles more jit stacks. Frame handles more JIT stacks. + + handle zero length posts Handle zero length POSTs + + implemented multi-part ranges so that acrobat is happy. Implemented + multi-part ranges so that acrobat is happy. + + improved flush ordering for forwarded requests. Improved flush ordering for + forwarded requests. + + improved threadpool stop handling Improved ThreadPool stop handling + + simplified multipart response class. Simplified multipart response class. + + start session scavenger if needed. Start session scavenger if needed. jetty-3.1.rc2 - 30 March 2001 - + Added MultiException to throw multiple nested exceptions. - + added options to turn off ranges and chunking to support acrobat requests. - + fixed getLocales handling of quality params - + fixed getParameter(name) handling for multiple values. - + Improved handling of Primitive classes in XmlConfig - + Improved logging of nested exceptions. - + Lifecycle.start() may throw Exception - + Only one instance of default MIME map. - + Renamed getConnection to getHttpConnection - + Use reference JAXP1.1 for XML parsing.y - + Version 1.1 of configuration dtd supports New objects. + + added multiexception to throw multiple nested exceptions. Added + MultiException to throw multiple nested exceptions. + + added options to turn off ranges and chunking to support acrobat reque added + options to turn off ranges and chunking to support acrobat requests. + + fixed getlocales handling of quality params fixed getLocales handling of + quality params + + fixed getparameter(name) handling for multiple values. fixed + getParameter(name) handling for multiple values. + + improved handling of primitive classes in xmlconfig Improved handling of + Primitive classes in XmlConfig + + improved logging of nested exceptions. Improved logging of nested + exceptions. + + lifecycle.start() may throw exception Lifecycle.start() may throw Exception + + only one instance of default mime map. Only one instance of default MIME + map. + + renamed getconnection to gethttpconnection Renamed getConnection to + getHttpConnection + + use reference jaxp1.1 for xml parsing.y Use reference JAXP1.1 for XML + parsing.y + + version 1.1 of configuration dtd supports new objects. Version 1.1 of + configuration dtd supports New objects. jetty-3.1.rc1 - 18 March 2001 - + Added Jetty documentation pages from JettyWiki - + Cleaned up build.xml script - + Fixed problem with ServletContext.getContext(uri) - + Minimal handling of Servlet.log before initialization. - + Moved JMX and SASL handling to Jetty3Extra release - + Resource handler strips URL params like JSESSION. - + Various SSL cleanups + + added jetty documentation pages from jettywiki Added Jetty documentation + pages from JettyWiki + + cleaned up build.xml script Cleaned up build.xml script + + fixed problem with servletcontext.getcontext(uri) Fixed problem with + ServletContext.getContext(uri) + + minimal handling of servlet.log before initialization. Minimal handling of + Servlet.log before initialization. + + moved jmx and sasl handling to jetty3extra release Moved JMX and SASL + handling to Jetty3Extra release + + resource handler strips url params like jsession. Resource handler strips + URL params like JSESSION. + + various ssl cleanups Various SSL cleanups jetty-3.1.rc0 - 23 February 2001 - + Added JMX management framework. - + Changed getter and setter methods that did not conform to beans API. - + Dynamic servlets may be restricted to Context classloader. - + Fixed init order for unnamed servlets. - + Fixed session invalidation unbind notification to conform with spec - + Improved handling of primitives in utilities. - + Improved InetAddrPort and ThreadedServer to reduce DNS lookups. - + Reoganized packages to allowed sealed Jars - + Socket made available via HttpConnection. - + Use Thread context classloader as default context loader parent. + + added jmx management framework. Added JMX management framework. + + changed getter and setter methods that did not conform to beans api. Changed + getter and setter methods that did not conform to beans API. + + dynamic servlets may be restricted to context classloader. Dynamic servlets + may be restricted to Context classloader. + + fixed init order for unnamed servlets. Fixed init order for unnamed + servlets. + + fixed session invalidation unbind notification to conform with spec Fixed + session invalidation unbind notification to conform with spec + + improved handling of primitives in utilities. Improved handling of + primitives in utilities. + + improved inetaddrport and threadedserver to reduce dns lookups. Improved + InetAddrPort and ThreadedServer to reduce DNS lookups. + + reoganized packages to allowed sealed jars Reoganized packages to allowed + sealed Jars + + socket made available via httpconnection. Socket made available via + HttpConnection. + + use thread context classloader as default context loader parent. Use Thread + context classloader as default context loader parent. jetty-3.0.4 - 23 February 2001 - + Fixed LineInput bug with split CRLF. + + fixed lineinput bug with split crlf. Fixed LineInput bug with split CRLF. jetty-3.0.3 - 03 February 2001 - + Allow Log to be disabled before initialization. - + Fixed handling of directories without trailing / - + Fixed pipelined request buffer bug. - + Handle empty form content without exception. - + Implemented web.xml servlet mapping to a JSP - + Included new Jetty Logo + + allow log to be disabled before initialization. Allow Log to be disabled + before initialization. + + fixed handling of directories without trailing / Fixed handling of + directories without trailing / + + fixed pipelined request buffer bug. Fixed pipelined request buffer bug. + + handle empty form content without exception. Handle empty form content + without exception. + + implemented web.xml servlet mapping to a jsp Implemented web.xml servlet + mapping to a JSP + + included new jetty logo Included new Jetty Logo jetty-3.0.2 - 13 January 2001 - + Added etc/jetty.policy as example policy file. - + Allow '+' in path portion of a URL. - + Context specific security permissions. - + Greatly improved buffering in ChunkableOutputStream - + Handle unknown status reasons in HttpResponse - + Ignore included response updates rather than IllegalStateException - + Improved HTML.Block efficiency - + Improved jetty.bat - + Improved jetty.sh - + Padded error bodies for IE bug. - + Removed classloading stats which were causing circular class loading - problems. - + Replaced ResourceHandler FIFO cache with LRU cache. - + Restructured demo site pages. - + Try ISO8859_1 encoding if can't find ISO-8859-1 + + added etc/jetty.policy as example policy file. Added etc/jetty.policy as + example policy file. + + allow '+' in path portion of a url. Allow '+' in path portion of a URL. + + context specific security permissions. Context specific security + permissions. + + greatly improved buffering in chunkableoutputstream Greatly improved + buffering in ChunkableOutputStream + + handle unknown status reasons in httpresponse Handle unknown status reasons + in HttpResponse + + ignore included response updates rather than illegalstateexception Ignore + included response updates rather than IllegalStateException + + improved html.block efficiency Improved HTML.Block efficiency + + improved jetty.bat Improved jetty.bat + + improved jetty.sh Improved jetty.sh + + padded error bodies for ie bug. Padded error bodies for IE bug. + + removed classloading stats which were causing circular class loading Removed + classloading stats which were causing circular class loading problems. + + replaced resourcehandler fifo cache with lru cache. Replaced ResourceHandler + FIFO cache with LRU cache. + + restructured demo site pages. Restructured demo site pages. + + try iso8859_1 encoding if can't find iso-8859-1 Try ISO8859_1 encoding if + can't find ISO-8859-1 jetty-3.0.1 - 20 December 2000 - + Fixed value unbind notification for session invalidation. - + Removed double null check possibility from ServletHolder + + fixed value unbind notification for session invalidation. Fixed value unbind + notification for session invalidation. + + removed double null check possibility from servletholder Removed double null + check possibility from ServletHolder jetty-3.0.0 - 17 December 2000 - + Fixed rel path handling in default configurations. - + Fixed rollover bug in WriterLogSink - + Fixed taglib parsing - + Fixed WriterLogSink init bug - + Improved dtd resolution in XML parser. - + Improved jetty.sh logging - + Optional extract war files. - + Use inner class to avoid double null check sync problems + + fixed rel path handling in default configurations. Fixed rel path handling + in default configurations. + + fixed rollover bug in writerlogsink Fixed rollover bug in WriterLogSink + + fixed taglib parsing Fixed taglib parsing + + fixed writerlogsink init bug Fixed WriterLogSink init bug + + improved dtd resolution in xml parser. Improved dtd resolution in XML + parser. + + improved jetty.sh logging Improved jetty.sh logging + + optional extract war files. Optional extract war files. + + use inner class to avoid double null check sync problems Use inner class to + avoid double null check sync problems jetty-3.0.0.rc8 - 13 December 2000 - + Added ForwardHandler - + Change PathMap handling of /* to give precedence over suffix mapping. - + Default log options changed if in debug mode. - + Forward to welcome pages rather than redirect. - + getSecurityHandler creates handler at position 0. - + Improved exit admin handling - + Jetty.Server catches init exceptions per server - + Mapped *.jsp,*.jsP,*.jSp,*.jSP,*.Jsp,*.JsP,*.JSp,*.JSP - + Optional alias checking added to FileResource. Turned on by default on all + + added forwardhandler Added ForwardHandler + + change pathmap handling of /* to give precedence over suffix mapping. Change + PathMap handling of /* to give precedence over suffix mapping. + + default log options changed if in debug mode. Default log options changed if + in debug mode. + + forward to welcome pages rather than redirect. Forward to welcome pages + rather than redirect. + + getsecurityhandler creates handler at position 0. getSecurityHandler creates + handler at position 0. + + improved exit admin handling Improved exit admin handling + + jetty.server catches init exceptions per server Jetty.Server catches init + exceptions per server + + mapped *.jsp,*.jsp,*.jsp,*.jsp,*.jsp,*.jsp,*.jsp,*.jsp Mapped + *.jsp,*.jsP,*.jSp,*.jSP,*.Jsp,*.JsP,*.JSp,*.JSP + + optional alias checking added to fileresource. turned on by default o + Optional alias checking added to FileResource. Turned on by default on all platforms without the "/" file separator. - + Patched jasper to tomcat 3.2.1 - + Protected META-INF as well as WEB-INF in web applications. - + Removed security constraint on demo admin server. - + Removed some unused variables. - + Removed special characters from source. - + SysV unix init script - + Tidied handling of ".", ".." and "//" in resource paths + + patched jasper to tomcat 3.2.1 Patched jasper to tomcat 3.2.1 + + protected meta-inf as well as web-inf in web applications. Protected + META-INF as well as WEB-INF in web applications. + + removed security constraint on demo admin server. Removed security + constraint on demo admin server. + + removed some unused variables. Removed some unused variables. + + removed special characters from source. Removed special characters from + source. + + sysv unix init script SysV unix init script + + tidied handling of ".", ".." and "//" in resource paths Tidied handling of + ".", ".." and "//" in resource paths jetty-3.0.0.rc7 - 02 December 2000 - + Added Com.mortbay.HTTP.Handler.Servlet.Context.LogSink attribute to Servlet + + added com.mortbay.http.handler.servlet.context.logsink attribute to se Added + Com.mortbay.HTTP.Handler.Servlet.Context.LogSink attribute to Servlet Context. If set, it is used in preference to the system log. - + Added NotFoundServlet - + Added range handling to ResourceHandler. - + Allow dynamic servlets to be served from / - + Auto add a NotFoundHandler if needed. - + CGI servlet handles not found better. - + Changed log options to less verbose defaults. - + Conditionals apply to puts, dels and moves in ResourceHandler. - + Depreciated RollOverLogSink and moved functionality to an improved + + added notfoundservlet Added NotFoundServlet + + added range handling to resourcehandler. Added range handling to + ResourceHandler. + + allow dynamic servlets to be served from / Allow dynamic servlets to be + served from / + + auto add a notfoundhandler if needed. Auto add a NotFoundHandler if needed. + + cgi servlet handles not found better. CGI servlet handles not found better. + + changed log options to less verbose defaults. Changed log options to less + verbose defaults. + + conditionals apply to puts, dels and moves in resourcehandler. Conditionals + apply to puts, dels and moves in ResourceHandler. + + depreciated rolloverlogsink and moved functionality to an improved + Depreciated RollOverLogSink and moved functionality to an improved WriterLogSink. - + Don't set MIME-Version in response. - + Double null lock checks use ThreadPool.__nullLockChecks. - + Extended security constraints (see README and WebApp Demo). - + Fixed security problem with lowercase WEB-INF uris on windows. - + Handle multiple inits of same servlet class. - + PUT, MOVE disabled in WebApplication unless defaults file is passed. - + Set the AcceptRanges header. - + Set thread context classloader during handler start/stop calls. - + Split Debug servlet out of Admin Servlet. - + ThreadedServer.forceStop() now makes a connection to itself to handle + + don't set mime-version in response. Don't set MIME-Version in response. + + double null lock checks use threadpool.__nulllockchecks. Double null lock + checks use ThreadPool.__nullLockChecks. + + extended security constraints (see readme and webapp demo). Extended + security constraints (see README and WebApp Demo). + + fixed security problem with lowercase web-inf uris on windows. Fixed + security problem with lowercase WEB-INF uris on windows. + + handle multiple inits of same servlet class. Handle multiple inits of same + servlet class. + + put, move disabled in webapplication unless defaults file is passed. PUT, + MOVE disabled in WebApplication unless defaults file is passed. + + set the acceptranges header. Set the AcceptRanges header. + + set thread context classloader during handler start/stop calls. Set thread + context classloader during handler start/stop calls. + + split debug servlet out of admin servlet. Split Debug servlet out of Admin + Servlet. + + threadedserver.forcestop() now makes a connection to itself to handle + ThreadedServer.forceStop() now makes a connection to itself to handle non-premptive close. - + URIs accept all characters < 0xff. - + WEB-INF protected by NotFoundServlet rather than security constraint. + + uris accept all characters < 0xff. URIs accept all characters < 0xff. + + web-inf protected by notfoundservlet rather than security constraint. + WEB-INF protected by NotFoundServlet rather than security constraint. jetty-3.0.0.rc6 - 20 November 2000 - + Added ServletWriter that can be disabled. - + Added Win32 service support - + Admin servlet uses unique links for IE. - + Allow HttpMessage state to be manipulated. - + Allow load-on-startup with no content. - + Allow multiple set cookies. - + Corrected a few of the many spelling mistakes. - + don't include classes in release. - + Don't set connection:close for normal HTTP/1.0 responses. - + Don't start HttpServer log sink on add. - + Fixed RollOverFileLogSink bug with extra log files. - + Implemented customizable error pages. - + Implemented resource aliases in HandlerContext - used by Servlet Context - + Improved Log defaults - + Javadoc improvements. - + Map tablib configuration to resource aliases. - + Prevent reloading dynamic servlets at different paths. - + Put extra server and servlet info in header. - + Reduced risk of double null check sync problem. - + RequestDispatcher.forward() only resets buffer, not headers. - + RequestDispatcher new queries params replace old. - + Resource gets systemresources from it's own classloader. - + Servlet init order may be negative. - + Session cookies are given context path - + Sessions try version 1 cookies in set-cookie2 header. - + Simple stats in ContextLoader. - + Version details in header can be suppressed with System property + + added servletwriter that can be disabled. Added ServletWriter that can be + disabled. + + added win32 service support Added Win32 service support + + admin servlet uses unique links for ie. Admin servlet uses unique links for + IE. + + allow httpmessage state to be manipulated. Allow HttpMessage state to be + manipulated. + + allow load-on-startup with no content. Allow load-on-startup with no + content. + + allow multiple set cookies. Allow multiple set cookies. + + corrected a few of the many spelling mistakes. Corrected a few of the many + spelling mistakes. + + don't include classes in release. don't include classes in release. + + don't set connection:close for normal http/1.0 responses. Don't set + connection:close for normal HTTP/1.0 responses. + + don't start httpserver log sink on add. Don't start HttpServer log sink on + add. + + fixed rolloverfilelogsink bug with extra log files. Fixed + RollOverFileLogSink bug with extra log files. + + implemented customizable error pages. Implemented customizable error pages. + + implemented resource aliases in handlercontext - used by servlet conte + Implemented resource aliases in HandlerContext - used by Servlet Context + + improved log defaults Improved Log defaults + + javadoc improvements. Javadoc improvements. + + map tablib configuration to resource aliases. Map tablib configuration to + resource aliases. + + prevent reloading dynamic servlets at different paths. Prevent reloading + dynamic servlets at different paths. + + put extra server and servlet info in header. Put extra server and servlet + info in header. + + reduced risk of double null check sync problem. Reduced risk of double null + check sync problem. + + requestdispatcher.forward() only resets buffer, not headers. + RequestDispatcher.forward() only resets buffer, not headers. + + requestdispatcher new queries params replace old. RequestDispatcher new + queries params replace old. + + resource gets systemresources from it's own classloader. Resource gets + systemresources from it's own classloader. + + servlet init order may be negative. Servlet init order may be negative. + + session cookies are given context path Session cookies are given context + path + + sessions try version 1 cookies in set-cookie2 header. Sessions try version 1 + cookies in set-cookie2 header. + + simple stats in contextloader. Simple stats in ContextLoader. + + version details in header can be suppressed with system property Version + details in header can be suppressed with System property java.com.mortbay.HTTP.Version.paranoid - + Warn for missing WEB-INF or web.xml - + Webapps serve dynamics servlets by default. + + warn for missing web-inf or web.xml Warn for missing WEB-INF or web.xml + + webapps serve dynamics servlets by default. Webapps serve dynamics servlets + by default. jetty-3.0.0.rc5 - 12 November 2000 - + Added debug form to Admin servlet. - + Allow null cookie values - + Avoid jprobe race warnings in DateCache - + Default writer encoding set by mime type if not explicitly set. - + Implemented servlet load ordering. - + Many javadoc cleanups. - + Merged DynamicHandler into ServletHandler. - + Moved JSP classpath hack to ServletHolder - + Pass flush through ServletOut - + Relax webapp rules, accept no web.xml or no WEB-INF - + Removed Makefile build system. - + RequestDispatcher can dispatch static resources. - + Servlet exceptions cause 503 unavailable rather than 500 server error + + added debug form to admin servlet. Added debug form to Admin servlet. + + allow null cookie values Allow null cookie values + + avoid jprobe race warnings in datecache Avoid jprobe race warnings in + DateCache + + default writer encoding set by mime type if not explicitly set. Default + writer encoding set by mime type if not explicitly set. + + implemented servlet load ordering. Implemented servlet load ordering. + + many javadoc cleanups. Many javadoc cleanups. + + merged dynamichandler into servlethandler. Merged DynamicHandler into + ServletHandler. + + moved jsp classpath hack to servletholder Moved JSP classpath hack to + ServletHolder + + pass flush through servletout Pass flush through ServletOut + + relax webapp rules, accept no web.xml or no web-inf Relax webapp rules, + accept no web.xml or no WEB-INF + + removed makefile build system. Removed Makefile build system. + + requestdispatcher can dispatch static resources. RequestDispatcher can + dispatch static resources. + + servlet exceptions cause 503 unavailable rather than 500 server error + Servlet exceptions cause 503 unavailable rather than 500 server error jetty-2.4.9 - 12 November 2000 - + HtmlFilter handles non default encodings - + HttpListener default max idle time = 20s - + HttpListener ignore InterruptedIOExceptions - + HttpRequest.write uses ISO8859_1 encoding. - + Writing HttpRequests encodes path + + htmlfilter handles non default encodings HtmlFilter handles non default + encodings + + httplistener default max idle time = 20s HttpListener default max idle time + = 20s + + httplistener ignore interruptedioexceptions HttpListener ignore + InterruptedIOExceptions + + httprequest.write uses iso8859_1 encoding. HttpRequest.write uses ISO8859_1 + encoding. + + writing httprequests encodes path Writing HttpRequests encodes path jetty-3.0.0.rc4 - 06 November 2000 - + Fixed mime type mapping bug introduced in RC3 - + Fixed mis-synchronization in ThreadPool.stop() - + Ignore more IOExceptions (still visible with debug). - + Provide default JettyIndex.properties + + fixed mime type mapping bug introduced in rc3 Fixed mime type mapping bug + introduced in RC3 + + fixed mis-synchronization in threadpool.stop() Fixed mis-synchronization in + ThreadPool.stop() + + ignore more ioexceptions (still visible with debug). Ignore more + IOExceptions (still visible with debug). + + provide default jettyindex.properties Provide default JettyIndex.properties jetty-3.0.0.rc3 - 05 November 2000 - + Added bin/jetty.sh run script. - + Added context class path dynamic servlet demo - + Added gz tgz tar.gz .z mime mappings. - + Added HandlerContext.setHttpServerAccess for trusted contexts. - + Changed ThreadPool.stop for IBM 1.3 JVM - + Fixed default mimemap initialization bug - + Further clean up of the connection close actions - + Handle mime suffixes containing dots. - + Implemented mime mapping in webapplications. - + Moved unused classes from com.mortbay.Util to com.mortbay.Tools in new + + added bin/jetty.sh run script. Added bin/jetty.sh run script. + + added context class path dynamic servlet demo Added context class path + dynamic servlet demo + + added gz tgz tar.gz .z mime mappings. Added gz tgz tar.gz .z mime mappings. + + added handlercontext.sethttpserveraccess for trusted contexts. Added + HandlerContext.setHttpServerAccess for trusted contexts. + + changed threadpool.stop for ibm 1.3 jvm Changed ThreadPool.stop for IBM 1.3 + JVM + + fixed default mimemap initialization bug Fixed default mimemap + initialization bug + + further clean up of the connection close actions Further clean up of the + connection close actions + + handle mime suffixes containing dots. Handle mime suffixes containing dots. + + implemented mime mapping in webapplications. Implemented mime mapping in + webapplications. + + moved unused classes from com.mortbay.util to com.mortbay.tools in new Moved + unused classes from com.mortbay.Util to com.mortbay.Tools in new distribution package. - + Optimized persistent connections by recycling objects - + Prevent servlet setAttribute calls to protected context attributes. - + Removed redundant context attributes. - + Set MaxReadTimeMs in all examples - + Set the thread context class loader in HandlerContext.handle - + Strip ./ from relative resources. - + upgraded build.xml to ant v1.2 + + optimized persistent connections by recycling objects Optimized persistent + connections by recycling objects + + prevent servlet setattribute calls to protected context attributes. Prevent + servlet setAttribute calls to protected context attributes. + + removed redundant context attributes. Removed redundant context attributes. + + set maxreadtimems in all examples Set MaxReadTimeMs in all examples + + set the thread context class loader in handlercontext.handle Set the thread + context class loader in HandlerContext.handle + + strip ./ from relative resources. Strip ./ from relative resources. + + upgraded build.xml to ant v1.2 upgraded build.xml to ant v1.2 jetty-3.0.0.rc2 - 29 October 2000 - + Accept HTTP/1. as HTTP/1.0 (for netscape bug). - + Accept public DTD for XmlConfiguration (old style still supported). - + Cleaned up non persistent connection close. - + ErlEncoding treats params without values as empty rather than null. - + Fixed thread name problem in ThreadPool - + Pass file based classpath to JspServlet (see README). - + Prevented multiple init of ServletHolder - + Replaced ISO-8859-1 literals with StringUtil static + + accept http/1. as http/1.0 (for netscape bug). Accept HTTP/1. as HTTP/1.0 + (for netscape bug). + + accept public dtd for xmlconfiguration (old style still supported). Accept + public DTD for XmlConfiguration (old style still supported). + + cleaned up non persistent connection close. Cleaned up non persistent + connection close. + + erlencoding treats params without values as empty rather than null. + ErlEncoding treats params without values as empty rather than null. + + fixed thread name problem in threadpool Fixed thread name problem in + ThreadPool + + pass file based classpath to jspservlet (see readme). Pass file based + classpath to JspServlet (see README). + + prevented multiple init of servletholder Prevented multiple init of + ServletHolder + + replaced iso-8859-1 literals with stringutil static Replaced ISO-8859-1 + literals with StringUtil static jetty-3.0.0.rc1 - 22 October 2000 - + Added CGI to demo - + Added HashUserRealm and cleaned up security constraints - + Added Multipart request and response classes from Jetty2 - + Added simple admin servlet. - + All attributes in javax. java. and com.mortbay. name spaces to be set. - + Cleaned up exception handling. - + Initialize JSP with classloader. - + Moved and simplified ServletLoader to ContextLoader. - + Partial handling of 0.9 requests. - + removed Thread.destroy() calls. + + added cgi to demo Added CGI to demo + + added hashuserrealm and cleaned up security constraints Added HashUserRealm + and cleaned up security constraints + + added multipart request and response classes from jetty2 Added Multipart + request and response classes from Jetty2 + + added simple admin servlet. Added simple admin servlet. + + all attributes in javax. java. and com.mortbay. name spaces to be set. All + attributes in javax. java. and com.mortbay. name spaces to be set. + + cleaned up exception handling. Cleaned up exception handling. + + initialize jsp with classloader. Initialize JSP with classloader. + + moved and simplified servletloader to contextloader. Moved and simplified + ServletLoader to ContextLoader. + + partial handling of 0.9 requests. Partial handling of 0.9 requests. + + removed thread.destroy() calls. removed Thread.destroy() calls. jetty-2.4.8 - 23 October 2000 - + Fixed bug with 304 replies with bodies. - + Fixed closing socket problem - + Improved win32 make files. + + fixed bug with 304 replies with bodies. Fixed bug with 304 replies with + bodies. + + fixed closing socket problem Fixed closing socket problem + + improved win32 make files. Improved win32 make files. jetty-3.0.B05 - 18 October 2000 - + Added default webapp servlet mapping /servlet/name/* - + Cleaned up response committing and flushing - + Fixed JarFileResource to handle jar files without directories. - + Handler RFC2109 cookies (like any browser handles them!) - + Implemented security-role-ref for servlets - + Implemented war file support - + improved ant documentation. - + Improved default log format for clarity. - + Improved null returns to get almost clean watchdog test. - + Improved path spec interpretation by looking at 2.3 spec - + Java2 style classloading - + Made test harnesses work with ant. - + Protected servletConfig from downcast security problems - + Removed most deprecation warnings - + Separated context attributes and initParams. + + added default webapp servlet mapping /servlet/name/* Added default webapp + servlet mapping /servlet/name/* + + cleaned up response committing and flushing Cleaned up response committing + and flushing + + fixed jarfileresource to handle jar files without directories. Fixed + JarFileResource to handle jar files without directories. + + handler rfc2109 cookies (like any browser handles them!) Handler RFC2109 + cookies (like any browser handles them!) + + implemented security-role-ref for servlets Implemented security-role-ref for + servlets + + implemented war file support Implemented war file support + + improved ant documentation. improved ant documentation. + + improved default log format for clarity. Improved default log format for + clarity. + + improved null returns to get almost clean watchdog test. Improved null + returns to get almost clean watchdog test. + + improved path spec interpretation by looking at 2.3 spec Improved path spec + interpretation by looking at 2.3 spec + + java2 style classloading Java2 style classloading + + made test harnesses work with ant. Made test harnesses work with ant. + + protected servletconfig from downcast security problems Protected + servletConfig from downcast security problems + + removed most deprecation warnings Removed most deprecation warnings + + separated context attributes and initparams. Separated context attributes + and initParams. jetty-3.0.B04 - 12 October 2000 - + Added modified version of JasperB3.2 for JSP - + Added webdefault.xml for web applications. - + Do not try multiple servlets for a request. - + Filthy hack to teach jasper JspServer Jetty classpath - + Fixed problem with session ID in paths - + Implemented Context.getContext(uri) - + Merged and renamed third party jars. - + Moved FileBase to docroot - + Redirect to index files, so index.jsp works. - + Restricted context mapping to simple model for servlets. + + added modified version of jasperb3.2 for jsp Added modified version of + JasperB3.2 for JSP + + added webdefault.xml for web applications. Added webdefault.xml for web + applications. + + do not try multiple servlets for a request. Do not try multiple servlets for + a request. + + filthy hack to teach jasper jspserver jetty classpath Filthy hack to teach + jasper JspServer Jetty classpath + + fixed problem with session id in paths Fixed problem with session ID in + paths + + implemented context.getcontext(uri) Implemented Context.getContext(uri) + + merged and renamed third party jars. Merged and renamed third party jars. + + moved filebase to docroot Moved FileBase to docroot + + redirect to index files, so index.jsp works. Redirect to index files, so + index.jsp works. + + restricted context mapping to simple model for servlets. Restricted context + mapping to simple model for servlets. jetty-3.0.B03 - 09 October 2000 - + Added append mode in RolloverFileLogSink - + Added release script - + Catch stop and destroy exceptions in HttpServer.stop() - + Expanded import package.*; lines - + Expanded leading tabs to spaces - + Handle ignorable spaces in WebApplication - + Handle ignorable spaces in XmlConfiguration - + Implemented request dispatching. - + Improved Context to Handler contract. - + Improved handler toString - + Improved Log rollover. - + Made LogSink a Lifecycle interface - + Parse but not handler startup ordering in web applications. - + Pass object to LogSink - + Redirect context only paths. - + Redo dynamic servlets handling - + Remove 411 checks as IE breaks this rule after redirect. - + Removed last remnants JDK 1.1 support - + Send request log via a LogSink - + Simplified path translation and real path calculation. - + Warn about explicit sets of WebApplication + + added append mode in rolloverfilelogsink Added append mode in + RolloverFileLogSink + + added release script Added release script + + catch stop and destroy exceptions in httpserver.stop() Catch stop and + destroy exceptions in HttpServer.stop() + + expanded import package.*; lines Expanded import package.*; lines + + expanded leading tabs to spaces Expanded leading tabs to spaces + + handle ignorable spaces in webapplication Handle ignorable spaces in + WebApplication + + handle ignorable spaces in xmlconfiguration Handle ignorable spaces in + XmlConfiguration + + implemented request dispatching. Implemented request dispatching. + + improved context to handler contract. Improved Context to Handler contract. + + improved handler tostring Improved handler toString + + improved log rollover. Improved Log rollover. + + made logsink a lifecycle interface Made LogSink a Lifecycle interface + + parse but not handler startup ordering in web applications. Parse but not + handler startup ordering in web applications. + + pass object to logsink Pass object to LogSink + + redirect context only paths. Redirect context only paths. + + redo dynamic servlets handling Redo dynamic servlets handling + + remove 411 checks as ie breaks this rule after redirect. Remove 411 checks + as IE breaks this rule after redirect. + + removed last remnants jdk 1.1 support Removed last remnants JDK 1.1 support + + send request log via a logsink Send request log via a LogSink + + simplified path translation and real path calculation. Simplified path + translation and real path calculation. + + warn about explicit sets of webapplication Warn about explicit sets of + WebApplication jetty-2.4.7 - 06 October 2000 - + Added encode methods to URI - + Allow Objects to be passed to LogSink - + fixes to SSL doco - + Improved win32 build - + Set content length on errors for keep alive. - + Support key and keystore passwords - + Various improvements to ServletDispatch, PropertyTree and associated + + added encode methods to uri Added encode methods to URI + + allow objects to be passed to logsink Allow Objects to be passed to LogSink + + fixes to ssl doco fixes to SSL doco + + improved win32 build Improved win32 build + + set content length on errors for keep alive. Set content length on errors + for keep alive. + + support key and keystore passwords Support key and keystore passwords + + various improvements to servletdispatch, propertytree and associated + Various improvements to ServletDispatch, PropertyTree and associated classes. jetty-3.0.B02 - 24 August 2000 - + Added CGI servlet - + Fixed bug in TestRFC2616 - + Fixed HTTP/1.0 input close bug - + Fixed LineInput bug with SSL giving CR pause LF. - + Improved ThreadedServer stop and destroy - + Use resources in WebApplication + + added cgi servlet Added CGI servlet + + fixed bug in testrfc2616 Fixed bug in TestRFC2616 + + fixed http/1.0 input close bug Fixed HTTP/1.0 input close bug + + fixed lineinput bug with ssl giving cr pause lf. Fixed LineInput bug with + SSL giving CR pause LF. + + improved threadedserver stop and destroy Improved ThreadedServer stop and + destroy + + use resources in webapplication Use resources in WebApplication jetty-3.0.B01 - 21 August 2000 - + Implemented more webapp configuration - + Partial implementation of webapp securitycontraints - + SSL implemented with JsseListener - + Switched to the aelfred XML parser from microstar, which is only partially + + implemented more webapp configuration Implemented more webapp configuration + + partial implementation of webapp securitycontraints Partial implementation + of webapp securitycontraints + + ssl implemented with jsselistener SSL implemented with JsseListener + + switched to the aelfred xml parser from microstar, which is only parti + Switched to the aelfred XML parser from microstar, which is only partially validating, but small and lightweight jetty-2.4.6 - 16 August 2000 - + Added passive mode methods to FTP - + com.mortbay.Util.KeyPairTool added to handle openSSL SSL keys. - + JsseListener & SunJsseListener added and documented - + Minor changes to compile with jikes. - + Turn Linger off before closing sockets, to allow restart. + + added passive mode methods to ftp Added passive mode methods to FTP + + com.mortbay.util.keypairtool added to handle openssl ssl keys. + com.mortbay.Util.KeyPairTool added to handle openSSL SSL keys. + + jsselistener & sunjsselistener added and documented JsseListener & + SunJsseListener added and documented + + minor changes to compile with jikes. Minor changes to compile with jikes. + + turn linger off before closing sockets, to allow restart. Turn Linger off + before closing sockets, to allow restart. jetty-3.0.A99 - 10 August 2000 - + Added Resource abstraction - + Added Xmlconfiguration utility - + Implemented jetty.xml configuration - + Make it compile cleanly with jikes. - + Re-added commented out imports for JDK-1.1 compile - + Removed FileBase. Now use ResourceBase instead - + Replaced FileHandler with ResourceHandler - + ServletLoader simplied and uses ResourcePath - + Use SAX XML parsing instead of DOM for space saving. + + added resource abstraction Added Resource abstraction + + added xmlconfiguration utility Added Xmlconfiguration utility + + implemented jetty.xml configuration Implemented jetty.xml configuration + + make it compile cleanly with jikes. Make it compile cleanly with jikes. + + re-added commented out imports for jdk-1.1 compile Re-added commented out + imports for JDK-1.1 compile + + removed filebase. now use resourcebase instead Removed FileBase. Now use + ResourceBase instead + + replaced filehandler with resourcehandler Replaced FileHandler with + ResourceHandler + + servletloader simplied and uses resourcepath ServletLoader simplied and uses + ResourcePath + + use sax xml parsing instead of dom for space saving. Use SAX XML parsing + instead of DOM for space saving. jetty-3.0.A98 - 20 July 2000 - + Allow HttpRequest.toString() handles bad requests. - + Fixed constructor to RolloverFileLogSink - + Implemented Jetty demos and Site as Web Application. - + Implemented WebApplicationContext - + Improved synchronization on LogSink - + ServletRequest.getServerPort() returns 80 rather than 0 - + Switched to JDK1.2 only + + allow httprequest.tostring() handles bad requests. Allow + HttpRequest.toString() handles bad requests. + + fixed constructor to rolloverfilelogsink Fixed constructor to + RolloverFileLogSink + + implemented jetty demos and site as web application. Implemented Jetty demos + and Site as Web Application. + + implemented webapplicationcontext Implemented WebApplicationContext + + improved synchronization on logsink Improved synchronization on LogSink + + servletrequest.getserverport() returns 80 rather than 0 + ServletRequest.getServerPort() returns 80 rather than 0 + + switched to jdk1.2 only Switched to JDK1.2 only jetty-3.0.A97 - 13 July 2000 - + Added error handling to LifeCycleThread - + Added WML mappings - + Better tuned SocketListener parameters - + Fixed makefiles for BSD ls - + Fixed persistent commits with no content (eg redirect+keep-alive). - + Formatted version in server info string. - + implemented removeAttribute on requests - + Implemented servlet getLocale(s). - + Implemented servlet isSecure(). - + Less verbose debug - + Protect setContentLength from a late set in default servlet HEAD handling. - + Started RequestDispatcher implementation. - + Tempory request log implementation + + added error handling to lifecyclethread Added error handling to + LifeCycleThread + + added wml mappings Added WML mappings + + better tuned socketlistener parameters Better tuned SocketListener + parameters + + fixed makefiles for bsd ls Fixed makefiles for BSD ls + + fixed persistent commits with no content (eg redirect+keep-alive). Fixed + persistent commits with no content (eg redirect+keep-alive). + + formatted version in server info string. Formatted version in server info + string. + + implemented removeattribute on requests implemented removeAttribute on + requests + + implemented servlet getlocale(s). Implemented servlet getLocale(s). + + implemented servlet issecure(). Implemented servlet isSecure(). + + less verbose debug Less verbose debug + + protect setcontentlength from a late set in default servlet head handl + Protect setContentLength from a late set in default servlet HEAD handling. + + started requestdispatcher implementation. Started RequestDispatcher + implementation. + + tempory request log implementation Tempory request log implementation jetty-2.4.5 - 09 July 2000 - + Added HtmlExpireFilter and removed response cache revention from HtmlFilter. - + Don't mark a session invalid until after values unbound. - + Fixed transaction handling in JDBC wrappers - + Formatted version in server info. + + added htmlexpirefilter and removed response cache revention from htmlf Added + HtmlExpireFilter and removed response cache revention from HtmlFilter. + + don't mark a session invalid until after values unbound. Don't mark a + session invalid until after values unbound. + + fixed transaction handling in jdbc wrappers Fixed transaction handling in + JDBC wrappers + + formatted version in server info. Formatted version in server info. jetty-3.0.A96 - 27 June 2000 - + Fixed bug with HTTP/1.1 Head reqests to servlets. - + Supressed un-needed chunking EOF indicators. + + fixed bug with http/1.1 head reqests to servlets. Fixed bug with HTTP/1.1 + Head reqests to servlets. + + supressed un-needed chunking eof indicators. Supressed un-needed chunking + EOF indicators. jetty-3.0.A95 - 24 June 2000 - + Fixed getServletPath for default "/" - + Handle spaces in file names in FileHandler. + + fixed getservletpath for default "/" Fixed getServletPath for default "/" + + handle spaces in file names in filehandler. Handle spaces in file names in + FileHandler. jetty-3.0.A94 - 19 June 2000 - + Added HandlerContext to allow grouping of handlers into units with the same - file, resource and class configurations. - + Cleaned up commit() and added complete() to HttpResponse - + Implemented Sessions. - + PathMap exact matches can terminate with ; or # for URL sessions and - targets. - + Updated license to clarify that commercial usage IS OK! + + added handlercontext to allow grouping of handlers into units with the Added + HandlerContext to allow grouping of handlers into units with the same file, + resource and class configurations. + + cleaned up commit() and added complete() to httpresponse Cleaned up commit() + and added complete() to HttpResponse + + implemented sessions. Implemented Sessions. + + pathmap exact matches can terminate with ; or # for url sessions and PathMap + exact matches can terminate with ; or # for URL sessions and targets. + + updated license to clarify that commercial usage is ok! Updated license to + clarify that commercial usage IS OK! jetty-3.0.A93 - 14 June 2000 - + Lots of changes and probably unstable - + Major rethink! Moved to 2.2 servlet API + + lots of changes and probably unstable Lots of changes and probably unstable + + major rethink! moved to 2.2 servlet api Major rethink! Moved to 2.2 servlet + API jetty-3.0.A92 - 07 June 2000 - + Added HTML classes to jar - + Fixed redirection bug in FileHandler + + added html classes to jar Added HTML classes to jar + + fixed redirection bug in filehandler Fixed redirection bug in FileHandler jetty-2.4.4 - 03 June 2000 - + Added build-win32.mak - + Added HTML.Composite.replace - + Added RolloverFileLogSink - + Added uk.org.gosnell.Servlets.CgiServlet to contrib - + BasicAuthHandler uses getResourcePath so it can be used behind request + + added build-win32.mak Added build-win32.mak + + added html.composite.replace Added HTML.Composite.replace + + added rolloverfilelogsink Added RolloverFileLogSink + + added uk.org.gosnell.servlets.cgiservlet to contrib Added + uk.org.gosnell.Servlets.CgiServlet to contrib + + basicauthhandler uses getresourcepath so it can be used behind request + BasicAuthHandler uses getResourcePath so it can be used behind request dispatching - + FileHandler implements IfModifiedSince on index files. - + HttpRequest.setRequestPath does not null pathInfo. - + Improved LogSink configuration - + Many debug call optimizations - + Support System.property expansions in PropertyTrees. + + filehandler implements ifmodifiedsince on index files. FileHandler + implements IfModifiedSince on index files. + + httprequest.setrequestpath does not null pathinfo. + HttpRequest.setRequestPath does not null pathInfo. + + improved logsink configuration Improved LogSink configuration + + many debug call optimizations Many debug call optimizations + + support system.property expansions in propertytrees. Support System.property + expansions in PropertyTrees. jetty-3.0.A91 - 03 June 2000 - + Abstracted ServletHandler - + Added HTML classes from Jetty2 - + Implemented realPath and getResource methods for servlets. - + Improved LogSink mechanism - + Simplified class loading - + Simplified HttpServer configuration methods and arguments + + abstracted servlethandler Abstracted ServletHandler + + added html classes from jetty2 Added HTML classes from Jetty2 + + implemented realpath and getresource methods for servlets. Implemented + realPath and getResource methods for servlets. + + improved logsink mechanism Improved LogSink mechanism + + simplified class loading Simplified class loading + + simplified httpserver configuration methods and arguments Simplified + HttpServer configuration methods and arguments jetty-3.0.A9 - 07 May 2000 - + File handler checks modified headers on directory indexes. - + Fixed double chunking bug in SocketListener. - + Improvided finally handling of output end game. - + ServletLoader tries unix then platform separator for zip separator. + + file handler checks modified headers on directory indexes. File handler + checks modified headers on directory indexes. + + fixed double chunking bug in socketlistener. Fixed double chunking bug in + SocketListener. + + improvided finally handling of output end game. Improvided finally handling + of output end game. + + servletloader tries unix then platform separator for zip separator. + ServletLoader tries unix then platform separator for zip separator. jetty-3.0.A8 - 04 May 2000 - + addCookie takes an int maxAge rather than a expires date. - + Added LogSink extensible log architecture. - + Added Tenlet class for reverse telnet. - + Code.ignore only outputs when debug is verbose. - + Moved Sevlet2_1 handler to com.mortbay.Servlet2_1 - + Servlet2_1 class loading re-acrchitected. See README. + + addcookie takes an int maxage rather than a expires date. addCookie takes an + int maxAge rather than a expires date. + + added logsink extensible log architecture. Added LogSink extensible log + architecture. + + added tenlet class for reverse telnet. Added Tenlet class for reverse + telnet. + + code.ignore only outputs when debug is verbose. Code.ignore only outputs + when debug is verbose. + + moved sevlet2_1 handler to com.mortbay.servlet2_1 Moved Sevlet2_1 handler to + com.mortbay.Servlet2_1 + + servlet2_1 class loading re-acrchitected. see readme. Servlet2_1 class + loading re-acrchitected. See README. jetty-2.4.3 - 04 May 2000 - + Allow CRLF in UrlEncoded - + Pass Cookies with 0 max age to browser. + + allow crlf in urlencoded Allow CRLF in UrlEncoded + + pass cookies with 0 max age to browser. Pass Cookies with 0 max age to + browser. jetty-2.4.2 - 23 April 2000 - + Added GNUJSP to JettyServer.prp file. - + Added LogSink and FileLogSink classes to allow extensible Log handling. - + Handle nested RequestDispatcher includes. - + Modified GNUJSP to prevent close in nested requests. + + added gnujsp to jettyserver.prp file. Added GNUJSP to JettyServer.prp file. + + added logsink and filelogsink classes to allow extensible log handling Added + LogSink and FileLogSink classes to allow extensible Log handling. + + handle nested requestdispatcher includes. Handle nested RequestDispatcher + includes. + + modified gnujsp to prevent close in nested requests. Modified GNUJSP to + prevent close in nested requests. jetty-3.0.A7 - 15 April 2000 - + Added InetGateway to help debug IE5 problems - + added removeValue method to MultiMap - + fixed flush problem with chunked output for IE5 - + Include java 1.2 source hierarchy - + removed excess ';' from source + + added inetgateway to help debug ie5 problems Added InetGateway to help debug + IE5 problems + + added removevalue method to multimap added removeValue method to MultiMap + + fixed flush problem with chunked output for ie5 fixed flush problem with + chunked output for IE5 + + include java 1.2 source hierarchy Include java 1.2 source hierarchy + + removed excess ';' from source removed excess ';' from source jetty-2.4.1 - 09 April 2000 - + Fixed bug in HtmlFilter for tags split between writes. - + Removed debug println from ServletHolder. - + Set encoding before exception in FileHandler. + + fixed bug in htmlfilter for tags split between writes. Fixed bug in + HtmlFilter for tags split between writes. + + removed debug println from servletholder. Removed debug println from + ServletHolder. + + set encoding before exception in filehandler. Set encoding before exception + in FileHandler. jetty-3.0.A6 - 09 April 2000 - + added bin/useJava2Collections to convert to JDK1.2 - + Dates forced to use US locale - + Improved portability of Frame and Debug. - + Integrated skeleton 2.1 Servlet container - + Removed Converter utilities and InetGateway. + + added bin/usejava2collections to convert to jdk1.2 added + bin/useJava2Collections to convert to JDK1.2 + + dates forced to use us locale Dates forced to use US locale + + improved portability of frame and debug. Improved portability of Frame and + Debug. + + integrated skeleton 2.1 servlet container Integrated skeleton 2.1 Servlet + container + + removed converter utilities and inetgateway. Removed Converter utilities and + InetGateway. jetty-2.4.0 - 24 March 2000 - + Absolute URIs are returned by getRequestURI (if sent by browser). - + Added doc directory with a small start - + Added per servlet resourceBase configuration. - + Added VirtualHostHandler for virtual host handling - + Fixed bug with RequestDispatcher.include() - + Fixed caste problem in UrlEncoded - + Fixed null pointer in ThreadedServer with stopAll - + Form parameters only decoded for POSTs - + Implemented full handling of cookie max age. - + Improved parsing of stack trace in debug mode. - + Moved SetUID native code to contrib hierarchy - + RequestDispatcher handles URI parameters - + Upgraded to gnujsp 1.0.0 + + absolute uris are returned by getrequesturi (if sent by browser). Absolute + URIs are returned by getRequestURI (if sent by browser). + + added doc directory with a small start Added doc directory with a small + start + + added per servlet resourcebase configuration. Added per servlet resourceBase + configuration. + + added virtualhosthandler for virtual host handling Added VirtualHostHandler + for virtual host handling + + fixed bug with requestdispatcher.include() Fixed bug with + RequestDispatcher.include() + + fixed caste problem in urlencoded Fixed caste problem in UrlEncoded + + fixed null pointer in threadedserver with stopall Fixed null pointer in + ThreadedServer with stopAll + + form parameters only decoded for posts Form parameters only decoded for + POSTs + + implemented full handling of cookie max age. Implemented full handling of + cookie max age. + + improved parsing of stack trace in debug mode. Improved parsing of stack + trace in debug mode. + + moved setuid native code to contrib hierarchy Moved SetUID native code to + contrib hierarchy + + requestdispatcher handles uri parameters RequestDispatcher handles URI + parameters + + upgraded to gnujsp 1.0.0 Upgraded to gnujsp 1.0.0 jetty-2.3.5 - 25 January 2000 - + Added configuration option to turn off Keep-Alive in HTTP/1.0 - + Added contrib/com/kiwiconsulting/jetty JSSE SSL adaptor to release. - + Allow configured servlets to be auto reloaded. - + Allow properties to be configured for dynamic servlets. - + Fixed expires bug in Cookies - + Fixed nasty bug with HTTP/1.1 redirects. - + Force locale of date formats to US. - + ProxyHandler sends content for POSTs etc. + + added configuration option to turn off keep-alive in http/1.0 Added + configuration option to turn off Keep-Alive in HTTP/1.0 + + added contrib/com/kiwiconsulting/jetty jsse ssl adaptor to release. Added + contrib/com/kiwiconsulting/jetty JSSE SSL adaptor to release. + + allow configured servlets to be auto reloaded. Allow configured servlets to + be auto reloaded. + + allow properties to be configured for dynamic servlets. Allow properties to + be configured for dynamic servlets. + + fixed expires bug in cookies Fixed expires bug in Cookies + + fixed nasty bug with http/1.1 redirects. Fixed nasty bug with HTTP/1.1 + redirects. + + force locale of date formats to us. Force locale of date formats to US. + + proxyhandler sends content for posts etc. ProxyHandler sends content for + POSTs etc. jetty-2.3.4 - 18 January 2000 - + Cookie map keyed on domain as well as name and path. - + DictionaryConverter handles null values. - + Fixed IllegalStateException handling in DefaultExceptionHandler - + Fixed interaction with resourcePaths and proxy demo. - + Improved HtmlFilter.activate header modifications. - + include from linux rather than genunix for native builds - + MethodTag.invoke() is now public. - + Servlet properties allow objects to be stored. - + URI decodes applies URL decoding to the path. + + cookie map keyed on domain as well as name and path. Cookie map keyed on + domain as well as name and path. + + dictionaryconverter handles null values. DictionaryConverter handles null + values. + + fixed illegalstateexception handling in defaultexceptionhandler Fixed + IllegalStateException handling in DefaultExceptionHandler + + fixed interaction with resourcepaths and proxy demo. Fixed interaction with + resourcePaths and proxy demo. + + improved htmlfilter.activate header modifications. Improved + HtmlFilter.activate header modifications. + + include from linux rather than genunix for native builds include from linux + rather than genunix for native builds + + methodtag.invoke() is now public. MethodTag.invoke() is now public. + + servlet properties allow objects to be stored. Servlet properties allow + objects to be stored. + + uri decodes applies url decoding to the path. URI decodes applies URL + decoding to the path. jetty-3.0.A5 - 19 October 1999 - + Do our own URL string encoding with 8859-1 - + Replaced LF wait in LineInput with state boolean. - + Use char array in UrlEncoded.decode - + Use ISO8859_1 instead of UTF8 for headers etc. + + do our own url string encoding with 8859-1 Do our own URL string encoding + with 8859-1 + + replaced lf wait in lineinput with state boolean. Replaced LF wait in + LineInput with state boolean. + + use char array in urlencoded.decode Use char array in UrlEncoded.decode + + use iso8859_1 instead of utf8 for headers etc. Use ISO8859_1 instead of UTF8 + for headers etc. jetty-2.3.3 - 19 October 1999 - + Do our own URL encoding with ISO-8859-1 - + HTTP.HTML.EmbedUrl uses contents encoding. - + Replaced UTF8 encoding with ISO-8859-1 for headers. - + Use UrlEncoded for form parameters. + + do our own url encoding with iso-8859-1 Do our own URL encoding with + ISO-8859-1 + + http.html.embedurl uses contents encoding. HTTP.HTML.EmbedUrl uses contents + encoding. + + replaced utf8 encoding with iso-8859-1 for headers. Replaced UTF8 encoding + with ISO-8859-1 for headers. + + use urlencoded for form parameters. Use UrlEncoded for form parameters. jetty-2.3.2 - 17 October 1999 - + Fixed getReader bug with HttpRequest. - + Updated UrlEncoded with Jetty3 version. + + fixed getreader bug with httprequest. Fixed getReader bug with HttpRequest. + + updated urlencoded with jetty3 version. Updated UrlEncoded with Jetty3 + version. jetty-3.0.A4 - 16 October 1999 - + Added LF wait after CR to LineInput. - + Basic Authentication Handler. - + Request attributes - + UTF8 in UrlDecoded.decodeString. + + added lf wait after cr to lineinput. Added LF wait after CR to LineInput. + + basic authentication handler. Basic Authentication Handler. + + request attributes Request attributes + + utf8 in urldecoded.decodestring. UTF8 in UrlDecoded.decodeString. jetty-2.3.1 - 14 October 1999 - + Added assert with no message to Code - + Added Oracle DB adapter - + Changed demo servlets to use writers in preference to outputstreams - + Fixed GNUJSP 1.0 resource bug. - + Force UTF8 for FTP commands - + Force UTF8 for HTML - + HTTP/1.0 Keep-Alive (about time!). - + NullHandler/Server default name.name.PROPERTIES to load - prefix/name.name.properties - + Prevented thread churn on idle server. - + ThreadedServer calls setSoTimeout(_maxThreadIdleMs) on accepted sockets. + + added assert with no message to code Added assert with no message to Code + + added oracle db adapter Added Oracle DB adapter + + changed demo servlets to use writers in preference to outputstreams Changed + demo servlets to use writers in preference to outputstreams + + fixed gnujsp 1.0 resource bug. Fixed GNUJSP 1.0 resource bug. + + force utf8 for ftp commands Force UTF8 for FTP commands + + force utf8 for html Force UTF8 for HTML + + http/1.0 keep-alive (about time!). HTTP/1.0 Keep-Alive (about time!). + + nullhandler/server default name.name.properties to load NullHandler/Server + default name.name.PROPERTIES to load prefix/name.name.properties + + prevented thread churn on idle server. Prevented thread churn on idle + server. + + threadedserver calls setsotimeout(_maxthreadidlems) on accepted socket + ThreadedServer calls setSoTimeout(_maxThreadIdleMs) on accepted sockets. Idle reads will timeout. - + Use UTF8 in HTTP headers + + use utf8 in http headers Use UTF8 in HTTP headers jetty-3.0.A3 - 14 October 1999 - + Added LifeCycle interface to Utils implemented by ThreadPool, - ThreadedServer, HttpListener & HttpHandler - + Added service method to HttpConnection for specialization. - + MaxReadTimeMs added to ThreadedServer. - + StartAll, stopAll and destroyAll methods added to HttpServer. + + added lifecycle interface to utils implemented by threadpool, Added + LifeCycle interface to Utils implemented by ThreadPool, ThreadedServer, + HttpListener & HttpHandler + + added service method to httpconnection for specialization. Added service + method to HttpConnection for specialization. + + maxreadtimems added to threadedserver. MaxReadTimeMs added to + ThreadedServer. + + startall, stopall and destroyall methods added to httpserver. StartAll, + stopAll and destroyAll methods added to HttpServer. jetty-3.0.A2 - 13 October 1999 - + Added cookie support and demo. - + Cleaned up Util TestHarness. - + Fixed LineInput problem with repeated CRs - + HEAD handling. - + HTTP/1.0 Keep-alive (about time!) - + NotFound Handler - + OPTION * Handling. - + Prevent entity content for responses 100-199,203,304 - + Reduced flushing on writing response. - + TRACE handling. - + UTF8 handling on raw output stream. - + Virtual Hosts. + + added cookie support and demo. Added cookie support and demo. + + cleaned up util testharness. Cleaned up Util TestHarness. + + fixed lineinput problem with repeated crs Fixed LineInput problem with + repeated CRs + + head handling. HEAD handling. + + http/1.0 keep-alive (about time!) HTTP/1.0 Keep-alive (about time!) + + notfound handler NotFound Handler + + option * handling. OPTION * Handling. + + prevent entity content for responses 100-199,203,304 Prevent entity content + for responses 100-199,203,304 + + reduced flushing on writing response. Reduced flushing on writing response. + + trace handling. TRACE handling. + + utf8 handling on raw output stream. UTF8 handling on raw output stream. + + virtual hosts. Virtual Hosts. jetty-3.0.A1 - 12 October 1999 - + Added HttpHandler interface with start/stop/destroy lifecycle - + Added MultiMap for common handling of multiple valued parameters. - + Added parameters to HttpRequest - + Added PathMap implementing mapping as defined in the 2.2 API specification - (ie. /exact, /prefix/*, *.extention & default ). - + Implemented simple extension architecture in HttpServer. - + LineInput uses own buffering and uses character encodings. - + Quick port of FileHandler - + Setup demo pages. - + Updated HttpListener is start/stop/destroy lifecycle. + + added httphandler interface with start/stop/destroy lifecycle Added + HttpHandler interface with start/stop/destroy lifecycle + + added multimap for common handling of multiple valued parameters. Added + MultiMap for common handling of multiple valued parameters. + + added parameters to httprequest Added parameters to HttpRequest + + added pathmap implementing mapping as defined in the 2.2 api specifica Added + PathMap implementing mapping as defined in the 2.2 API specification (ie. + /exact, /prefix/*, *.extention & default ). + + implemented simple extension architecture in httpserver. Implemented simple + extension architecture in HttpServer. + + lineinput uses own buffering and uses character encodings. LineInput uses + own buffering and uses character encodings. + + quick port of filehandler Quick port of FileHandler + + setup demo pages. Setup demo pages. + + updated httplistener is start/stop/destroy lifecycle. Updated HttpListener + is start/stop/destroy lifecycle. jetty-3.0.A0 - 09 October 1999 - + Added generalized HTTP Connection. - + Added support for servlet 2.2 outbut buffer control. - + Added support for transfer and content encoding filters. - + Cleaned up chunking code to use LineInput and reduce buffering. - + Cleanup and abstraction of ThreadPool. - + Cleanup of HttpRequest and decoupled from Servlet API - + Cleanup of HttpResponse and decoupled from Servlet API - + Cleanup of LineInput, using 1.2 Collections. - + Cleanup of URI, using 1.2 Collections. - + Cleanup of UrlEncoded, using 1.2 Collections. - + Created RFC2616 test harness. - + Extended URI to handle absolute URLs - + Generalized notification of outputStream events. - + gzip and deflate request transfer encodings - + HttpExceptions now produce error pages with specific detail of the + + added generalized http connection. Added generalized HTTP Connection. + + added support for servlet 2.2 outbut buffer control. Added support for + servlet 2.2 outbut buffer control. + + added support for transfer and content encoding filters. Added support for + transfer and content encoding filters. + + cleaned up chunking code to use lineinput and reduce buffering. Cleaned up + chunking code to use LineInput and reduce buffering. + + cleanup and abstraction of threadpool. Cleanup and abstraction of + ThreadPool. + + cleanup of httprequest and decoupled from servlet api Cleanup of HttpRequest + and decoupled from Servlet API + + cleanup of httpresponse and decoupled from servlet api Cleanup of + HttpResponse and decoupled from Servlet API + + cleanup of lineinput, using 1.2 collections. Cleanup of LineInput, using 1.2 + Collections. + + cleanup of uri, using 1.2 collections. Cleanup of URI, using 1.2 + Collections. + + cleanup of urlencoded, using 1.2 collections. Cleanup of UrlEncoded, using + 1.2 Collections. + + created rfc2616 test harness. Created RFC2616 test harness. + + extended uri to handle absolute urls Extended URI to handle absolute URLs + + generalized notification of outputstream events. Generalized notification of + outputStream events. + + gzip and deflate request transfer encodings gzip and deflate request + transfer encodings + + httpexceptions now produce error pages with specific detail of the + HttpExceptions now produce error pages with specific detail of the exception. - + HttpMessage supports chunked trailers. - + HttpMessage supports message states. - + Moved com.mortbay.Base classes to com.mortbay.Util - + Moved HttpInput/OutputStream to ChunkableInput/OutputStream. - + Split HttpHeader into HttpFields and HttpMessage. - + Started fresh repository in CVS - + TE field coding and trailer handler - + ThreadedServer based on ThreadPool. + + httpmessage supports chunked trailers. HttpMessage supports chunked + trailers. + + httpmessage supports message states. HttpMessage supports message states. + + moved com.mortbay.base classes to com.mortbay.util Moved com.mortbay.Base + classes to com.mortbay.Util + + moved httpinput/outputstream to chunkableinput/outputstream. Moved + HttpInput/OutputStream to ChunkableInput/OutputStream. + + split httpheader into httpfields and httpmessage. Split HttpHeader into + HttpFields and HttpMessage. + + started fresh repository in cvs Started fresh repository in CVS + + te field coding and trailer handler TE field coding and trailer handler + + threadedserver based on threadpool. ThreadedServer based on ThreadPool. jetty-2.3.0 - 05 October 1999 - + Added SetUID class with native Unix call to set the effective User ID. - + FTP closes files after put/get. - + FTP uses InetAddress of command socket for data socket. + + added setuid class with native unix call to set the effective user id. Added + SetUID class with native Unix call to set the effective User ID. + + ftp closes files after put/get. FTP closes files after put/get. + + ftp uses inetaddress of command socket for data socket. FTP uses InetAddress + of command socket for data socket. jetty-2.3.0A - 22 September 1999 - + Added "Powered by Jetty" button. - + Added BuildJetty.java file. - + Added GNUJSP 1.0 for the JSP 1.0 API. - + Expanded tabs to spaces in source. - + Made session IDs less predictable and removed race. - + ServerContext available to HtmlFilters via context param - + Use javax.servlet classes from JWSDK1.0 + + added "powered by jetty" button. Added "Powered by Jetty" button. + + added buildjetty.java file. Added BuildJetty.java file. + + added gnujsp 1.0 for the jsp 1.0 api. Added GNUJSP 1.0 for the JSP 1.0 API. + + expanded tabs to spaces in source. Expanded tabs to spaces in source. + + made session ids less predictable and removed race. Made session IDs less + predictable and removed race. + + servercontext available to htmlfilters via context param ServerContext + available to HtmlFilters via context param + + use javax.servlet classes from jwsdk1.0 Use javax.servlet classes from + JWSDK1.0 jetty-2.2.8 - 15 September 1999 - + Added disableLog() to turn off logging. - + Allow default table attributes to be overriden. - + Fixed bug in Element.attribute with empty string values. - + Improved quoting in HTML element values - + Made translation of getRequestURI() optional. - + Removed recursion from TranslationHandler + + added disablelog() to turn off logging. Added disableLog() to turn off + logging. + + allow default table attributes to be overriden. Allow default table + attributes to be overriden. + + fixed bug in element.attribute with empty string values. Fixed bug in + Element.attribute with empty string values. + + improved quoting in html element values Improved quoting in HTML element + values + + made translation of getrequesturi() optional. Made translation of + getRequestURI() optional. + + removed recursion from translationhandler Removed recursion from + TranslationHandler jetty-2.2.7 - 09 September 1999 - + Added default row, head and cell elements to Table. - + Added GzipFilter for content encoding. - + FileHandler passes POST request through if the file does not exist. - + Reverted semantics of getRequestURI() to return untranslated URI. + + added default row, head and cell elements to table. Added default row, head + and cell elements to Table. + + added gzipfilter for content encoding. Added GzipFilter for content + encoding. + + filehandler passes post request through if the file does not exist. + FileHandler passes POST request through if the file does not exist. + + reverted semantics of getrequesturi() to return untranslated uri. Reverted + semantics of getRequestURI() to return untranslated URI. jetty-2.2.6 - 05 September 1999 - + Added destroy() method on all HttpHandlers. - + Added ServletRunnerHandler to the contrib directories. - + Allow the handling of getPathTranslated to be configured in ServletHandler. - + class StyleLink added. - + Cookies always available from getCookies. - + Cookies parameter renamed to CookiesAsParameters - + cssClass, cssID and style methods added to element. - + FileHandler does not server files ending in '/' - + Fixed Cookie max age order of magnitude bug. - + HttpRequest.getSession() always returns a session as per the latest API + + added destroy() method on all httphandlers. Added destroy() method on all + HttpHandlers. + + added servletrunnerhandler to the contrib directories. Added + ServletRunnerHandler to the contrib directories. + + allow the handling of getpathtranslated to be configured in servlethan Allow + the handling of getPathTranslated to be configured in ServletHandler. + + class stylelink added. class StyleLink added. + + cookies always available from getcookies. Cookies always available from + getCookies. + + cookies parameter renamed to cookiesasparameters Cookies parameter renamed + to CookiesAsParameters + + cssclass, cssid and style methods added to element. cssClass, cssID and + style methods added to element. + + filehandler does not server files ending in '/' FileHandler does not server + files ending in '/' + + fixed cookie max age order of magnitude bug. Fixed Cookie max age order of + magnitude bug. + + httprequest.getsession() always returns a session as per the latest ap + HttpRequest.getSession() always returns a session as per the latest API spec. - + Ignore duplicate single valued headers, rather than reply with bad request, + + ignore duplicate single valued headers, rather than reply with bad req + Ignore duplicate single valued headers, rather than reply with bad request, as IE4 breaks the rules. - + media added to Style - + New implementation of ThreadPool, avoids a thread leak problem. - + Removed JRUN options from ServletHandler configuration. - + ServletHandler.destroy destroys all servlets. - + SPAN added to Block - + Updated HTML package to better support CSS: + + media added to style media added to Style + + new implementation of threadpool, avoids a thread leak problem. New + implementation of ThreadPool, avoids a thread leak problem. + + removed jrun options from servlethandler configuration. Removed JRUN options + from ServletHandler configuration. + + servlethandler.destroy destroys all servlets. ServletHandler.destroy + destroys all servlets. + + span added to block SPAN added to Block + + updated html package to better support css: Updated HTML package to better + support CSS: jetty-2.2.5 - 19 August 1999 - + Always close connection after a bad request. - + Better default handling of ServletExceptions - + Close loaded class files so Win32 can overwrite them before GC (what a silly - file system!). - + Don't override the cookie as parameter option. - + Fixed bug with closing connections in ThreadedServer - + Improved error messages from Jetty.Server. - + Limited growth in MultiPartResponse boundary. - + Made start and stop non final in ThreadedServer - + Set Expires header in HtmlFilter. + + always close connection after a bad request. Always close connection after a + bad request. + + better default handling of servletexceptions Better default handling of + ServletExceptions + + close loaded class files so win32 can overwrite them before gc (what a Close + loaded class files so Win32 can overwrite them before GC (what a silly file + system!). + + don't override the cookie as parameter option. Don't override the cookie as + parameter option. + + fixed bug with closing connections in threadedserver Fixed bug with closing + connections in ThreadedServer + + improved error messages from jetty.server. Improved error messages from + Jetty.Server. + + limited growth in multipartresponse boundary. Limited growth in + MultiPartResponse boundary. + + made start and stop non final in threadedserver Made start and stop non + final in ThreadedServer + + set expires header in htmlfilter. Set Expires header in HtmlFilter. jetty-2.2.4 - 02 August 1999 - + Better help on Jetty.Server - + Fixed bugs in HtmlFilter parser and added TestHarness. - + HtmlFilter blanks IfModifiedSince headers on construction - + HttpRequests may be passed to HttpFilter constructors. - + Improved cfg RCS script. - + ThreadedServer can use subclasses of Thread. + + better help on jetty.server Better help on Jetty.Server + + fixed bugs in htmlfilter parser and added testharness. Fixed bugs in + HtmlFilter parser and added TestHarness. + + htmlfilter blanks ifmodifiedsince headers on construction HtmlFilter blanks + IfModifiedSince headers on construction + + httprequests may be passed to httpfilter constructors. HttpRequests may be + passed to HttpFilter constructors. + + improved cfg rcs script. Improved cfg RCS script. + + threadedserver can use subclasses of thread. ThreadedServer can use + subclasses of Thread. jetty-2.2.3 - 27 July 1999 - + Added stop call to HttpServer, used by Exit Servlet. - + FileHandler defaults to allowing directory access. - + Fixed parser bug in HtmlFilter - + Improved performance of com.mortbay.HTML.Heading - + JDBC tests modified to use cloudscape as DB. - + Made setInitialize public in ServletHolder - + Simplified JDBC connection handling so that it works with Java1.2 - albeit + + added stop call to httpserver, used by exit servlet. Added stop call to + HttpServer, used by Exit Servlet. + + filehandler defaults to allowing directory access. FileHandler defaults to + allowing directory access. + + fixed parser bug in htmlfilter Fixed parser bug in HtmlFilter + + improved performance of com.mortbay.html.heading Improved performance of + com.mortbay.HTML.Heading + + jdbc tests modified to use cloudscape as db. JDBC tests modified to use + cloudscape as DB. + + made setinitialize public in servletholder Made setInitialize public in + ServletHolder + + simplified jdbc connection handling so that it works with java1.2 - al + Simplified JDBC connection handling so that it works with Java1.2 - albeit less efficiently. jetty-2.2.2 - 22 July 1999 - + File handler passes through not allowed options for non existant files. - + Fixed bug in com.mortbay.Util.IO with thread routines. - + Fixed bug in HtmlFilter that prevented single char buffers from being - written. - + Fixed bug with CLASSPATH in FileJarServletLoader after attempt to load from - a jar. - + Implemented getResourceAsStream in FileJarServletLoader - + Improved com.mortbay.Base.Log handling of different JVMs - + Minor fixes to README - + Moved more test harnesses out of classes. - + NotFoundHandler can repond with SC_METHOD_NOT_ALLOWED. + + file handler passes through not allowed options for non existant files File + handler passes through not allowed options for non existant files. + + fixed bug in com.mortbay.util.io with thread routines. Fixed bug in + com.mortbay.Util.IO with thread routines. + + fixed bug in htmlfilter that prevented single char buffers from being Fixed + bug in HtmlFilter that prevented single char buffers from being written. + + fixed bug with classpath in filejarservletloader after attempt to load Fixed + bug with CLASSPATH in FileJarServletLoader after attempt to load from a jar. + + implemented getresourceasstream in filejarservletloader Implemented + getResourceAsStream in FileJarServletLoader + + improved com.mortbay.base.log handling of different jvms Improved + com.mortbay.Base.Log handling of different JVMs + + minor fixes to readme Minor fixes to README + + moved more test harnesses out of classes. Moved more test harnesses out of + classes. + + notfoundhandler can repond with sc_method_not_allowed. NotFoundHandler can + repond with SC_METHOD_NOT_ALLOWED. jetty-2.2.1 - 18 July 1999 - + Added optional resourceBase property to HttpConfiguration. This is used as a - URL prefix in the getResource API and was suggested by the JSERV and Tomcat + + added optional resourcebase property to httpconfiguration. this is use Added + optional resourceBase property to HttpConfiguration. This is used as a URL + prefix in the getResource API and was suggested by the JSERV and Tomcat implementors. - + Added TerseExceptionHandler - + Comma separate header fields. - + Decoupled ExceptionHandler configuration from Handler stacks. Old config + + added terseexceptionhandler Added TerseExceptionHandler + + comma separate header fields. Comma separate header fields. + + decoupled exceptionhandler configuration from handler stacks. old conf + Decoupled ExceptionHandler configuration from Handler stacks. Old config style will produce warning and Default behavior. See new config file format for changes. - + Handle continuation lines in HttpHeader. - + HtmlFilter resets last-modified and content-length headers. - + Ignore IOException in ThreadedServer.run() when closing. - + Implemented com.mortbay.Util.IO as a ThreadPool - + Less verbose debug in PropertyTree - + Limit maximum line length in HttpInputStream. - + Protect against duplicate single valued headers. - + Response with SC_BAD_REQUEST rather than close in more circumstances + + handle continuation lines in httpheader. Handle continuation lines in + HttpHeader. + + htmlfilter resets last-modified and content-length headers. HtmlFilter + resets last-modified and content-length headers. + + ignore ioexception in threadedserver.run() when closing. Ignore IOException + in ThreadedServer.run() when closing. + + implemented com.mortbay.util.io as a threadpool Implemented + com.mortbay.Util.IO as a ThreadPool + + less verbose debug in propertytree Less verbose debug in PropertyTree + + limit maximum line length in httpinputstream. Limit maximum line length in + HttpInputStream. + + protect against duplicate single valued headers. Protect against duplicate + single valued headers. + + response with sc_bad_request rather than close in more circumstances + Response with SC_BAD_REQUEST rather than close in more circumstances jetty-2.2.0 - 01 July 1999 - + Added Protekt SSL HttpListener - + Exit servlet improved (a little). - + Fixed some of the javadoc formatting. - + Improved feature description page. - + Moved GNUJSP and Protekt listener to a contrib hierarchy. - + ThreadedServer.stop() closes socket before interrupting threads. + + added protekt ssl httplistener Added Protekt SSL HttpListener + + exit servlet improved (a little). Exit servlet improved (a little). + + fixed some of the javadoc formatting. Fixed some of the javadoc formatting. + + improved feature description page. Improved feature description page. + + moved gnujsp and protekt listener to a contrib hierarchy. Moved GNUJSP and + Protekt listener to a contrib hierarchy. + + threadedserver.stop() closes socket before interrupting threads. + ThreadedServer.stop() closes socket before interrupting threads. jetty-2.2.Beta4 - 29 June 1999 - + Added comments to configuration files. - + Added getGlobalProperty to Jetty.Server and used this to configure default - page type. - + Added JettyMinimalDemo.prp as an example of an abbreviated configuration. - + Added property handling to ServletHandler to read JRUN servlet configuration + + added comments to configuration files. Added comments to configuration files. - + Altered meaning of * in PropertyTree to assist in abbreviated configuration + + added getglobalproperty to jetty.server and used this to configure def Added + getGlobalProperty to Jetty.Server and used this to configure default page + type. + + added jettyminimaldemo.prp as an example of an abbreviated configurati Added + JettyMinimalDemo.prp as an example of an abbreviated configuration. + + added property handling to servlethandler to read jrun servlet configu Added + property handling to ServletHandler to read JRUN servlet configuration files. - + Expanded Mime.prp file - + FileHandler flushes files from cache in DELETE method. - + Made ServerSocket and accept call generic in ThreadedServer for SSL - listeners. - + Options "allowDir" added to FileHandler. - + Restructured com.mortbay.Jetty.Server for better clarity and documentation. - + ThreadedServer.stop() now waits until all threads are stopped. - + Updated README.txt + + altered meaning of * in propertytree to assist in abbreviated configur + Altered meaning of * in PropertyTree to assist in abbreviated configuration + files. + + expanded mime.prp file Expanded Mime.prp file + + filehandler flushes files from cache in delete method. FileHandler flushes + files from cache in DELETE method. + + made serversocket and accept call generic in threadedserver for ssl Made + ServerSocket and accept call generic in ThreadedServer for SSL listeners. + + options "allowdir" added to filehandler. Options "allowDir" added to + FileHandler. + + restructured com.mortbay.jetty.server for better clarity and documenta + Restructured com.mortbay.Jetty.Server for better clarity and documentation. + + threadedserver.stop() now waits until all threads are stopped. + ThreadedServer.stop() now waits until all threads are stopped. + + updated readme.txt Updated README.txt jetty-2.2.Beta3 - 22 June 1999 - + Added alternate constructors to HTML.Include for InputStream. - + Added file cache to FileHandler - + Applied contributed patch of spelling and typo corrections - + Fixed bug in HttpResponse flush. - + Fixed file and socket leaks in Include and Embed tags. - + Implemented efficient version of ServletContext.getResourceAsStream() that + + added alternate constructors to html.include for inputstream. Added + alternate constructors to HTML.Include for InputStream. + + added file cache to filehandler Added file cache to FileHandler + + applied contributed patch of spelling and typo corrections Applied + contributed patch of spelling and typo corrections + + fixed bug in httpresponse flush. Fixed bug in HttpResponse flush. + + fixed file and socket leaks in include and embed tags. Fixed file and socket + leaks in Include and Embed tags. + + implemented efficient version of servletcontext.getresourceasstream() + Implemented efficient version of ServletContext.getResourceAsStream() that does not open a new socket connection (as does getResource()). - + Improved Block.write. - + LookAndFeelServlet uses getResourceAsStream to get the file to wrap. This + + improved block.write. Improved Block.write. + + lookandfeelservlet uses getresourceasstream to get the file to wrap. t + LookAndFeelServlet uses getResourceAsStream to get the file to wrap. This allows it to benefit from any caching done and to wrap arbitrary content (not just files). - + Ran dos2unix on all text files - + Re-implemented ThreadedServer to improve and balance performance. - + Restructure demo so that LookAndFeel content comes from simple handler + + ran dos2unix on all text files Ran dos2unix on all text files + + re-implemented threadedserver to improve and balance performance. + Re-implemented ThreadedServer to improve and balance performance. + + restructure demo so that lookandfeel content comes from simple handler + Restructure demo so that LookAndFeel content comes from simple handler stack. - + Server.shutdown() clears configuration so that server may be restarted in + + server.shutdown() clears configuration so that server may be restarted + Server.shutdown() clears configuration so that server may be restarted in same virtual machine. jetty-2.2.Beta2 - 12 June 1999 - + Added all write methods to HttpOutputStream$SwitchOutputStream - + Added com.mortbay.Jetty.Server.shutdown() for gentler shutdown of server. - Called from Exit servlet - + Handle path info of a dynamic loaded servlets and correctly set the servlet + + added all write methods to httpoutputstream$switchoutputstream Added all + write methods to HttpOutputStream$SwitchOutputStream + + added com.mortbay.jetty.server.shutdown() for gentler shutdown of serv Added + com.mortbay.Jetty.Server.shutdown() for gentler shutdown of server. Called + from Exit servlet + + handle path info of a dynamic loaded servlets and correctly set the s + Handle path info of a dynamic loaded servlets and correctly set the servlet path. - + HttpRequest.getParameterNames() no longer alters the order returned by + + httprequest.getparameternames() no longer alters the order returned by + HttpRequest.getParameterNames() no longer alters the order returned by getQueryString(). - + Standardized date format in persistent cookies. + + standardized date format in persistent cookies. Standardized date format in + persistent cookies. jetty-2.2.Beta1 - 07 June 1999 - + Allow configuration of MinListenerThreads, MaxListenerThreads, + + allow configuration of minlistenerthreads, maxlistenerthreads, Allow + configuration of MinListenerThreads, MaxListenerThreads, MaxListenerThreadIdleMs - + Close files after use to avoid "file leak" under heavy load. - + Defined abstract ServletLoader, derivations of which can be specified in + + close files after use to avoid "file leak" under heavy load. Close files + after use to avoid "file leak" under heavy load. + + defined abstract servletloader, derivations of which can be specified + Defined abstract ServletLoader, derivations of which can be specified in HttpConfiguration properties. - + Destroy requests and responses to help garbage collector. - + Don't warn about IOExceptions unless Debug is on. - + Fixed cache in FileJarServletLoader - + Fixed incorrect version numbers in a few places. - + Fixed missing copyright messages from some contributions - + HtmlFilter optimized for being called by a buffered writer. - + Implemented all HttpServer attribute methods by mapping to the - HttpConfiguration properties. Dynamic reconfiguration is NOT supported by - these methods (but we are thinking about it). - + Improved ThreadPool synchronization and added minThreads. - + Included GNUJSP 0.9.9 - + Limit the job queue only grow to the max number of threads. - + Optional use of DateCache in log file format - + Restructure ThreadedServer to reduce object creation. + + destroy requests and responses to help garbage collector. Destroy requests + and responses to help garbage collector. + + don't warn about ioexceptions unless debug is on. Don't warn about + IOExceptions unless Debug is on. + + fixed cache in filejarservletloader Fixed cache in FileJarServletLoader + + fixed incorrect version numbers in a few places. Fixed incorrect version + numbers in a few places. + + fixed missing copyright messages from some contributions Fixed missing + copyright messages from some contributions + + htmlfilter optimized for being called by a buffered writer. HtmlFilter + optimized for being called by a buffered writer. + + implemented all httpserver attribute methods by mapping to the Implemented + all HttpServer attribute methods by mapping to the HttpConfiguration + properties. Dynamic reconfiguration is NOT supported by these methods (but + we are thinking about it). + + improved threadpool synchronization and added minthreads. Improved + ThreadPool synchronization and added minThreads. + + included gnujsp 0.9.9 Included GNUJSP 0.9.9 + + limit the job queue only grow to the max number of threads. Limit the job + queue only grow to the max number of threads. + + optional use of datecache in log file format Optional use of DateCache in + log file format + + restructure threadedserver to reduce object creation. Restructure + ThreadedServer to reduce object creation. jetty-2.2.Beta0 - 31 May 1999 - + Added "Initialize" attribute to servlet configuration to allow servlet to be + + added "initialize" attribute to servlet configuration to allow servlet Added + "Initialize" attribute to servlet configuration to allow servlet to be initialized when loaded. - + Added HttpResponse.requestHandled() method to avoid bug with servlet doHead + + added httpresponse.requesthandled() method to avoid bug with servlet d Added + HttpResponse.requestHandled() method to avoid bug with servlet doHead method. - + Added Page.rewind() method to allow a page to be written multiple times - + Handle malformed % characters in URLs. - + HttpRequest.getCookies returns empty array rather than null for no cookies. - + Included and improved version of ThreadPool for significant performance + + added page.rewind() method to allow a page to be written multiple time Added + Page.rewind() method to allow a page to be written multiple times + + handle malformed % characters in urls. Handle malformed % characters in + URLs. + + httprequest.getcookies returns empty array rather than null for no coo + HttpRequest.getCookies returns empty array rather than null for no cookies. + + included and improved version of threadpool for significant performanc + Included and improved version of ThreadPool for significant performance improvement under high load. - + Included contributed com.mortbay.Jetty.StressTester class - + LogHandler changed to support only a single outfile and optional append. - + Removed support for STF - + Servlet loader handles jar files with different files separator. - + ThreadedServer gently shuts down. - + Token effort to keep test files out of the jar + + included contributed com.mortbay.jetty.stresstester class Included + contributed com.mortbay.Jetty.StressTester class + + loghandler changed to support only a single outfile and optional appen + LogHandler changed to support only a single outfile and optional append. + + removed support for stf Removed support for STF + + servlet loader handles jar files with different files separator. Servlet + loader handles jar files with different files separator. + + threadedserver gently shuts down. ThreadedServer gently shuts down. + + token effort to keep test files out of the jar Token effort to keep test + files out of the jar jetty-2.2.Alpha1 - 07 May 1999 - + Call destroy on old servlets when reloading. - + Dynamic servlets can have autoReload configured - + Fixed bug in SessionDump - + Made capitalization of config file more consistent(ish) - + ServletHolder can auto reload servlets - + Wait for requests to complete before reloading. + + call destroy on old servlets when reloading. Call destroy on old servlets + when reloading. + + dynamic servlets can have autoreload configured Dynamic servlets can have + autoReload configured + + fixed bug in sessiondump Fixed bug in SessionDump + + made capitalization of config file more consistent(ish) Made capitalization + of config file more consistent(ish) + + servletholder can auto reload servlets ServletHolder can auto reload + servlets + + wait for requests to complete before reloading. Wait for requests to + complete before reloading. jetty-2.2.Alpha0 - 06 May 1999 - + Added reload method to ServletHolder, but no way to call it yet. - + Added ServletLoader implementation if ClassLoader. - + Changed options for FileServer - + Dynamic loading of servlets. - + Fixed date overflow in Cookies - + HttpHandlers given setProperties method to configure via Properties. - + HttpListener class can be configured - + HttpResponse.sendError avoids IllegalStateException - + Implemented ServletServer - + Improved PropertyTree implementation - + Improved SessionDump servlet - + Mime suffix mapping can be configured. - + New Server class using PropertyTree for configuration - + Old Jetty.Server class renamed to Jetty.Server21 - + Removed historic API from sessions - + Removed SimpleServletServer + + added reload method to servletholder, but no way to call it yet. Added + reload method to ServletHolder, but no way to call it yet. + + added servletloader implementation if classloader. Added ServletLoader + implementation if ClassLoader. + + changed options for fileserver Changed options for FileServer + + dynamic loading of servlets. Dynamic loading of servlets. + + fixed date overflow in cookies Fixed date overflow in Cookies + + httphandlers given setproperties method to configure via properties. + HttpHandlers given setProperties method to configure via Properties. + + httplistener class can be configured HttpListener class can be configured + + httpresponse.senderror avoids illegalstateexception HttpResponse.sendError + avoids IllegalStateException + + implemented servletserver Implemented ServletServer + + improved propertytree implementation Improved PropertyTree implementation + + improved sessiondump servlet Improved SessionDump servlet + + mime suffix mapping can be configured. Mime suffix mapping can be + configured. + + new server class using propertytree for configuration New Server class using + PropertyTree for configuration + + old jetty.server class renamed to jetty.server21 Old Jetty.Server class + renamed to Jetty.Server21 + + removed historic api from sessions Removed historic API from sessions + + removed simpleservletserver Removed SimpleServletServer jetty-2.1.7 - 22 April 1999 - + Fixed showstopper bug with getReader and getWriter in requests and - responses. - + HttpFilter uses package interface to get HttpOutputStream + + fixed showstopper bug with getreader and getwriter in requests and Fixed + showstopper bug with getReader and getWriter in requests and responses. + + httpfilter uses package interface to get httpoutputstream HttpFilter uses + package interface to get HttpOutputStream jetty-2.1.6 - 21 April 1999 - + Added additional date formats for HttpHeader.getDateHeader - + New simpler version of PropertyTree - + Reduced initial size of most hashtables to reduce default memory overheads. - + Return EOF from HttpInputStream that has a content length. - + Throw IllegalStateException as required from gets of - input/output/reader/writer in requests/responses. - + Updated PropertyTreeEditor + + added additional date formats for httpheader.getdateheader Added additional + date formats for HttpHeader.getDateHeader + + new simpler version of propertytree New simpler version of PropertyTree + + reduced initial size of most hashtables to reduce default memory overh + Reduced initial size of most hashtables to reduce default memory overheads. + + return eof from httpinputstream that has a content length. Return EOF from + HttpInputStream that has a content length. + + throw illegalstateexception as required from gets of Throw + IllegalStateException as required from gets of input/output/reader/writer in + requests/responses. + + updated propertytreeeditor Updated PropertyTreeEditor jetty-2.1.5 - 15 April 1999 - + Added setType methods to com.mortbay.FTP.Ftp - + Fixed alignment bug in TableForm - + Fixed bug in ServletDispatch for null pathInfo - + Fixed bugs with invalid sessions - + Form parameters protected against multiple decodes when redirected. - + HtmlFilter now expands to the URL encoded session if required. - + Implemented HttpRequest.getReader() - + Instrumented most of the demo to support URL session encoding. - + Moved SessionHandler to front of stacks - + Page factory requires response for session encoding - + Reduced session memory overhead of sessions - + Removed RFCs from package - + Servlet log has been diverted to com.mortbay.Base.Log.event() Thus debug + + added settype methods to com.mortbay.ftp.ftp Added setType methods to + com.mortbay.FTP.Ftp + + fixed alignment bug in tableform Fixed alignment bug in TableForm + + fixed bug in servletdispatch for null pathinfo Fixed bug in ServletDispatch + for null pathInfo + + fixed bugs with invalid sessions Fixed bugs with invalid sessions + + form parameters protected against multiple decodes when redirected. Form + parameters protected against multiple decodes when redirected. + + htmlfilter now expands to the url encoded session if requi + HtmlFilter now expands to the URL encoded session if required. + + implemented httprequest.getreader() Implemented HttpRequest.getReader() + + instrumented most of the demo to support url session encoding. Instrumented + most of the demo to support URL session encoding. + + moved sessionhandler to front of stacks Moved SessionHandler to front of + stacks + + page factory requires response for session encoding Page factory requires + response for session encoding + + reduced session memory overhead of sessions Reduced session memory overhead + of sessions + + removed rfcs from package Removed RFCs from package + + servlet log has been diverted to com.mortbay.base.log.event() thus deb + Servlet log has been diverted to com.mortbay.Base.Log.event() Thus debug does not need to be turned on to see servlet logs. - + Session URL encoding fixed for relative URLs. + + session url encoding fixed for relative urls. Session URL encoding fixed for + relative URLs. jetty-2.1.4 - 26 March 1999 - + fixed bug in getRealPath - + Fixed problem compiling PathMap under some JDKs. - + getPathTranslated now call getRealPath with pathInfo (as per spec). - + HttpRequest attributes implemented. - + pathInfo returns null for zero length pathInfo (as per spec). Sorry if this + + fixed bug in getrealpath fixed bug in getRealPath + + fixed problem compiling pathmap under some jdks. Fixed problem compiling + PathMap under some JDKs. + + getpathtranslated now call getrealpath with pathinfo (as per spec). + getPathTranslated now call getRealPath with pathInfo (as per spec). + + httprequest attributes implemented. HttpRequest attributes implemented. + + pathinfo returns null for zero length pathinfo (as per spec). sorry if + pathInfo returns null for zero length pathInfo (as per spec). Sorry if this breaks your servlets - it is a pain! - + Reduced HTML dependence in HTTP package to allow minimal configuration - + Session max idle time implemented. - + Tightened license agreement so that binary distributions are required to + + reduced html dependence in http package to allow minimal configuration + Reduced HTML dependence in HTTP package to allow minimal configuration + + session max idle time implemented. Session max idle time implemented. + + tightened license agreement so that binary distributions are required + Tightened license agreement so that binary distributions are required to include the license file. jetty-2.1.3 - 19 March 1999 - + Added support for suffixes to PathMap - + Included GNUJSP implementation of Java Server Pages - + Use Java2 javadoc + + added support for suffixes to pathmap Added support for suffixes to PathMap + + included gnujsp implementation of java server pages Included GNUJSP + implementation of Java Server Pages + + use java2 javadoc Use Java2 javadoc jetty-2.1.2 - 09 March 1999 - + API documentation for JSDK 2.1.1 - + Cascading style sheet HTML element added. - + Converted most servlets to HttpServlets using do Methods. - + Fixed trailing / bug in FileHandler (again!). - + JSDK 2.1.1 + + api documentation for jsdk 2.1.1 API documentation for JSDK 2.1.1 + + cascading style sheet html element added. Cascading style sheet HTML element + added. + + converted most servlets to httpservlets using do methods. Converted most + servlets to HttpServlets using do Methods. + + fixed trailing / bug in filehandler (again!). Fixed trailing / bug in + FileHandler (again!). + + jsdk 2.1.1 JSDK 2.1.1 jetty-2.1.1 - 05 March 1999 - + com.mortbay.Base.DateCache class added and used to speed date handling. - + Fast char buffer handling in HttpInputStream - + Faster version of HttpHeader.read() - + Faster version of HttpInputStream.readLine(). - + Faster version of HttpRequest - + Handle '.' in configured paths (temp fix until PropertyTrees) - + Reduced number of calls to getRemoteHost for optimization - + Size all StringBuffers + + com.mortbay.base.datecache class added and used to speed date handling + com.mortbay.Base.DateCache class added and used to speed date handling. + + fast char buffer handling in httpinputstream Fast char buffer handling in + HttpInputStream + + faster version of httpheader.read() Faster version of HttpHeader.read() + + faster version of httpinputstream.readline(). Faster version of + HttpInputStream.readLine(). + + faster version of httprequest Faster version of HttpRequest + + handle '.' in configured paths (temp fix until propertytrees) Handle '.' in + configured paths (temp fix until PropertyTrees) + + reduced number of calls to getremotehost for optimization Reduced number of + calls to getRemoteHost for optimization + + size all stringbuffers Size all StringBuffers jetty-2.1.0 - 22 February 1999 - + Deprecated com.mortbay.Util.STF - + getServlet methods return null. - + image/jpg -> image/jpeg - + PropertyTrees (see new Demo page) - + ServletDispatch (see new Demo page) - + Session URL Encoding + + deprecated com.mortbay.util.stf Deprecated com.mortbay.Util.STF + + getservlet methods return null. getServlet methods return null. + + image/jpg -> image/jpeg image/jpg -> image/jpeg + + propertytrees (see new demo page) PropertyTrees (see new Demo page) + + servletdispatch (see new demo page) ServletDispatch (see new Demo page) + + session url encoding Session URL Encoding jetty-2.1.B1 - 13 February 1999 - + Added video/quicktime to default MIME types. - + Fixed bug with if-modified-since in FileHandler - + Fixed bug with MultipartRequest. - + Implemented getResource and getResourceAsStream (NOT Tested!). - + Implemented Handler translations and getRealPath. - + Implemented RequestDispatcher (NOT Tested!). - + Improved handling of File.separator in FileHandler. - + Replace package com.mortbay.Util.Gateway with class - com.mortbay.Util.InetGateway - + Updated DefaultExceptionHandler. - + Updated InetAddrPort. - + Updated URI. + + added video/quicktime to default mime types. Added video/quicktime to + default MIME types. + + fixed bug with if-modified-since in filehandler Fixed bug with + if-modified-since in FileHandler + + fixed bug with multipartrequest. Fixed bug with MultipartRequest. + + implemented getresource and getresourceasstream (not tested!). Implemented + getResource and getResourceAsStream (NOT Tested!). + + implemented handler translations and getrealpath. Implemented Handler + translations and getRealPath. + + implemented requestdispatcher (not tested!). Implemented RequestDispatcher + (NOT Tested!). + + improved handling of file.separator in filehandler. Improved handling of + File.separator in FileHandler. + + replace package com.mortbay.util.gateway with class Replace package + com.mortbay.Util.Gateway with class com.mortbay.Util.InetGateway + + updated defaultexceptionhandler. Updated DefaultExceptionHandler. + + updated inetaddrport. Updated InetAddrPort. + + updated uri. Updated URI. jetty-2.1.B0 - 30 January 1999 - + Added plug gateway classes com.mortbay.Util.Gateway - + Added support for PUT, MOVE, DELETE in FileHandler - + FileHandler now sets content length. - + Fixed command line bug with SimpleServletConfig - + Minor changes to support MS J++ and its non standard language extensions - - MMMmmm should have left it unchanged! - + Uses JSDK2.1 API, but not all methods implemented. + + added plug gateway classes com.mortbay.util.gateway Added plug gateway + classes com.mortbay.Util.Gateway + + added support for put, move, delete in filehandler Added support for PUT, + MOVE, DELETE in FileHandler + + filehandler now sets content length. FileHandler now sets content length. + + fixed command line bug with simpleservletconfig Fixed command line bug with + SimpleServletConfig + + minor changes to support ms j++ and its non standard language extensio Minor + changes to support MS J++ and its non standard language extensions - MMMmmm + should have left it unchanged! + + uses jsdk2.1 api, but not all methods implemented. Uses JSDK2.1 API, but not + all methods implemented. jetty-2.0.5 - 15 December 1998 - + added getHeaderNoParams - + Temp fix to getCharacterEncoding + + added getheadernoparams added getHeaderNoParams + + temp fix to getcharacterencoding Temp fix to getCharacterEncoding jetty-2.0.4 - 10 December 1998 - + Implement getCharacterEncoding - + Improved default Makefile behaviour - + Improved error code returns - + Portability issues solved for Apple's - + Removed MORTBAY_HOME support from Makefiles - + Use real release of JSDK2.0 (rather than beta). + + implement getcharacterencoding Implement getCharacterEncoding + + improved default makefile behaviour Improved default Makefile behaviour + + improved error code returns Improved error code returns + + portability issues solved for apple's Portability issues solved for Apple's + + removed mortbay_home support from makefiles Removed MORTBAY_HOME support + from Makefiles + + use real release of jsdk2.0 (rather than beta). Use real release of JSDK2.0 + (rather than beta). jetty-2.0.3 - 13 November 1998 - + Fix bug with index files for Jetty.Server. Previously servers configured - with com.mortbay.Jetty.Server would not handle index.html files. Need to - make this configurable in the prp file. - + Fixed errors in README file: com.mortbay.Jetty.Server was called + + fix bug with index files for jetty.server. previously servers configur Fix + bug with index files for Jetty.Server. Previously servers configured with + com.mortbay.Jetty.Server would not handle index.html files. Need to make + this configurable in the prp file. + + fixed errors in readme file: com.mortbay.jetty.server was called Fixed + errors in README file: com.mortbay.Jetty.Server was called com.mortbay.HTTP.Server - + Limit threads in ThreadedServer and low priority listener option greatly - improve performance under worse case loads. + + limit threads in threadedserver and low priority listener option great Limit + threads in ThreadedServer and low priority listener option greatly improve + performance under worse case loads. jetty-2.0.2 - 01 November 1998 - + Add thread pool to threaded server for significant performance improvement. - + Buffer files during configuration - + Buffer HTTP Response headers. - + Use JETTY_HOME rather than MORTBAY_HOME for build environment + + add thread pool to threaded server for significant performance improve Add + thread pool to threaded server for significant performance improvement. + + buffer files during configuration Buffer files during configuration + + buffer http response headers. Buffer HTTP Response headers. + + use jetty_home rather than mortbay_home for build environment Use JETTY_HOME + rather than MORTBAY_HOME for build environment jetty-2.0.1 - 27 October 1998 - + Released under an Open Source license. + + released under an open source license. Released under an Open Source + license. jetty-2.0.0 - 25 October 1998 - + Added multipart/form-data demo. - + Fixed Code.formatObject handling of null objects. - + Removed Chat demo (too many netscape dependencies). - + Removed exceptional case from FileHandler redirect. + + added multipart/form-data demo. Added multipart/form-data demo. + + fixed code.formatobject handling of null objects. Fixed Code.formatObject + handling of null objects. + + removed chat demo (too many netscape dependencies). Removed Chat demo (too + many netscape dependencies). + + removed exceptional case from filehandler redirect. Removed exceptional case + from FileHandler redirect. jetty-2.0.Beta3 - 29 September 1998 - + Added com.mortbay.HTTP.MultiPartRequest to handle file uploads - + Added com.mortbay.Jetty.Server (see README.Jetty) - + Demo converted to an instance of com.mortbay.Jetty.Server - + Fixed Log Handler again. - + Ignore exception from HttpListener - + Properly implemented multiple listening addresses - + Send 301 for directories without trailing / in FileHandler + + added com.mortbay.http.multipartrequest to handle file uploads Added + com.mortbay.HTTP.MultiPartRequest to handle file uploads + + added com.mortbay.jetty.server (see readme.jetty) Added + com.mortbay.Jetty.Server (see README.Jetty) + + demo converted to an instance of com.mortbay.jetty.server Demo converted to + an instance of com.mortbay.Jetty.Server + + fixed log handler again. Fixed Log Handler again. + + ignore exception from httplistener Ignore exception from HttpListener + + properly implemented multiple listening addresses Properly implemented + multiple listening addresses + + send 301 for directories without trailing / in filehandler Send 301 for + directories without trailing / in FileHandler jetty-2.0Beta2 - 01 July 1998 - + Fixed Log Handler for HTTP/1.1 - + Slight improvement in READMEEs + + fixed log handler for http/1.1 Fixed Log Handler for HTTP/1.1 + + slight improvement in readmees Slight improvement in READMEEs jetty-2.0Beta1 - 01 June 1998 - + Fixed bug with calls to service during initialization of servlet - + Handle full URLs in HTTP requests (to some extent) - + Improved performance of Code.debug() calls, significantly in the case of non + + fixed bug with calls to service during initialization of servlet Fixed bug + with calls to service during initialization of servlet + + handle full urls in http requests (to some extent) Handle full URLs in HTTP + requests (to some extent) + + improved performance of code.debug() calls, significantly in the case + Improved performance of Code.debug() calls, significantly in the case of non matching debug patterns. - + Improved performance with special asciiToLowerCase - + Provided addSection on com.mortbay.HTML.Page - + Provided reset on com.mortbay.HTML.Composite. - + Proxy demo in different server instance - + Warn if MSIE used for multi part MIME. + + improved performance with special asciitolowercase Improved performance with + special asciiToLowerCase + + provided addsection on com.mortbay.html.page Provided addSection on + com.mortbay.HTML.Page + + provided reset on com.mortbay.html.composite. Provided reset on + com.mortbay.HTML.Composite. + + proxy demo in different server instance Proxy demo in different server + instance + + warn if msie used for multi part mime. Warn if MSIE used for multi part + MIME. jetty-2.0Alpha2 - 01 May 1998 - + Added date format to Log - + Added timezone to Log - + Handle params in getIntHeader and getDateHeader - + Handle Single Threaded servlets with servlet pool - + JDK1.2 javax.servlet API - + Removed HttpRequest.getByteContent - + Use javax.servlet.http.Cookie - + Use javax.servlet.http.HttpSession - + Use javax.servlet.http.HttpUtils.parsePostData + + added date format to log Added date format to Log + + added timezone to log Added timezone to Log + + handle params in getintheader and getdateheader Handle params in + getIntHeader and getDateHeader + + handle single threaded servlets with servlet pool Handle Single Threaded + servlets with servlet pool + + jdk1.2 javax.servlet api JDK1.2 javax.servlet API + + removed httprequest.getbytecontent Removed HttpRequest.getByteContent + + use javax.servlet.http.cookie Use javax.servlet.http.Cookie + + use javax.servlet.http.httpsession Use javax.servlet.http.HttpSession + + use javax.servlet.http.httputils.parsepostdata Use + javax.servlet.http.HttpUtils.parsePostData jetty-1.3.5 - 01 May 1998 - + Added date format to Log - + Correct handling of multiple parameters - + Debug triggers added to com.mortbay.Base.Code - + Fixed socket inet bug in FTP + + added date format to log Added date format to Log + + correct handling of multiple parameters Correct handling of multiple + parameters + + debug triggers added to com.mortbay.base.code Debug triggers added to + com.mortbay.Base.Code + + fixed socket inet bug in ftp Fixed socket inet bug in FTP jetty-2.0Alpha1 - 08 April 1998 - + accept chunked data - + Add HTTP/1.1 Date: header - + Correct formatting of Date HTTP headers - + Debug triggers added to com.mortbay.Base.Code - + Fixed forward bug with no port number - + handle extra spaces in HTTP headers - + Handle file requests with If-Modified-Since: or If-Unmodified-Since: - + Handle HEAD properly - + Handle HTTP/1.1 Host: header - + HttpTests test harness - + persistent connections - + Really fixed handling of multiple parameters - + Removed HttpRequestHeader class - + Requires Host: header for 1.1 requests - + Send 100 Continue for HTTP/1.1 requests (concerned about push???) - + Send Connection: close - + Sends chunked data for 1.1 responses of unknown length. + + accept chunked data accept chunked data + + add http/1.1 date: header Add HTTP/1.1 Date: header + + correct formatting of date http headers Correct formatting of Date HTTP + headers + + debug triggers added to com.mortbay.base.code Debug triggers added to + com.mortbay.Base.Code + + fixed forward bug with no port number Fixed forward bug with no port number + + handle extra spaces in http headers handle extra spaces in HTTP headers + + handle file requests with if-modified-since: or if-unmodified-since: Handle + file requests with If-Modified-Since: or If-Unmodified-Since: + + handle head properly Handle HEAD properly + + handle http/1.1 host: header Handle HTTP/1.1 Host: header + + httptests test harness HttpTests test harness + + persistent connections persistent connections + + really fixed handling of multiple parameters Really fixed handling of + multiple parameters + + removed httprequestheader class Removed HttpRequestHeader class + + requires host: header for 1.1 requests Requires Host: header for 1.1 + requests + + send 100 continue for http/1.1 requests (concerned about push???) Send 100 + Continue for HTTP/1.1 requests (concerned about push???) + + send connection: close Send Connection: close + + sends chunked data for 1.1 responses of unknown length. Sends chunked data + for 1.1 responses of unknown length. jetty-1.3.4 - 15 March 1998 - + Dump servlet enhanced to exercise these changes. - + Fixed handling of multiple parameters in query and form content. + + dump servlet enhanced to exercise these changes. Dump servlet enhanced to + exercise these changes. + + fixed handling of multiple parameters in query and form content. Fixed + handling of multiple parameters in query and form content. "?A=1%2C2&A=C%2CD" now returns two values ("1,2" & "C,D") rather than 4. - + ServletHandler now takes an optional file base directory name which is used + + servlethandler now takes an optional file base directory name which is + ServletHandler now takes an optional file base directory name which is used to set the translated path for pathInfo in servlet requests. jetty-1.3.3 - + Closed exception window in HttpListener.java - + Fixed TableForm.addButtonArea bug. - + TableForm.extendRow() uses existing cell + + closed exception window in httplistener.java Closed exception window in + HttpListener.java + + fixed tableform.addbuttonarea bug. Fixed TableForm.addButtonArea bug. + + tableform.extendrow() uses existing cell TableForm.extendRow() uses existing + cell jetty-1.3.2 - + Added per Table cell composite factories - + Fixed proxy bug with no port number + + added per table cell composite factories Added per Table cell composite + factories + + fixed proxy bug with no port number Fixed proxy bug with no port number jetty-1.3.1 - + Better handling of InvocationTargetException in debug - + ForwardHandler only forwards as http/1.0 (from Tobias.Miller) - + Improved parsing of stack traces - + Minor fixes in SmtpMail - + Minor release adjustments for Tracker + + better handling of invocationtargetexception in debug Better handling of + InvocationTargetException in debug + + forwardhandler only forwards as http/1.0 (from tobias.miller) ForwardHandler + only forwards as http/1.0 (from Tobias.Miller) + + improved parsing of stack traces Improved parsing of stack traces + + minor fixes in smtpmail Minor fixes in SmtpMail + + minor release adjustments for tracker Minor release adjustments for Tracker jetty-1.3.0 - + Added DbAdaptor to JDBC wrappers - + Beta release of Tracker + + added dbadaptor to jdbc wrappers Added DbAdaptor to JDBC wrappers + + beta release of tracker Beta release of Tracker jetty-1.2.0 - + Alternate look and feel for Jetty - + Better Debug configuration - + DebugServlet - + Fixed install bug for nested classes - + Reintroduced STF + + alternate look and feel for jetty Alternate look and feel for Jetty + + better debug configuration Better Debug configuration + + debugservlet DebugServlet + + fixed install bug for nested classes Fixed install bug for nested classes + + reintroduced stf Reintroduced STF jetty-1.1.1 - + Improved documentation + + improved documentation Improved documentation jetty-1.1 - + Improved connection caching in java.mortbay.JDBC - + Moved HttpCode to com.mortbay.Util + + improved connection caching in java.mortbay.jdbc Improved connection caching + in java.mortbay.JDBC + + moved httpcode to com.mortbay.util Moved HttpCode to com.mortbay.Util jetty-1.0.1 - + Bug fixes + + bug fixes Bug fixes jetty-1.0 - + First release in com.mortbay package structure - + Included Util, JDBC, HTML, HTTP, Jetty + + first release in com.mortbay package structure First release in com.mortbay + package structure + + included util, jdbc, html, http, jetty Included Util, JDBC, HTML, HTTP, + Jetty diff --git a/apache-jsp/pom.xml b/apache-jsp/pom.xml index 3916db1835c..4483a67050b 100644 --- a/apache-jsp/pom.xml +++ b/apache-jsp/pom.xml @@ -25,7 +25,7 @@ org.eclipse.jetty.jsp.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}" osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)" - osgi.serviceloader; osgi.serviceloader=javax.servlet.ServletContainerInitializer + osgi.serviceloader;osgi.serviceloader=javax.servlet.ServletContainerInitializer,osgi.serviceloader;osgi.serviceloader=org.apache.juli.logging.Log <_nouses>true diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FileServer.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FileServer.java index 2da99b2aeab..f2381378d87 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FileServer.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/FileServer.java @@ -23,7 +23,6 @@ import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.DefaultHandler; import org.eclipse.jetty.server.handler.HandlerList; import org.eclipse.jetty.server.handler.ResourceHandler; -import org.eclipse.jetty.server.handler.gzip.GzipHandler; /** * Simple Jetty FileServer. @@ -41,6 +40,7 @@ public class FileServer // Create the ResourceHandler. It is the object that will actually handle the request for a given file. It is // a Jetty Handler object so it is suitable for chaining with other handlers as you will see in other examples. ResourceHandler resource_handler = new ResourceHandler(); + // Configure the ResourceHandler. Setting the resource base indicates where the files should be served out of. // In this example it is the current directory but it can be configured to anything that the jvm has access to. resource_handler.setDirectoriesListed(true); @@ -48,11 +48,9 @@ public class FileServer resource_handler.setResourceBase("."); // Add the ResourceHandler to the server. - GzipHandler gzip = new GzipHandler(); - server.setHandler(gzip); HandlerList handlers = new HandlerList(); handlers.setHandlers(new Handler[] { resource_handler, new DefaultHandler() }); - gzip.setHandler(handlers); + server.setHandler(handlers); // Start things up! By using the server.join() the server thread will join with the current thread. // See "http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.html#join()" for more details. diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java index 328765b559d..ce359c79c81 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java @@ -30,7 +30,6 @@ import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.jmx.MBeanContainer; import org.eclipse.jetty.rewrite.handler.RewriteHandler; import org.eclipse.jetty.security.HashLoginService; -import org.eclipse.jetty.server.ConnectorStatistics; import org.eclipse.jetty.server.DebugListener; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.HttpConfiguration; @@ -39,6 +38,7 @@ import org.eclipse.jetty.server.LowResourceMonitor; import org.eclipse.jetty.server.NCSARequestLog; import org.eclipse.jetty.server.SecureRequestCustomizer; import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnectionStatistics; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.SslConnectionFactory; import org.eclipse.jetty.server.handler.ContextHandlerCollection; @@ -193,7 +193,7 @@ public class LikeJettyXml StatisticsHandler stats = new StatisticsHandler(); stats.setHandler(server.getHandler()); server.setHandler(stats); - ConnectorStatistics.addToAllConnectors(server); + ServerConnectionStatistics.addToAllConnectors(server); // === Rewrite Handler RewriteHandler rewrite = new RewriteHandler(); diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneServletContextJmxStats.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneServletContextJmxStats.java index 80b631d7e99..abc59ca2426 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneServletContextJmxStats.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneServletContextJmxStats.java @@ -21,8 +21,8 @@ package org.eclipse.jetty.embedded; import java.lang.management.ManagementFactory; import org.eclipse.jetty.jmx.MBeanContainer; -import org.eclipse.jetty.server.ConnectorStatistics; import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnectionStatistics; import org.eclipse.jetty.servlet.DefaultServlet; import org.eclipse.jetty.servlet.ServletContextHandler; @@ -44,7 +44,7 @@ public class OneServletContextJmxStats context.addServlet(DefaultServlet.class, "/"); // Add Connector Statistics tracking to all connectors - ConnectorStatistics.addToAllConnectors(server); + ServerConnectionStatistics.addToAllConnectors(server); server.start(); server.join(); diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java index fcab2ac596a..048d2844270 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java @@ -21,7 +21,6 @@ package org.eclipse.jetty.annotations; import java.io.IOException; import java.net.MalformedURLException; import java.net.URI; -import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -48,6 +47,7 @@ import org.eclipse.jetty.plus.annotation.ContainerInitializer; import org.eclipse.jetty.util.ConcurrentHashSet; import org.eclipse.jetty.util.MultiException; 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; import org.eclipse.jetty.util.resource.Resource; @@ -81,8 +81,6 @@ public class AnnotationConfiguration extends AbstractConfiguration protected List _containerInitializerAnnotationHandlers = new ArrayList(); protected List _parserTasks; - protected WebAppClassNameResolver _webAppClassNameResolver; - protected ContainerClassNameResolver _containerClassNameResolver; protected CounterStatistic _containerPathStats; protected CounterStatistic _webInfLibStats; @@ -138,15 +136,13 @@ public class AnnotationConfiguration extends AbstractConfiguration protected Exception _exception; protected final AnnotationParser _parser; protected final Set _handlers; - protected final ClassNameResolver _resolver; protected final Resource _resource; protected TimeStatistic _stat; - public ParserTask (AnnotationParser parser, Sethandlers, Resource resource, ClassNameResolver resolver) + public ParserTask (AnnotationParser parser, Sethandlers, Resource resource) { _parser = parser; _handlers = handlers; - _resolver = resolver; _resource = resource; } @@ -160,7 +156,7 @@ public class AnnotationConfiguration extends AbstractConfiguration if (_stat != null) _stat.start(); if (_parser != null) - _parser.parse(_handlers, _resource, _resolver); + _parser.parse(_handlers, _resource); if (_stat != null) _stat.end(); return null; @@ -174,83 +170,7 @@ public class AnnotationConfiguration extends AbstractConfiguration public Resource getResource() { return _resource; - } - - } - - /** - * WebAppClassNameResolver - * - * Checks to see if a classname belongs to hidden or visible packages when scanning, - * and whether a classname that is a duplicate should override a previously - * scanned classname. - * - * This is analogous to the management of classes that the WebAppClassLoader is doing, - * however we don't want to load the classes at this point so we are doing it on - * the name only. - * - */ - public class WebAppClassNameResolver implements ClassNameResolver - { - private WebAppContext _context; - - public WebAppClassNameResolver (WebAppContext context) - { - _context = context; - } - - public boolean isExcluded (String name) - { - if (_context.isSystemClass(name)) return true; - if (_context.isServerClass(name)) return false; - return false; - } - - public boolean shouldOverride (String name) - { - //looking at webapp classpath, found already-parsed class - //of same name - did it come from system or duplicate in webapp? - if (_context.isParentLoaderPriority()) - return false; - return true; - } - } - - - /** - * ContainerClassNameResolver - * - * Checks to see if a classname belongs to a hidden or visible package - * when scanning for annotations and thus whether it should be excluded from - * consideration or not. - * - * This is analogous to the management of classes that the WebAppClassLoader is doing, - * however we don't want to load the classes at this point so we are doing it on - * the name only. - * - */ - public class ContainerClassNameResolver implements ClassNameResolver - { - private WebAppContext _context; - - public ContainerClassNameResolver (WebAppContext context) - { - _context = context; - } - public boolean isExcluded (String name) - { - if (_context.isSystemClass(name)) return false; - if (_context.isServerClass(name)) return true; - return false; - } - - public boolean shouldOverride (String name) - { - //visiting the container classpath, - if (_context.isParentLoaderPriority()) - return true; - return false; - } + } } @@ -390,8 +310,6 @@ public class AnnotationConfiguration extends AbstractConfiguration @Override public void preConfigure(final WebAppContext context) throws Exception { - _webAppClassNameResolver = new WebAppClassNameResolver(context); - _containerClassNameResolver = new ContainerClassNameResolver(context); String tmp = (String)context.getAttribute(SERVLET_CONTAINER_INITIALIZER_EXCLUSION_PATTERN); _sciExcludePattern = (tmp==null?null:Pattern.compile(tmp)); } @@ -445,15 +363,15 @@ public class AnnotationConfiguration extends AbstractConfiguration if (!_discoverableAnnotationHandlers.isEmpty() || _classInheritanceHandler != null || !_containerInitializerAnnotationHandlers.isEmpty()) scanForAnnotations(context); - + // Resolve container initializers List initializers = - (List)context.getAttribute(AnnotationConfiguration.CONTAINER_INITIALIZERS); + (List)context.getAttribute(AnnotationConfiguration.CONTAINER_INITIALIZERS); if (initializers != null && initializers.size()>0) { Map> map = ( Map>) context.getAttribute(AnnotationConfiguration.CLASS_INHERITANCE_MAP); for (ContainerInitializer i : initializers) - i.resolveClasses(context,map); + i.resolveClasses(context,map); } } @@ -723,23 +641,7 @@ public class AnnotationConfiguration extends AbstractConfiguration public Resource getJarFor (ServletContainerInitializer service) throws MalformedURLException, IOException { - //try the thread context classloader to get the jar that loaded the class - URL jarURL = Thread.currentThread().getContextClassLoader().getResource(service.getClass().getName().replace('.','/')+".class"); - - //if for some reason that failed (eg we're in osgi and the TCCL does not know about the service) try the classloader that - //loaded the class - if (jarURL == null) - jarURL = service.getClass().getClassLoader().getResource(service.getClass().getName().replace('.','/')+".class"); - - String loadingJarName = jarURL.toString(); - - int i = loadingJarName.indexOf(".jar"); - if (i < 0) - return null; //not from a jar - - loadingJarName = loadingJarName.substring(0,i+4); - loadingJarName = (loadingJarName.startsWith("jar:")?loadingJarName.substring(4):loadingJarName); - return Resource.newResource(loadingJarName); + return TypeUtil.getLoadedFrom(service.getClass()); } /** @@ -760,26 +662,41 @@ public class AnnotationConfiguration extends AbstractConfiguration if (context == null) throw new IllegalArgumentException("WebAppContext null"); - if (LOG.isDebugEnabled()) LOG.debug("Checking {} for jar exclusion", sci); - + //A ServletContainerInitializer that came from the container's classpath cannot be excluded by an ordering //of WEB-INF/lib jars if (isFromContainerClassPath(context, sci)) + { + if (LOG.isDebugEnabled()) + LOG.debug("!Excluded {} from container classpath", sci); return false; + } //If no ordering, nothing is excluded if (context.getMetaData().getOrdering() == null) + { + if (LOG.isDebugEnabled()) + LOG.debug("!Excluded {} no ordering", sci); return false; - + } List orderedJars = context.getMetaData().getOrderedWebInfJars(); //there is an ordering, but there are no jars resulting from the ordering, everything excluded if (orderedJars.isEmpty()) + { + if (LOG.isDebugEnabled()) + LOG.debug("Excluded {} empty ordering", sci); return true; + } if (sciResource == null) - return false; //not from a jar therefore not from WEB-INF so not excludable + { + //not from a jar therefore not from WEB-INF so not excludable + if (LOG.isDebugEnabled()) + LOG.debug("!Excluded {} not from jar", sci); + return false; + } URI loadingJarURI = sciResource.getURI(); boolean found = false; @@ -790,10 +707,11 @@ public class AnnotationConfiguration extends AbstractConfiguration found = r.getURI().equals(loadingJarURI); } + if (LOG.isDebugEnabled()) + LOG.debug("{}Excluded {} found={}",found?"!":"",sci,found); return !found; } - /** * Test if the ServletContainerIntializer is excluded by the * o.e.j.containerInitializerExclusionPattern @@ -808,7 +726,8 @@ public class AnnotationConfiguration extends AbstractConfiguration return false; //test if name of class matches the regex - if (LOG.isDebugEnabled()) LOG.debug("Checking {} against containerInitializerExclusionPattern",sci.getClass().getName()); + if (LOG.isDebugEnabled()) + LOG.debug("Checking {} against containerInitializerExclusionPattern",sci.getClass().getName()); return _sciExcludePattern.matcher(sci.getClass().getName()).matches(); } @@ -866,17 +785,18 @@ public class AnnotationConfiguration extends AbstractConfiguration //because containerInitializerOrdering omits it for (ServletContainerInitializer sci:_loadedInitializers) { - if (matchesExclusionPattern(sci)) { - if (LOG.isDebugEnabled()) LOG.debug("{} excluded by pattern", sci); + if (LOG.isDebugEnabled()) + LOG.debug("{} excluded by pattern", sci); continue; } Resource sciResource = getJarFor(sci); if (isFromExcludedJar(context, sci, sciResource)) { - if (LOG.isDebugEnabled()) LOG.debug("{} is from excluded jar", sci); + if (LOG.isDebugEnabled()) + LOG.debug("{} is from excluded jar", sci); continue; } @@ -885,7 +805,8 @@ public class AnnotationConfiguration extends AbstractConfiguration if (initializerOrdering != null && (!initializerOrdering.hasWildcard() && initializerOrdering.getIndexOf(name) < 0)) { - if (LOG.isDebugEnabled()) LOG.debug("{} is excluded by ordering", sci); + if (LOG.isDebugEnabled()) + LOG.debug("{} is excluded by ordering", sci); continue; } @@ -912,12 +833,14 @@ public class AnnotationConfiguration extends AbstractConfiguration //no web.xml ordering defined, add SCIs in any order if (context.getMetaData().getOrdering() == null) { - if (LOG.isDebugEnabled()) LOG.debug("No web.xml ordering, ServletContainerInitializers in random order"); + if (LOG.isDebugEnabled()) + LOG.debug("No web.xml ordering, ServletContainerInitializers in random order"); nonExcludedInitializers.addAll(sciResourceMap.keySet()); } else { - if (LOG.isDebugEnabled()) LOG.debug("Ordering ServletContainerInitializers with ordering {}",context.getMetaData().getOrdering()); + if (LOG.isDebugEnabled()) + LOG.debug("Ordering ServletContainerInitializers with ordering {}",context.getMetaData().getOrdering()); for (Map.Entry entry:sciResourceMap.entrySet()) { //add in SCIs from the container classpath @@ -992,7 +915,7 @@ public class AnnotationConfiguration extends AbstractConfiguration //queue it up for scanning if using multithreaded mode if (_parserTasks != null) { - ParserTask task = new ParserTask(parser, handlers, r, _containerClassNameResolver); + ParserTask task = new ParserTask(parser, handlers, r); _parserTasks.add(task); _containerPathStats.increment(); if (LOG.isDebugEnabled()) @@ -1054,7 +977,7 @@ public class AnnotationConfiguration extends AbstractConfiguration if (_parserTasks != null) { - ParserTask task = new ParserTask(parser, handlers,r, _webAppClassNameResolver); + ParserTask task = new ParserTask(parser, handlers,r); _parserTasks.add (task); _webInfLibStats.increment(); if (LOG.isDebugEnabled()) @@ -1087,7 +1010,7 @@ public class AnnotationConfiguration extends AbstractConfiguration { if (_parserTasks != null) { - ParserTask task = new ParserTask(parser, handlers, dir, _webAppClassNameResolver); + ParserTask task = new ParserTask(parser, handlers, dir); _parserTasks.add(task); _webInfClassesStats.increment(); if (LOG.isDebugEnabled()) diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java index 01a1c475d72..5ee998e9e67 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java @@ -544,28 +544,24 @@ public class AnnotationParser * * @param handlers the set of handlers to find class * @param className the class name to parse - * @param resolver the class name resolver to use * @throws Exception if unable to parse */ - public void parse (Set handlers, String className, ClassNameResolver resolver) + public void parse (Set handlers, String className) throws Exception { if (className == null) return; - if (!resolver.isExcluded(className)) + if (!isParsed(className)) { - if (!isParsed(className) || resolver.shouldOverride(className)) + className = className.replace('.', '/')+".class"; + URL resource = Loader.getResource(className); + if (resource!= null) { - className = className.replace('.', '/')+".class"; - URL resource = Loader.getResource(className); - if (resource!= null) + Resource r = Resource.newResource(resource); + try (InputStream is = r.getInputStream()) { - Resource r = Resource.newResource(resource); - try (InputStream is = r.getInputStream()) - { - scanClass(handlers, null, is); - } + scanClass(handlers, null, is); } } } @@ -578,33 +574,30 @@ public class AnnotationParser * * @param handlers the handlers to look for class in * @param clazz the class to look for - * @param resolver the resolver to look up class with * @param visitSuperClasses if true, also visit super classes for parse * @throws Exception if unable to parse class */ - public void parse (Set handlers, Class clazz, ClassNameResolver resolver, boolean visitSuperClasses) + public void parse (Set handlers, Class clazz, boolean visitSuperClasses) throws Exception { Class cz = clazz; while (cz != null) { - if (!resolver.isExcluded(cz.getName())) + if (!isParsed(cz.getName())) { - if (!isParsed(cz.getName()) || resolver.shouldOverride(cz.getName())) + String nameAsResource = cz.getName().replace('.', '/')+".class"; + URL resource = Loader.getResource(nameAsResource); + if (resource!= null) { - String nameAsResource = cz.getName().replace('.', '/')+".class"; - URL resource = Loader.getResource(nameAsResource); - if (resource!= null) + Resource r = Resource.newResource(resource); + try (InputStream is = r.getInputStream()) { - Resource r = Resource.newResource(resource); - try (InputStream is = r.getInputStream()) - { - scanClass(handlers, null, is); - } + scanClass(handlers, null, is); } } } + if (visitSuperClasses) cz = cz.getSuperclass(); else @@ -619,16 +612,15 @@ public class AnnotationParser * * @param handlers the set of handlers to look for class in * @param classNames the class name - * @param resolver the class name resolver * @throws Exception if unable to parse */ - public void parse (Set handlers, String[] classNames, ClassNameResolver resolver) + public void parse (Set handlers, String[] classNames) throws Exception { if (classNames == null) return; - parse(handlers, Arrays.asList(classNames), resolver); + parse(handlers, Arrays.asList(classNames)); } @@ -637,10 +629,9 @@ public class AnnotationParser * * @param handlers the set of handlers to look for class in * @param classNames the class names - * @param resolver the class name resolver * @throws Exception if unable to parse */ - public void parse (Set handlers, List classNames, ClassNameResolver resolver) + public void parse (Set handlers, List classNames) throws Exception { MultiException me = new MultiException(); @@ -649,7 +640,7 @@ public class AnnotationParser { try { - if ((resolver == null) || (!resolver.isExcluded(s) && (!isParsed(s) || resolver.shouldOverride(s)))) + if (!isParsed(s)) { s = s.replace('.', '/')+".class"; URL resource = Loader.getResource(s); @@ -677,10 +668,9 @@ public class AnnotationParser * * @param handlers the set of handlers to look for classes in * @param dir the resource directory to look for classes - * @param resolver the class name resolver * @throws Exception if unable to parse */ - protected void parseDir (Set handlers, Resource dir, ClassNameResolver resolver) + protected void parseDir (Set handlers, Resource dir) throws Exception { // skip dirs whose name start with . (ie hidden) @@ -696,7 +686,7 @@ public class AnnotationParser { Resource res = dir.addPath(files[f]); if (res.isDirectory()) - parseDir(handlers, res, resolver); + parseDir(handlers, res); else { //we've already verified the directories, so just verify the class file name @@ -706,7 +696,7 @@ public class AnnotationParser try { String name = res.getName(); - if ((resolver == null)|| (!resolver.isExcluded(name) && (!isParsed(name) || resolver.shouldOverride(name)))) + if (!isParsed(name)) { Resource r = Resource.newResource(res.getURL()); if (LOG.isDebugEnabled()) {LOG.debug("Scanning class {}", r);}; @@ -741,10 +731,9 @@ public class AnnotationParser * @param loader the classloader for the classes * @param visitParents if true, visit parent classloaders too * @param nullInclusive if true, an empty pattern means all names match, if false, none match - * @param resolver the class name resolver * @throws Exception if unable to parse */ - public void parse (final Set handlers, ClassLoader loader, boolean visitParents, boolean nullInclusive, final ClassNameResolver resolver) + public void parse (final Set handlers, ClassLoader loader, boolean visitParents, boolean nullInclusive) throws Exception { if (loader==null) @@ -762,7 +751,7 @@ public class AnnotationParser { try { - parseJarEntry(handlers, Resource.newResource(jarUri), entry, resolver); + parseJarEntry(handlers, Resource.newResource(jarUri), entry); } catch (Exception e) { @@ -782,10 +771,9 @@ public class AnnotationParser * * @param handlers the handlers to look for classes in * @param uris the uris for the jars - * @param resolver the class name resolver * @throws Exception if unable to parse */ - public void parse (final Set handlers, final URI[] uris, final ClassNameResolver resolver) + public void parse (final Set handlers, final URI[] uris) throws Exception { if (uris==null) @@ -797,7 +785,7 @@ public class AnnotationParser { try { - parse(handlers, uri, resolver); + parse(handlers, uri); } catch (Exception e) { @@ -812,16 +800,15 @@ public class AnnotationParser * * @param handlers the handlers to look for classes in * @param uri the uri for the jar - * @param resolver the class name resolver * @throws Exception if unable to parse */ - public void parse (final Set handlers, URI uri, final ClassNameResolver resolver) + public void parse (final Set handlers, URI uri) throws Exception { if (uri == null) return; - parse (handlers, Resource.newResource(uri), resolver); + parse (handlers, Resource.newResource(uri)); } @@ -830,10 +817,9 @@ public class AnnotationParser * * @param handlers the handlers to look for classes in * @param r the resource to parse - * @param resolver the class name resolver * @throws Exception if unable to parse */ - public void parse (final Set handlers, Resource r, final ClassNameResolver resolver) + public void parse (final Set handlers, Resource r) throws Exception { if (r == null) @@ -841,14 +827,14 @@ public class AnnotationParser if (r.exists() && r.isDirectory()) { - parseDir(handlers, r, resolver); + parseDir(handlers, r); return; } String fullname = r.toString(); if (fullname.endsWith(".jar")) { - parseJar(handlers, r, resolver); + parseJar(handlers, r); return; } @@ -872,10 +858,9 @@ public class AnnotationParser * * @param handlers the handlers to look for classes in * @param jarResource the jar resource to parse - * @param resolver the class name resolver * @throws Exception if unable to parse */ - protected void parseJar (Set handlers, Resource jarResource, final ClassNameResolver resolver) + protected void parseJar (Set handlers, Resource jarResource) throws Exception { if (jarResource == null) @@ -899,7 +884,7 @@ public class AnnotationParser { try { - parseJarEntry(handlers, jarResource, entry, resolver); + parseJarEntry(handlers, jarResource, entry); } catch (Exception e) { @@ -927,10 +912,9 @@ public class AnnotationParser * @param handlers the handlers to look for classes in * @param jar the jar resource to parse * @param entry the entry in the jar resource to parse - * @param resolver the class name resolver * @throws Exception if unable to parse */ - protected void parseJarEntry (Set handlers, Resource jar, JarEntry entry, final ClassNameResolver resolver) + protected void parseJarEntry (Set handlers, Resource jar, JarEntry entry) throws Exception { if (jar == null || entry == null) @@ -947,9 +931,7 @@ public class AnnotationParser { String shortName = name.replace('/', '.').substring(0,name.length()-6); - if ((resolver == null) - || - (!resolver.isExcluded(shortName) && (!isParsed(shortName) || resolver.shouldOverride(shortName)))) + if (!isParsed(shortName)) { Resource clazz = Resource.newResource("jar:"+jar.getURI()+"!/"+name); if (LOG.isDebugEnabled()) {LOG.debug("Scanning class from jar {}", clazz);}; diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationInheritance.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationInheritance.java index 643c3f84077..5a7ed8b56ac 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationInheritance.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationInheritance.java @@ -74,6 +74,12 @@ public class TestAnnotationInheritance return; annotatedMethods.add(info.getClassInfo().getClassName()+"."+info.getMethodName()); } + + @Override + public String toString() + { + return annotatedClassNames.toString()+annotatedMethods+annotatedFields; + } } @After @@ -93,18 +99,7 @@ public class TestAnnotationInheritance SampleHandler handler = new SampleHandler(); AnnotationParser parser = new AnnotationParser(); - parser.parse(Collections.singleton(handler), classNames, new ClassNameResolver () - { - public boolean isExcluded(String name) - { - return false; - } - - public boolean shouldOverride(String name) - { - return false; - } - }); + parser.parse(Collections.singleton(handler), classNames); //check we got 2 class annotations assertEquals(2, handler.annotatedClassNames.size()); @@ -129,18 +124,7 @@ public class TestAnnotationInheritance { SampleHandler handler = new SampleHandler(); AnnotationParser parser = new AnnotationParser(); - parser.parse(Collections.singleton(handler), ClassB.class, new ClassNameResolver () - { - public boolean isExcluded(String name) - { - return false; - } - - public boolean shouldOverride(String name) - { - return false; - } - }, true); + parser.parse(Collections.singleton(handler), ClassB.class, true); //check we got 2 class annotations assertEquals(2, handler.annotatedClassNames.size()); @@ -160,46 +144,6 @@ public class TestAnnotationInheritance assertEquals("org.eclipse.jetty.annotations.ClassA.m", handler.annotatedFields.get(0)); } - @Test - public void testExclusions() throws Exception - { - AnnotationParser parser = new AnnotationParser(); - SampleHandler handler = new SampleHandler(); - parser.parse(Collections.singleton(handler), ClassA.class.getName(), new ClassNameResolver() - { - public boolean isExcluded(String name) - { - return true; - } - - public boolean shouldOverride(String name) - { - return false; - } - }); - assertEquals (0, handler.annotatedClassNames.size()); - assertEquals (0, handler.annotatedFields.size()); - assertEquals (0, handler.annotatedMethods.size()); - - handler.annotatedClassNames.clear(); - handler.annotatedFields.clear(); - handler.annotatedMethods.clear(); - - parser.parse (Collections.singleton(handler), ClassA.class.getName(), new ClassNameResolver() - { - public boolean isExcluded(String name) - { - return false; - } - - public boolean shouldOverride(String name) - { - return false; - } - }); - assertEquals (1, handler.annotatedClassNames.size()); - } - @Test public void testTypeInheritanceHandling() throws Exception { @@ -218,7 +162,7 @@ public class TestAnnotationInheritance classNames.add(InterfaceD.class.getName()); classNames.add(Foo.class.getName()); - parser.parse(Collections.singleton(handler), classNames, null); + parser.parse(Collections.singleton(handler), classNames); assertNotNull(map); assertFalse(map.isEmpty()); diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationParser.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationParser.java index d86283b32a5..002e41bfa5c 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationParser.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationParser.java @@ -111,19 +111,7 @@ public class TestAnnotationParser } //long start = System.currentTimeMillis(); - parser.parse(Collections.singleton(new SampleAnnotationHandler()), classNames,new ClassNameResolver() - { - public boolean isExcluded(String name) - { - return false; - } - - public boolean shouldOverride(String name) - { - return false; - } - - }); + parser.parse(Collections.singleton(new SampleAnnotationHandler()), classNames); //long end = System.currentTimeMillis(); //System.err.println("Time to parse class: " + ((end - start))); @@ -162,7 +150,7 @@ public class TestAnnotationParser } } - parser.parse(Collections.singleton(new MultiAnnotationHandler()), classNames,null); + parser.parse(Collections.singleton(new MultiAnnotationHandler()), classNames); } @Test @@ -171,7 +159,7 @@ public class TestAnnotationParser File badClassesJar = MavenTestingUtils.getTestResourceFile("bad-classes.jar"); AnnotationParser parser = new AnnotationParser(); Set emptySet = Collections.emptySet(); - parser.parse(emptySet, badClassesJar.toURI(),null); + parser.parse(emptySet, badClassesJar.toURI()); // only the valid classes inside bad-classes.jar should be parsed. If any invalid classes are parsed and exception would be thrown here } @@ -196,7 +184,7 @@ public class TestAnnotationParser AnnotationParser parser = new AnnotationParser(); // Parse - parser.parse(Collections.singleton(tracker), basedir.toURI(),null); + parser.parse(Collections.singleton(tracker), basedir.toURI()); // Validate Assert.assertThat("Found Class", tracker.foundClasses, contains(ClassA.class.getName())); diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java index e26f856035c..01ed2f35d3a 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java @@ -73,18 +73,7 @@ public class TestServletAnnotations TestWebServletAnnotationHandler handler = new TestWebServletAnnotationHandler(wac, results); - parser.parse(Collections.singleton(handler), classes, new ClassNameResolver () - { - public boolean isExcluded(String name) - { - return false; - } - - public boolean shouldOverride(String name) - { - return false; - } - }); + parser.parse(Collections.singleton(handler), classes); assertEquals(1, results.size()); diff --git a/jetty-cdi/test-cdi-webapp/pom.xml b/jetty-cdi/test-cdi-webapp/pom.xml index 5fa23abfb82..2ff830a83a5 100644 --- a/jetty-cdi/test-cdi-webapp/pom.xml +++ b/jetty-cdi/test-cdi-webapp/pom.xml @@ -1,4 +1,21 @@ + org.eclipse.jetty.cdi diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/ContinueProtocolHandler.java b/jetty-client/src/main/java/org/eclipse/jetty/client/ContinueProtocolHandler.java index 354852d5f99..4081d37f011 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/ContinueProtocolHandler.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/ContinueProtocolHandler.java @@ -64,6 +64,10 @@ public class ContinueProtocolHandler implements ProtocolHandler return new ContinueListener(); } + protected void onContinue(Request request) + { + } + protected class ContinueListener extends BufferingResponseListener { @Override @@ -72,7 +76,8 @@ public class ContinueProtocolHandler implements ProtocolHandler // Handling of success must be done here and not from onComplete(), // since the onComplete() is not invoked because the request is not completed yet. - HttpConversation conversation = ((HttpRequest)response.getRequest()).getConversation(); + Request request = response.getRequest(); + HttpConversation conversation = ((HttpRequest)request).getConversation(); // Mark the 100 Continue response as handled conversation.setAttribute(ATTRIBUTE, Boolean.TRUE); @@ -88,6 +93,7 @@ public class ContinueProtocolHandler implements ProtocolHandler // All good, continue exchange.resetResponse(); exchange.proceed(null); + onContinue(request); break; } default: @@ -98,7 +104,7 @@ public class ContinueProtocolHandler implements ProtocolHandler List listeners = exchange.getResponseListeners(); HttpContentResponse contentResponse = new HttpContentResponse(response, getContent(), getMediaType(), getEncoding()); notifier.forwardSuccess(listeners, contentResponse); - exchange.proceed(new HttpRequestException("Expectation failed", exchange.getRequest())); + exchange.proceed(new HttpRequestException("Expectation failed", request)); break; } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/GZIPContentDecoder.java b/jetty-client/src/main/java/org/eclipse/jetty/client/GZIPContentDecoder.java index 8bae3b8a993..c469d2e4719 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/GZIPContentDecoder.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/GZIPContentDecoder.java @@ -18,26 +18,13 @@ package org.eclipse.jetty.client; -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.zip.DataFormatException; -import java.util.zip.Inflater; -import java.util.zip.ZipException; - -import org.eclipse.jetty.util.BufferUtil; /** * {@link ContentDecoder} for the "gzip" encoding. + * */ -public class GZIPContentDecoder implements ContentDecoder +public class GZIPContentDecoder extends org.eclipse.jetty.http.GZIPContentDecoder implements ContentDecoder { - private final Inflater inflater = new Inflater(true); - private final byte[] bytes; - private byte[] output; - private State state; - private int size; - private int value; - private byte flags; public GZIPContentDecoder() { @@ -46,285 +33,7 @@ public class GZIPContentDecoder implements ContentDecoder public GZIPContentDecoder(int bufferSize) { - this.bytes = new byte[bufferSize]; - reset(); - } - - /** - * {@inheritDoc} - *

If the decoding did not produce any output, for example because it consumed gzip header - * or trailer bytes, it returns a buffer with zero capacity.

- *

This method never returns null.

- *

The given {@code buffer}'s position will be modified to reflect the bytes consumed during - * the decoding.

- *

The decoding may be finished without consuming the buffer completely if the buffer contains - * gzip bytes plus other bytes (either plain or gzipped).

- */ - @Override - public ByteBuffer decode(ByteBuffer buffer) - { - try - { - while (buffer.hasRemaining()) - { - byte currByte = buffer.get(); - switch (state) - { - case INITIAL: - { - buffer.position(buffer.position() - 1); - state = State.ID; - break; - } - case ID: - { - value += (currByte & 0xFF) << 8 * size; - ++size; - if (size == 2) - { - if (value != 0x8B1F) - throw new ZipException("Invalid gzip bytes"); - state = State.CM; - } - break; - } - case CM: - { - if ((currByte & 0xFF) != 0x08) - throw new ZipException("Invalid gzip compression method"); - state = State.FLG; - break; - } - case FLG: - { - flags = currByte; - state = State.MTIME; - size = 0; - value = 0; - break; - } - case MTIME: - { - // Skip the 4 MTIME bytes - ++size; - if (size == 4) - state = State.XFL; - break; - } - case XFL: - { - // Skip XFL - state = State.OS; - break; - } - case OS: - { - // Skip OS - state = State.FLAGS; - break; - } - case FLAGS: - { - buffer.position(buffer.position() - 1); - if ((flags & 0x04) == 0x04) - { - state = State.EXTRA_LENGTH; - size = 0; - value = 0; - } - else if ((flags & 0x08) == 0x08) - state = State.NAME; - else if ((flags & 0x10) == 0x10) - state = State.COMMENT; - else if ((flags & 0x2) == 0x2) - { - state = State.HCRC; - size = 0; - value = 0; - } - else - state = State.DATA; - break; - } - case EXTRA_LENGTH: - { - value += (currByte & 0xFF) << 8 * size; - ++size; - if (size == 2) - state = State.EXTRA; - break; - } - case EXTRA: - { - // Skip EXTRA bytes - --value; - if (value == 0) - { - // Clear the EXTRA flag and loop on the flags - flags &= ~0x04; - state = State.FLAGS; - } - break; - } - case NAME: - { - // Skip NAME bytes - if (currByte == 0) - { - // Clear the NAME flag and loop on the flags - flags &= ~0x08; - state = State.FLAGS; - } - break; - } - case COMMENT: - { - // Skip COMMENT bytes - if (currByte == 0) - { - // Clear the COMMENT flag and loop on the flags - flags &= ~0x10; - state = State.FLAGS; - } - break; - } - case HCRC: - { - // Skip HCRC - ++size; - if (size == 2) - { - // Clear the HCRC flag and loop on the flags - flags &= ~0x02; - state = State.FLAGS; - } - break; - } - case DATA: - { - buffer.position(buffer.position() - 1); - while (true) - { - int decoded = inflate(bytes); - if (decoded == 0) - { - if (inflater.needsInput()) - { - if (buffer.hasRemaining()) - { - byte[] input = new byte[buffer.remaining()]; - buffer.get(input); - inflater.setInput(input); - } - else - { - if (output != null) - { - ByteBuffer result = ByteBuffer.wrap(output); - output = null; - return result; - } - break; - } - } - else if (inflater.finished()) - { - int remaining = inflater.getRemaining(); - buffer.position(buffer.limit() - remaining); - state = State.CRC; - size = 0; - value = 0; - break; - } - else - { - throw new ZipException("Invalid inflater state"); - } - } - else - { - if (output == null) - { - // Save the inflated bytes and loop to see if we have finished - output = Arrays.copyOf(bytes, decoded); - } - else - { - // Accumulate inflated bytes and loop to see if we have finished - byte[] newOutput = Arrays.copyOf(output, output.length + decoded); - System.arraycopy(bytes, 0, newOutput, output.length, decoded); - output = newOutput; - } - } - } - break; - } - case CRC: - { - value += (currByte & 0xFF) << 8 * size; - ++size; - if (size == 4) - { - // From RFC 1952, compliant decoders need not to verify the CRC - state = State.ISIZE; - size = 0; - value = 0; - } - break; - } - case ISIZE: - { - value += (currByte & 0xFF) << 8 * size; - ++size; - if (size == 4) - { - if (value != inflater.getBytesWritten()) - throw new ZipException("Invalid input size"); - - ByteBuffer result = output == null ? BufferUtil.EMPTY_BUFFER : ByteBuffer.wrap(output); - reset(); - return result; - } - break; - } - default: - throw new ZipException(); - } - } - return BufferUtil.EMPTY_BUFFER; - } - catch (ZipException x) - { - throw new RuntimeException(x); - } - } - - private int inflate(byte[] bytes) throws ZipException - { - try - { - return inflater.inflate(bytes); - } - catch (DataFormatException x) - { - throw new ZipException(x.getMessage()); - } - } - - private void reset() - { - inflater.reset(); - Arrays.fill(bytes, (byte)0); - output = null; - state = State.INITIAL; - size = 0; - value = 0; - flags = 0; - } - - protected boolean isFinished() - { - return state == State.INITIAL; + super(null,bufferSize); } /** @@ -351,9 +60,4 @@ public class GZIPContentDecoder implements ContentDecoder return new GZIPContentDecoder(bufferSize); } } - - private enum State - { - INITIAL, ID, CM, FLG, MTIME, XFL, OS, FLAGS, EXTRA_LENGTH, EXTRA, NAME, COMMENT, HCRC, DATA, CRC, ISIZE - } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java index 6b89c31a6a6..0ce07dc44aa 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java @@ -459,9 +459,10 @@ public class HttpClient extends ContainerLifeCycle HttpHeader.PROXY_AUTHORIZATION == header) continue; + String name = field.getName(); String value = field.getValue(); - if (!newRequest.getHeaders().contains(header, value)) - newRequest.header(field.getName(), value); + if (!newRequest.getHeaders().contains(name, value)) + newRequest.header(name, value); } return newRequest; } @@ -564,18 +565,12 @@ public class HttpClient extends ContainerLifeCycle { context.put(HttpClientTransport.HTTP_CONNECTION_PROMISE_CONTEXT_KEY, new Promise.Wrapper(promise) { - @Override - public void succeeded(Connection result) - { - getPromise().succeeded(result); - } - @Override public void failed(Throwable x) { int nextIndex = index + 1; if (nextIndex == socketAddresses.size()) - getPromise().failed(x); + super.failed(x); else connect(socketAddresses, nextIndex, context); } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java index 58f6fe33288..766bc308cc2 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpConnection.java @@ -35,7 +35,6 @@ import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeaderValue; -import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -68,21 +67,23 @@ public abstract class HttpConnection implements Connection @Override public void send(Request request, Response.CompleteListener listener) { - ArrayList listeners = new ArrayList<>(2); - if (request.getTimeout() > 0) + HttpRequest httpRequest = (HttpRequest)request; + + ArrayList listeners = new ArrayList<>(httpRequest.getResponseListeners()); + if (httpRequest.getTimeout() > 0) { - TimeoutCompleteListener timeoutListener = new TimeoutCompleteListener(request); + TimeoutCompleteListener timeoutListener = new TimeoutCompleteListener(httpRequest); timeoutListener.schedule(getHttpClient().getScheduler()); listeners.add(timeoutListener); } if (listener != null) listeners.add(listener); - HttpExchange exchange = new HttpExchange(getHttpDestination(), (HttpRequest)request, listeners); + HttpExchange exchange = new HttpExchange(getHttpDestination(), httpRequest, listeners); SendFailure result = send(exchange); if (result != null) - request.abort(result.failure); + httpRequest.abort(result.failure); } protected abstract SendFailure send(HttpExchange exchange); diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java index e8e305c0a24..30ce9da2ca5 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java @@ -37,6 +37,7 @@ import org.eclipse.jetty.io.ClientConnectionFactory; import org.eclipse.jetty.io.ssl.SslClientConnectionFactory; import org.eclipse.jetty.util.BlockingArrayQueue; import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.HostPort; import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; @@ -87,7 +88,7 @@ public abstract class HttpDestination extends ContainerLifeCycle implements Dest } this.connectionFactory = connectionFactory; - String host = getHost(); + String host = HostPort.normalizeHost(getHost()); if (!client.isDefaultPort(getScheme(), getPort())) host += ":" + getPort(); hostField = new HttpField(HttpHeader.HOST, host); diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java index 484b7811065..ab65d91a16d 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java @@ -37,6 +37,7 @@ import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.CountingCallback; +import org.eclipse.jetty.util.component.Destroyable; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -470,6 +471,7 @@ public abstract class HttpReceiver */ protected void reset() { + destroyDecoder(decoder); decoder = null; } @@ -482,9 +484,18 @@ public abstract class HttpReceiver */ protected void dispose() { + destroyDecoder(decoder); decoder = null; } + private static void destroyDecoder(ContentDecoder decoder) + { + if (decoder instanceof Destroyable) + { + ((Destroyable)decoder).destroy(); + } + } + public boolean abort(HttpExchange exchange, Throwable failure) { // Update the state to avoid more response processing. diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java index aaff1bad3ba..3a31b87d3fb 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java @@ -693,6 +693,11 @@ public class HttpRequest implements Request client.send(request, responseListeners); } + protected List getResponseListeners() + { + return responseListeners; + } + @Override public boolean abort(Throwable cause) { diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/ProxyConfiguration.java b/jetty-client/src/main/java/org/eclipse/jetty/client/ProxyConfiguration.java index c7970a697f0..56b4bc7f1b2 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/ProxyConfiguration.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/ProxyConfiguration.java @@ -25,6 +25,7 @@ import java.util.List; import java.util.Set; import org.eclipse.jetty.io.ClientConnectionFactory; +import org.eclipse.jetty.util.HostPort; /** * The configuration of the forward proxy to use with {@link org.eclipse.jetty.client.HttpClient}. @@ -58,6 +59,7 @@ public class ProxyConfiguration public static abstract class Proxy { + // TO use IPAddress Map private final Set included = new HashSet<>(); private final Set excluded = new HashSet<>(); private final Origin.Address address; @@ -149,12 +151,10 @@ public class ProxyConfiguration private boolean matches(Origin.Address address, String pattern) { // TODO: add support for CIDR notation like 192.168.0.0/24, see DoSFilter - int colon = pattern.indexOf(':'); - if (colon < 0) - return pattern.equals(address.getHost()); - String host = pattern.substring(0, colon); - String port = pattern.substring(colon + 1); - return host.equals(address.getHost()) && port.equals(String.valueOf(address.getPort())); + HostPort hostPort = new HostPort(pattern); + String host = hostPort.getHost(); + int port = hostPort.getPort(); + return host.equals(address.getHost()) && ( port<=0 || port==address.getPort() ); } /** diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/GZIPContentDecoderTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/GZIPContentDecoderTest.java index 9c1b460d02a..207f6d3e1fe 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/GZIPContentDecoderTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/GZIPContentDecoderTest.java @@ -33,6 +33,7 @@ import org.eclipse.jetty.toolchain.test.TestTracker; import org.junit.Rule; import org.junit.Test; +@Deprecated public class GZIPContentDecoderTest { @Rule diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientExplicitConnectionTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientExplicitConnectionTest.java index 81455cbfda1..7e3f6edd200 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientExplicitConnectionTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientExplicitConnectionTest.java @@ -18,6 +18,7 @@ package org.eclipse.jetty.client; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import org.eclipse.jetty.client.api.Connection; @@ -27,7 +28,7 @@ import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.http.HttpConnectionOverHTTP; import org.eclipse.jetty.client.http.HttpDestinationOverHTTP; import org.eclipse.jetty.client.util.FutureResponseListener; -import org.eclipse.jetty.toolchain.test.annotation.Slow; +import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.util.FuturePromise; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.junit.Assert; @@ -65,7 +66,6 @@ public class HttpClientExplicitConnectionTest extends AbstractHttpClientServerTe } } - @Slow @Test public void testExplicitConnectionIsClosedOnRemoteClose() throws Exception { @@ -98,4 +98,26 @@ public class HttpClientExplicitConnectionTest extends AbstractHttpClientServerTe Assert.assertTrue(connectionPool.getActiveConnections().isEmpty()); Assert.assertTrue(connectionPool.getIdleConnections().isEmpty()); } + + @Test + public void testExplicitConnectionResponseListeners() throws Exception + { + start(new EmptyServerHandler()); + + Destination destination = client.getDestination(scheme, "localhost", connector.getLocalPort()); + FuturePromise futureConnection = new FuturePromise<>(); + destination.newConnection(futureConnection); + Connection connection = futureConnection.get(5, TimeUnit.SECONDS); + CountDownLatch responseLatch = new CountDownLatch(1); + Request request = client.newRequest(destination.getHost(), destination.getPort()) + .scheme(scheme) + .onResponseSuccess(response -> responseLatch.countDown()); + + FutureResponseListener listener = new FutureResponseListener(request); + connection.send(request, listener); + ContentResponse response = listener.get(5, TimeUnit.SECONDS); + + Assert.assertEquals(HttpStatus.OK_200, response.getStatus()); + Assert.assertTrue(responseLatch.await(5, TimeUnit.SECONDS)); + } } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java index bd8f06bd210..f55802177e8 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTest.java @@ -22,7 +22,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpCookie; -import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; @@ -89,6 +88,7 @@ import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.SocketAddressResolver; import org.eclipse.jetty.util.log.StacklessLogging; import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.hamcrest.Matchers; import org.junit.Assert; import org.junit.Assume; import org.junit.Rule; @@ -811,10 +811,23 @@ public class HttpClientTest extends AbstractHttpClientServerTest @Test public void testConnectThrowsUnknownHostException() throws Exception { + String host = "idontexist"; + int port = 80; + + try + { + Socket socket = new Socket(); + socket.connect(new InetSocketAddress(host, port), 1000); + Assume.assumeTrue("Host must not be resolvable", false); + } + catch (IOException ignored) + { + } + start(new EmptyServerHandler()); final CountDownLatch latch = new CountDownLatch(1); - client.newRequest("idontexist", 80) + client.newRequest(host, port) .send(result -> { Assert.assertTrue(result.isFailed()); @@ -828,19 +841,8 @@ public class HttpClientTest extends AbstractHttpClientServerTest @Test public void testConnectHostWithMultipleAddresses() throws Exception { - String host = "google.com"; - try - { - // Likely that the DNS for google.com returns multiple addresses. - Assume.assumeTrue(InetAddress.getAllByName(host).length > 1); - } - catch (Throwable x) - { - Assume.assumeNoException(x); - } + start(new EmptyServerHandler()); - startClient(); - client.setFollowRedirects(false); // Avoid redirects from 80 to 443. client.setSocketAddressResolver(new SocketAddressResolver.Async(client.getExecutor(), client.getScheduler(), client.getConnectTimeout()) { @Override @@ -853,7 +855,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest { // Add as first address an invalid address so that we test // that the connect operation iterates over the addresses. - result.add(0, new InetSocketAddress("idontexist", 80)); + result.add(0, new InetSocketAddress("idontexist", port)); promise.succeeded(result); } @@ -866,9 +868,9 @@ public class HttpClientTest extends AbstractHttpClientServerTest } }); - // Response code may be 200 or 302; - // if no exceptions the test passes. - client.newRequest(host, 80) + // If no exceptions the test passes. + client.newRequest("localhost", connector.getLocalPort()) + .scheme(scheme) .header(HttpHeader.CONNECTION, "close") .send(); } @@ -1232,7 +1234,7 @@ public class HttpClientTest extends AbstractHttpClientServerTest // before closing the connection, so we need to wait before checking // that the connection is closed to avoid races. Thread.sleep(1000); - Assert.assertTrue(((HttpConnectionOverHTTP)connection).isClosed()); + Assert.assertTrue(connection.isClosed()); } } @@ -1535,6 +1537,93 @@ public class HttpClientTest extends AbstractHttpClientServerTest } } + @Test + public void test_IPv6_Host() throws Exception + { + start(new AbstractHandler() + { + @Override + public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + baseRequest.setHandled(true); + response.setContentType("text/plain"); + response.getOutputStream().print(request.getHeader("Host")); + } + }); + + URI uri = URI.create(scheme + "://[::1]:" + connector.getLocalPort() + "/path"); + ContentResponse response = client.newRequest(uri) + .method(HttpMethod.PUT) + .timeout(5, TimeUnit.SECONDS) + .send(); + + Assert.assertNotNull(response); + Assert.assertEquals(200, response.getStatus()); + Assert.assertThat(new String(response.getContent(), StandardCharsets.ISO_8859_1),Matchers.startsWith("[::1]:")); + } + + @Test + public void testCopyRequest() + throws Exception + { + startClient(); + + assertCopyRequest(client.newRequest("http://example.com/some/url") + .method(HttpMethod.HEAD) + .version(HttpVersion.HTTP_2) + .content(new StringContentProvider("some string")) + .timeout(321, TimeUnit.SECONDS) + .idleTimeout(2221, TimeUnit.SECONDS) + .followRedirects(true) + .header(HttpHeader.CONTENT_TYPE, "application/json") + .header("X-Some-Custom-Header", "some-value")); + + assertCopyRequest(client.newRequest("https://example.com") + .method(HttpMethod.POST) + .version(HttpVersion.HTTP_1_0) + .content(new StringContentProvider("some other string")) + .timeout(123231, TimeUnit.SECONDS) + .idleTimeout(232342, TimeUnit.SECONDS) + .followRedirects(false) + .header(HttpHeader.ACCEPT, "application/json") + .header("X-Some-Other-Custom-Header", "some-other-value")); + + assertCopyRequest(client.newRequest("https://example.com") + .header(HttpHeader.ACCEPT, "application/json") + .header(HttpHeader.ACCEPT, "application/xml") + .header("x-same-name", "value1") + .header("x-same-name", "value2")); + + assertCopyRequest(client.newRequest("https://example.com") + .header(HttpHeader.ACCEPT, "application/json") + .header(HttpHeader.CONTENT_TYPE, "application/json")); + + assertCopyRequest(client.newRequest("https://example.com") + .header("Accept", "application/json") + .header("Content-Type", "application/json")); + + assertCopyRequest(client.newRequest("https://example.com") + .header("X-Custom-Header-1", "value1") + .header("X-Custom-Header-2", "value2")); + + assertCopyRequest(client.newRequest("https://example.com") + .header("X-Custom-Header-1", "value") + .header("X-Custom-Header-2", "value")); + } + + private void assertCopyRequest(Request original) + { + Request copy = client.copyRequest((HttpRequest) original, original.getURI()); + Assert.assertEquals(original.getURI(), copy.getURI()); + Assert.assertEquals(original.getMethod(), copy.getMethod()); + Assert.assertEquals(original.getVersion(), copy.getVersion()); + Assert.assertEquals(original.getContent(), copy.getContent()); + Assert.assertEquals(original.getIdleTimeout(), copy.getIdleTimeout()); + Assert.assertEquals(original.getTimeout(), copy.getTimeout()); + Assert.assertEquals(original.isFollowRedirects(), copy.isFollowRedirects()); + Assert.assertEquals(original.getHeaders(), copy.getHeaders()); + } + private void consume(InputStream input, boolean eof) throws IOException { int crlfs = 0; diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ProxyConfigurationTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ProxyConfigurationTest.java index 3b485dfccaa..902d0a960d5 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/ProxyConfigurationTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ProxyConfigurationTest.java @@ -63,4 +63,16 @@ public class ProxyConfigurationTest Assert.assertTrue(proxy.matches(new Origin("http", "1.2.3.4", 0))); Assert.assertFalse(proxy.matches(new Origin("http", "1.2.3.4", 5))); } + + @Test + public void testProxyMatchesWithIncludesAndExcludesIPv6() throws Exception + { + HttpProxy proxy = new HttpProxy("host", 0); + proxy.getIncludedAddresses().add("[1::2:3:4]"); + proxy.getExcludedAddresses().add("[1::2:3:4]:5"); + + Assert.assertFalse(proxy.matches(new Origin("http", "any", 0))); + Assert.assertTrue(proxy.matches(new Origin("http", "[1::2:3:4]", 0))); + Assert.assertFalse(proxy.matches(new Origin("http", "[1::2:3:4]", 5))); + } } diff --git a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationThrowable.java b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationThrowable.java index e32717cabec..a6be363f136 100644 --- a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationThrowable.java +++ b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationThrowable.java @@ -43,4 +43,9 @@ package org.eclipse.jetty.continuation; *

*/ public class ContinuationThrowable extends Error -{} +{ + public ContinuationThrowable() + { + super(null, null, false, false); + } +} diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java index fdebfd668cd..b8237ad1605 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/WebAppProvider.java @@ -273,7 +273,7 @@ public class WebAppProvider extends ScanningAppProvider Resource resource = Resource.newResource(app.getOriginId()); File file = resource.getFile(); if (!resource.exists()) - throw new IllegalStateException("App resouce does not exist "+resource); + throw new IllegalStateException("App resource does not exist "+resource); String context = file.getName(); diff --git a/jetty-distribution/pom.xml b/jetty-distribution/pom.xml index 2b1b1318c22..463922fbe8d 100644 --- a/jetty-distribution/pom.xml +++ b/jetty-distribution/pom.xml @@ -329,7 +329,7 @@ jetty.home=${assembly-directory} jetty.base=${assembly-directory} - --add-to-start=deploy,websocket,ext,resources,jsp,jstl,http + --add-to-start=server,deploy,websocket,ext,resources,jsp,jstl,http diff --git a/jetty-documentation/pom.xml b/jetty-documentation/pom.xml index a0647025505..3ad8e2bfec8 100644 --- a/jetty-documentation/pom.xml +++ b/jetty-documentation/pom.xml @@ -72,6 +72,7 @@ com.agilejava.docbkx docbkx-maven-plugin + 2.0.17 html @@ -81,10 +82,10 @@ css/docbook.css - ${basedir}/src/main/docbkx-stylesheet/html/docbook.xsl + ${project.basedir}/src/main/docbkx-stylesheet/html/docbook.xsl - + @@ -92,16 +93,16 @@ - + - + - + - + diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/statistics-handler.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/statistics-handler.adoc index ab422527b84..38d19bbfc77 100644 --- a/jetty-documentation/src/main/asciidoc/administration/extras/statistics-handler.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/extras/statistics-handler.adoc @@ -72,10 +72,10 @@ This example comes from within `jetty-http.xml`. 30000 - + - + diff --git a/jetty-documentation/src/main/asciidoc/administration/fastcgi/configuring-fastcgi.adoc b/jetty-documentation/src/main/asciidoc/administration/fastcgi/configuring-fastcgi.adoc index 4a9d0c5c1b1..17867dd108c 100644 --- a/jetty-documentation/src/main/asciidoc/administration/fastcgi/configuring-fastcgi.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/fastcgi/configuring-fastcgi.adoc @@ -33,7 +33,7 @@ The fourth step is to create a Jetty base directory (see xref:startup-base-and-h .... $ mkdir -p /usr/jetty/wordpress $ cd /usr/jetty/wordpress -$ java -jar $JETTY_HOME/start.jar --add-to-startd=fcgi,http,deploy +$ java -jar $JETTY_HOME/start.jar --add-to-start=fcgi,http,deploy .... Therefore `$JETTY_BASE=/usr/jetty/wordpress`. @@ -152,7 +152,7 @@ Enabling the `http2` is easy; in additions to the modules you have enabled above [source, screen, subs="{sub-order}"] .... $ cd $JETTY_BASE -$ java -jar $JETTY_HOME/start.jar --add-to-startd=http2 +$ java -jar $JETTY_HOME/start.jar --add-to-start=http2 .... The command above adds the `http2` module (and its dependencies) to the existing modules and uses the default Jetty keystore to provide the key material required by TLS. diff --git a/jetty-documentation/src/main/asciidoc/administration/http2/configuring-http2.adoc b/jetty-documentation/src/main/asciidoc/administration/http2/configuring-http2.adoc index 01870b13ef6..f23c99692ae 100644 --- a/jetty-documentation/src/main/asciidoc/administration/http2/configuring-http2.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/http2/configuring-http2.adoc @@ -65,5 +65,5 @@ Currently there are very few HTTP/2 configuration properties and the default val |======================================================================= |Property |Description |jetty.http2.maxConcurrentStreams |The maximum number of concurrently open streams allowed on a single HTTP/2 connection (default 1024). Larger values increase parallelism but cost a memory commitment. -|jetty.http2.initialStreamSendWindow |The initial flow control window size for a new stream (default 65535). Larger values may allow greater throughput but also risk head of line blocking if TCP/IP flow control is triggered. +|jetty.http2.initialStreamRecvWindow |The initial receive flow control window size for a new stream (default 65535). Larger values may allow greater throughput but also risk head of line blocking if TCP/IP flow control is triggered. |======================================================================= diff --git a/jetty-documentation/src/main/asciidoc/administration/http2/enabling-http2.adoc b/jetty-documentation/src/main/asciidoc/administration/http2/enabling-http2.adoc index 12cd000d4d4..5ca944b9b6b 100644 --- a/jetty-documentation/src/main/asciidoc/administration/http2/enabling-http2.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/http2/enabling-http2.adoc @@ -25,7 +25,7 @@ A demo Jetty base that supports HTTP/1, HTTPS/1 and deployment from a webapps di $ JETTY_BASE=http2-demo $ mkdir $JETTY_BASE $ cd $JETTY_BASE -$ java -jar $JETTY_HOME/start.jar --add-to-startd=http,https,deploy +$ java -jar $JETTY_HOME/start.jar --add-to-start=http,https,deploy .... The commands above create a `$JETTY_BASE` directory called `http2-demo`, and initializes the `http,` `https` and `deploy` modules (and their dependencies) to run a typical Jetty Server on port 8080 (for HTTP/1) and 8443 (for HTTPS/1). @@ -35,7 +35,7 @@ To add HTTP/2 to this demo base, it is just a matter of enabling the `http2` mod [source, screen, subs="{sub-order}"] .... -$ java -jar $JETTY_HOME/start.jar --add-to-startd=http2 +$ java -jar $JETTY_HOME/start.jar --add-to-start=http2 .... This command does not create a new connector, but instead simply adds the HTTP/2 protocol to the existing HTTPS/1 connector, so that it now supports both protocols on port 8443. @@ -61,7 +61,7 @@ HTTP/2 can be enabled on the plain text connector and the server restarted with [source,screen] .... -$ java -jar $JETTY_HOME/start.jar --add-to-startd=http2c +$ java -jar $JETTY_HOME/start.jar --add-to-start=http2c $ java -jar $JETTY_HOME/start.jar .. 2015-06-17 14:16:12.549:INFO:oejs.ServerConnector:main: Started ServerConnector@6f32cd1e{HTTP/1.1,[http/1.1, h2c, h2c-17]}{0.0.0.0:8080} diff --git a/jetty-documentation/src/main/asciidoc/administration/jndi/quick-jndi-setup.adoc b/jetty-documentation/src/main/asciidoc/administration/jndi/quick-jndi-setup.adoc index 0152e02f5eb..3fc405faa81 100644 --- a/jetty-documentation/src/main/asciidoc/administration/jndi/quick-jndi-setup.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/jndi/quick-jndi-setup.adoc @@ -21,13 +21,12 @@ If you are using the standard distribution of Jetty, you must enable the _JNDI_ As the _plus_ module depends on the _JNDI_ module, you only need to enable the _plus_ module to enable both. Assuming you have Jetty installed in `/opt/jetty`, and you have made a link:#startup-base-and-home[jetty base] in `/opt/jetty/my-base`, do: -[source,bash] ----- +[source, screen, subs="{sub-order}"] +.... cd /opt/jetty cd my-base -java -jar $JETTY_HOME/start.jar --add-to-startd=plus - ----- +java -jar $JETTY_HOME/start.jar --add-to-start=plus +.... You can now start Jetty and use JNDI within your webapps. See link:#using-jndi[Using JNDI] for information on how to add entries to the JNDI environment that Jetty can look up within webapps. @@ -36,10 +35,9 @@ If you have extra jars associated with your JNDI resources, for example a databa You will then need to enable the _ext_ module to ensure the jars in the `ext/` directory are on the classpath. Assuming you have Jetty installed in `/opt/jetty`, and you have made a link:#startup-base-and-home[jetty base] in `/opt/jetty/my-base`, do: -[source,bash] ----- +[source, screen, subs="{sub-order}"] +.... cd /opt/jetty cd my-base -java -jar $JETTY_HOME/start.jar --add-to-startd=ext - ----- +java -jar $JETTY_HOME/start.jar --add-to-start=ext +.... diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/chapter.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/chapter.adoc index cfa8510f709..15d6528cd1c 100644 --- a/jetty-documentation/src/main/asciidoc/administration/logging/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/logging/chapter.adoc @@ -22,10 +22,12 @@ This chapter discusses various options for configuring logging. include::configuring-jetty-logging.adoc[] include::default-logging-with-stderrlog.adoc[] include::configuring-jetty-request-logs.adoc[] -include::example-apache-log4j.adoc[] -include::example-java-util-logging.adoc[] -include::example-java-util-logging-native.adoc[] -include::example-logback.adoc[] -include::example-slf4j-multiple-loggers.adoc[] +include::configuring-logging-modules.adoc[] +// TODO - Remove following +// include::example-apache-log4j.adoc[] +// include::example-java-util-logging.adoc[] +// include::example-java-util-logging-native.adoc[] +// include::example-logback.adoc[] +// include::example-slf4j-multiple-loggers.adoc[] include::example-logback-centralized-logging.adoc[] include::dump-tool.adoc[] diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/configuring-jetty-logging.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/configuring-jetty-logging.adoc index 4caddb3d035..7d405a20492 100644 --- a/jetty-documentation/src/main/asciidoc/administration/logging/configuring-jetty-logging.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/logging/configuring-jetty-logging.adoc @@ -51,7 +51,7 @@ Configure the Jetty logging layer via the `org.eclipse.jetty.util.log.Log` class * If no logger implementation is specified, default to `org.eclipse.jetty.util.log.StdErrLog`. ____ [NOTE] -You can create your own custom logging by providing an implementation of the link:{JDURL}org/eclipse/jetty/util/log/Logger.html[Jetty Logger API]. +You can create your own custom logging by providing an implementation of the link:{JDURL}org/eclipse/jetty/util/log/Logger.html[Jetty Logger API]. For an example of a custom logger, see link:{GITBROWSEURL}/jetty-util/src/main/java/org/eclipse/jetty/util/log/JavaUtilLog.java[JavaUtilLog.java]. ____ @@ -60,7 +60,7 @@ ____ By default, the internal Jetty Logging discovery mechanism will load logging specific properties from a classpath resource called `jetty-logging.properties` and then initialize the Logging from a combination of properties found in that file, along with any System Properties. A typical jetty-logging.properties file will include at least the declaration of which logging implementation you want to use by defining a value for the `org.eclipse.jetty.util.log.class` property. - + Examples for various logging frameworks can be found later in this documentation. * Default Logging with link:#default-logging-with-stderrlog[Jetty's StdErrLog] diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/configuring-jetty-request-logs.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/configuring-jetty-request-logs.adoc index 8fa90e1aeb3..d2fc4721e8e 100644 --- a/jetty-documentation/src/main/asciidoc/administration/logging/configuring-jetty-request-logs.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/logging/configuring-jetty-request-logs.adoc @@ -49,15 +49,14 @@ To enable the Request Log module for the entire server via the Jetty distributio [source, screen, subs="{sub-order}"] ---- -$ java -jar ../start.jar --add-to-startd=requestlog +$ java -jar ../start.jar --add-to-start=requestlog INFO: requestlog initialised in ${jetty.base}/start.d/requestlog.ini MKDIR: ${jetty.base}/logs INFO: Base directory was modified ---- -The above command will add a new `requestlog.ini` file to your `{$jetty.base}/start.d` directory. -If you used `--add-to-start` it will append the configuration options for the module to the `start.ini` file located in your `{$jetty.base}` directory. +The above command will add a new `requestlog.ini` file to your link:#start-vs-startd[`{$jetty.base}/start.d` directory]. The equivalent code for embedded usages of Jetty is: diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/configuring-logging-modules.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/configuring-logging-modules.adoc new file mode 100644 index 00000000000..39db1c792d1 --- /dev/null +++ b/jetty-documentation/src/main/asciidoc/administration/logging/configuring-logging-modules.adoc @@ -0,0 +1,425 @@ +// ======================================================================== +// Copyright (c) 1995-2016 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. +// ======================================================================== + +[[configuring-logging-modules]] +=== Jetty Logging Integrations (Slf4j, Log4j, Logback, JCL, JUL) + +Jetty provides support for several logging frameworks including SLF4J, Java Commons Logging (jcl), Java Util Logging (jul), Log4j (including version 2), and Logback. +This page includes examples of how to enable the associated modules for these different frameworks. +Enabling these frameworks in the Jetty distribution is as easy as activating any other module, by adding `--add-to-start=` to the start command for your server, such as: + +[source, screen, subs="{sub-order}"] +.... +$ java -jar ../start.jar --add-to-start=logging-jetty +INFO : logging-jetty initialized in ${jetty.base}/start.d/logging-jetty.ini +INFO : resources transitive +INFO : Base directory was modified +.... + +As noted above, Jetty supports a wide array of logging technologies. +The release of Jetty 9.4 made the implementation of these frameworks easier by providing logging modules that contain all the dependencies needed to implement a specific technology. +If a particular logging framework requires additional jar files, Jetty will automatically download these as part of enabling the associated module. +You can view a list of all the Jetty modules by running `java -jar /start.jar --list-modules`. + +[[example-logging-slf4j]] +==== Logging with SLF4J + +===== jetty-slf4j + +Jetty uses the Slf4j api as a bridge to provide logging information to additional frameworks such as Log4j or Logback. +It can also be used itself to provide logging in conjunction with standard Jetty logging. +To enable the Slf4j framework, you need to activate the `logging-slf4j` module. + +[source, screen, subs="{sub-order}"] +.... +$ java -jar ../start.jar --add-to-start=logging-slf4j + +ALERT: There are enabled module(s) with licenses. +The following 1 module(s): + + contains software not provided by the Eclipse Foundation! + + contains software not covered by the Eclipse Public License! + + has not been audited for compliance with its license + + Module: slf4j-api + + SLF4J is distributed under the MIT License. + + Copyright (c) 2004-2013 QOS.ch + + All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining + + a copy of this software and associated documentation files (the + + "Software"), to deal in the Software without restriction, including + + without limitation the rights to use, copy, modify, merge, publish, + + distribute, sublicense, and/or sell copies of the Software, and to + + permit persons to whom the Software is furnished to do so, subject to + + the following conditions: + + The above copyright notice and this permission notice shall be + + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Proceed (y/N)? y +INFO : slf4j-api transitive, ini template available with --add-to-start=slf4j-api +INFO : logging-slf4j initialized in ${jetty.base}/start.d/logging-slf4j.ini +INFO : slf4j-impl transitive +DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar +DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-simple/1.7.21/slf4j-simple-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-simple-1.7.21.jar +INFO : Base directory was modified + +$ tree +. +├── lib +│   └── slf4j +│   ├── slf4j-api-1.7.21.jar +│   └── slf4j-simple-1.7.21.jar +└── start.d + ├── logging-slf4j.ini +.... + + +[[example-logging-log4j]] +==== Logging with Log4j and log4j2 + +It is possible to have the Jetty Server logging configured so that Log4j or Log4j2 controls the output of logging events produced by Jetty. +This is accomplished by configuring Jetty for logging to http://logging.apache.org/log4j/[Apache Log4j] via http://slf4j.org/manual.html[Slf4j] and the http://slf4j.org/manual.html#swapping[Slf4j binding layer for Log4j]. +Implementation of Log4j can be done by enabling the `logging-log4j` module. + +[source, screen, subs="{sub-order}"] +.... +$ java -jar ../start.jar --add-to-start=logging-log4j + +ALERT: There are enabled module(s) with licenses. +The following 2 module(s): + + contains software not provided by the Eclipse Foundation! + + contains software not covered by the Eclipse Public License! + + has not been audited for compliance with its license + + Module: log4j-impl + + Log4j is released under the Apache 2.0 license. + + http://www.apache.org/licenses/LICENSE-2.0.html + + Module: slf4j-api + + SLF4J is distributed under the MIT License. + + Copyright (c) 2004-2013 QOS.ch + + All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining + + a copy of this software and associated documentation files (the + + "Software"), to deal in the Software without restriction, including + + without limitation the rights to use, copy, modify, merge, publish, + + distribute, sublicense, and/or sell copies of the Software, and to + + permit persons to whom the Software is furnished to do so, subject to + + the following conditions: + + The above copyright notice and this permission notice shall be + + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Proceed (y/N)? y +INFO : slf4j-api transitive, ini template available with --add-to-start=slf4j-api +INFO : log4j-impl transitive, ini template available with --add-to-start=log4j-impl +INFO : resources transitive +INFO : slf4j-log4j transitive +INFO : logging-log4j initialized in ${jetty.base}/start.d/logging-log4j.ini +DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar +DOWNLOAD: http://central.maven.org/maven2/log4j/log4j/1.2.17/log4j-1.2.17.jar to ${jetty.base}/lib/log4j/log4j-1.2.17.jar +DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-log4j12/1.7.21/slf4j-log4j12-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-log4j12-1.7.21.jar +INFO : Base directory was modified + +$ tree +. +├── lib +│   ├── log4j +│   │   └── log4j-1.2.17.jar +│   └── slf4j +│   ├── slf4j-api-1.7.21.jar +│   └── slf4j-log4j12-1.7.21.jar +├── resources +│   └── log4j.properties +└── start.d + ├── logging-log4j.ini +.... + +Or, to enable Log4j2, simply enable the `logging-log4j2` module. + +[source, screen, subs="{sub-order}"] +.... +$ java -jar ../start.jar --add-to-start=logging-log4j2 + +ALERT: There are enabled module(s) with licenses. +The following 2 module(s): + + contains software not provided by the Eclipse Foundation! + + contains software not covered by the Eclipse Public License! + + has not been audited for compliance with its license + + Module: log4j2-api + + Log4j is released under the Apache 2.0 license. + + http://www.apache.org/licenses/LICENSE-2.0.html + + Module: slf4j-api + + SLF4J is distributed under the MIT License. + + Copyright (c) 2004-2013 QOS.ch + + All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining + + a copy of this software and associated documentation files (the + + "Software"), to deal in the Software without restriction, including + + without limitation the rights to use, copy, modify, merge, publish, + + distribute, sublicense, and/or sell copies of the Software, and to + + permit persons to whom the Software is furnished to do so, subject to + + the following conditions: + + The above copyright notice and this permission notice shall be + + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Proceed (y/N)? y +INFO : slf4j-api transitive, ini template available with --add-to-start=slf4j-api +INFO : logging-log4j2 initialized in ${jetty.base}/start.d/logging-log4j2.ini +INFO : log4j2-api transitive, ini template available with --add-to-start=log4j2-api +INFO : resources transitive +INFO : slf4j-log4j2 transitive +INFO : log4j2-impl transitive +DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar +DOWNLOAD: http://central.maven.org/maven2/org/apache/logging/log4j/log4j-api/2.6.1/log4j-api-2.6.1.jar to ${jetty.base}/lib/log4j/log4j-api-2.6.1.jar +MKDIR: ${jetty.base}/resources +DOWNLOAD: http://central.maven.org/maven2/org/apache/logging/log4j/log4j-slf4j-impl/2.6.1/log4j-slf4j-impl-2.6.1.jar to ${jetty.base}/lib/log4j/log4j-slf4j-impl-2.6.1.jar +DOWNLOAD: http://central.maven.org/maven2/org/apache/logging/log4j/log4j-core/2.6.1/log4j-core-2.6.1.jar to ${jetty.base}/lib/log4j/log4j-core-2.6.1.jar +INFO : Base directory was modified + +$ tree +. +├── lib +│   ├── log4j +│   │   ├── log4j-api-2.6.1.jar +│   │   ├── log4j-core-2.6.1.jar +│   │   └── log4j-slf4j-impl-2.6.1.jar +│   └── slf4j +│   └── slf4j-api-1.7.21.jar +├── resources +│   └── log4j2.xml +└── start.d + ├── logging-log4j2.ini +.... + +[[example-logging-logback]] +==== Logging with Logback + +It is possible to have the Jetty Server logging configured so that Logback controls the output of logging events produced by Jetty. +This is accomplished by configuring Jetty for logging to `Logback`, which uses http://slf4j.org/manual.html[Slf4j] and the http://logback.qos.ch/[Logback Implementation for Slf4j]. + +To set up Jetty logging via Logback, enable the `logging-logback` module. + +[source, screen, subs="{sub-order}"] +.... +$ java -jar ../start.jar --add-to-start=logging-logback + +ALERT: There are enabled module(s) with licenses. +The following 2 module(s): + + contains software not provided by the Eclipse Foundation! + + contains software not covered by the Eclipse Public License! + + has not been audited for compliance with its license + + Module: logback-impl + + Logback: the reliable, generic, fast and flexible logging framework. + + Copyright (C) 1999-2012, QOS.ch. All rights reserved. + + This program and the accompanying materials are dual-licensed under + + either: + + the terms of the Eclipse Public License v1.0 + + as published by the Eclipse Foundation: + + http://www.eclipse.org/legal/epl-v10.html + + or (per the licensee's choosing) under + + the terms of the GNU Lesser General Public License version 2.1 + + as published by the Free Software Foundation: + + http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html + + Module: slf4j-api + + SLF4J is distributed under the MIT License. + + Copyright (c) 2004-2013 QOS.ch + + All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining + + a copy of this software and associated documentation files (the + + "Software"), to deal in the Software without restriction, including + + without limitation the rights to use, copy, modify, merge, publish, + + distribute, sublicense, and/or sell copies of the Software, and to + + permit persons to whom the Software is furnished to do so, subject to + + the following conditions: + + The above copyright notice and this permission notice shall be + + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Proceed (y/N)? y +INFO : slf4j-api transitive, ini template available with --add-to-start=slf4j-api +INFO : logback-impl transitive, ini template available with --add-to-start=logback-impl +INFO : slf4j-logback transitive +INFO : logging-logback initialized in ${jetty.base}/start.d/logging-logback.ini +INFO : resources transitive +DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar +DOWNLOAD: http://central.maven.org/maven2/ch/qos/logback/logback-core/1.1.7/logback-core-1.1.7.jar to ${jetty.base}/lib/logback/logback-core-1.1.7.jar +DOWNLOAD: http://central.maven.org/maven2/ch/qos/logback/logback-classic/1.1.7/logback-classic-1.1.7.jar to ${jetty.base}/lib/logback/logback-classic-1.1.7.jar +INFO : Base directory was modified + +$ tree +. +├── lib +│   ├── logback +│   │   ├── logback-classic-1.1.7.jar +│   │   └── logback-core-1.1.7.jar +│   └── slf4j +│   └── slf4j-api-1.7.21.jar +├── resources +│   └── logback.xml +└── start.d + ├── logging-logback.ini +.... + +At this point Jetty is configured so that the Jetty server itself will log using Logback, using the Logback configuration found in `{$jetty.base}/resources/logback.xml`. + +==== Logging with Java Util Logging + +[[example-logging-java-util-logging]] +===== Java Util Logging with SLF4J +It is possible to have the Jetty Server logging configured so that `java.util.logging` controls the output of logging events produced by Jetty. + +This example demonstrates how to configuring Jetty for logging to `java.util.logging` via http://slf4j.org/manual.html[Slf4j] and the http://slf4j.org/manual.html#swapping[Slf4j binding layer for java.util.logging]. +If you want to use the built-in native `java.util.logging` implementation, see link:#example-logging-java-util-logging-native[Native Java Util Logging]. + +[source, screen, subs="{sub-order}"] +.... +$ java -jar ../start.jar --add-to-start=logging-jul + +ALERT: There are enabled module(s) with licenses. +The following 1 module(s): + + contains software not provided by the Eclipse Foundation! + + contains software not covered by the Eclipse Public License! + + has not been audited for compliance with its license + + Module: slf4j-api + + SLF4J is distributed under the MIT License. + + Copyright (c) 2004-2013 QOS.ch + + All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining + + a copy of this software and associated documentation files (the + + "Software"), to deal in the Software without restriction, including + + without limitation the rights to use, copy, modify, merge, publish, + + distribute, sublicense, and/or sell copies of the Software, and to + + permit persons to whom the Software is furnished to do so, subject to + + the following conditions: + + The above copyright notice and this permission notice shall be + + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Proceed (y/N)? y +INFO : slf4j-api transitive, ini template available with --add-to-start=slf4j-api +INFO : slf4j-jul transitive +INFO : logging-jul initialized in ${jetty.base}/start.d/logging-jul.ini +DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar +DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-jdk14/1.7.21/slf4j-jdk14-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-jdk14-1.7.21.jar +INFO : Base directory was modified + +$ tree +. +├── lib +│   └── slf4j +│   ├── slf4j-api-1.7.21.jar +│   └── slf4j-jdk14-1.7.21.jar +└── start.d + ├── logging-jul.ini +.... + +==== Logging with Java Commons Logging +Jetty provides support of the Java Commons Logging (jcl) through the `logging-jcl` module, using Slf4j as a bridge. +This can be enabled as shown below: + +[source, screen, subs="{sub-order}"] +.... +$ java -jar ../start.jar --add-to-start=logging-jcl + +ALERT: There are enabled module(s) with licenses. +The following 2 module(s): + + contains software not provided by the Eclipse Foundation! + + contains software not covered by the Eclipse Public License! + + has not been audited for compliance with its license + + Module: jcl-impl + + Log4j is released under the Apache 2.0 license. + + http://www.apache.org/licenses/LICENSE-2.0.html + + Module: slf4j-api + + SLF4J is distributed under the MIT License. + + Copyright (c) 2004-2013 QOS.ch + + All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining + + a copy of this software and associated documentation files (the + + "Software"), to deal in the Software without restriction, including + + without limitation the rights to use, copy, modify, merge, publish, + + distribute, sublicense, and/or sell copies of the Software, and to + + permit persons to whom the Software is furnished to do so, subject to + + the following conditions: + + The above copyright notice and this permission notice shall be + + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Proceed (y/N)? y +INFO : slf4j-api transitive, ini template available with --add-to-start=slf4j-api +INFO : jcl-impl transitive, ini template available with --add-to-start=jcl-impl +INFO : slf4j-jcl transitive +INFO : logging-jcl initialized in ${jetty.base}/start.d/logging-jcl.ini +DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar +DOWNLOAD: http://central.maven.org/maven2/commons-logging/commons-logging/1.1.3/commons-logging-1.1.3.jar to ${jetty.base}/lib/jcl/commons-logging-1.1.3.jar +DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-jcl/1.7.21/slf4j-jcl-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-jcl-1.7.21.jar +INFO : Base directory was modified + +$ tree +. +├── lib +│   ├── jcl +│   │   └── commons-logging-1.1.3.jar +│   └── slf4j +│   ├── slf4j-api-1.7.21.jar +│   └── slf4j-jcl-1.7.21.jar +└── start.d + ├── logging-jcl.ini +.... diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/default-logging-with-stderrlog.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/default-logging-with-stderrlog.adoc index 4c593d6ac33..1d41d63c1f4 100644 --- a/jetty-documentation/src/main/asciidoc/administration/logging/default-logging-with-stderrlog.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/logging/default-logging-with-stderrlog.adoc @@ -20,7 +20,7 @@ [[stderrlog-configuration]] ==== StdErrLog Configuration -If you do nothing to configure a separate logging framework, Jetty will default to using an internal `org.eclipse.jetty.util.log.StdErrLog` implementation. +If you do nothing to configure a separate logging framework, Jetty will default to using an internal `org.eclipse.jetty.util.log.StdErrLog` implementation. This will output all logging events to STDERR (aka `System.err`). Simply use Jetty and `StdErrLog` based logging is output. @@ -29,62 +29,55 @@ Included in the Jetty distribution is a logging module that is capable of perfor To enable on this feature via the command line: -[source,bash] ----- -[my-base]$ java -jar /opt/jetty/start.jar --module=logging ----- +[source, screen, subs="{sub-order}"] +.... +[my-base]$ java -jar /opt/jetty/start.jar --add-to-start=logging-jetty +.... -You can also include the `--module=logging` command in your `${jetty.base}/start.ini`. - -[source,bash] ----- -[my-base]$ java -jar /opt/jetty/start.jar --add-to-start=logging ----- - -The default configuration for logging output will create a file `${jetty.logs}/yyyy_mm_dd.stderrout.log` which allows configuration of the output directory by setting the `jetty.logs` property. +The default configuration for logging output will create a file `${jetty.base}/logs/yyyy_mm_dd.stderrout.log` which allows configuration of the output directory by setting the `jetty.logs` property. For more advanced logging configurations, please consider use of a separate logging library. -The recommended way to configure `StdErrLog` is to create a `${jetty.home}/resources/jetty-logging.properties` file, specify the log implementation to `StdErrLog` and then setup logging levels. +The recommended way to configure `StdErrLog` is to create a `${jetty.base}/resources/jetty-logging.properties` file, specify the log implementation to `StdErrLog` and then setup logging levels. -[source,properties] ----- +[source, properties, subs="{sub-order}"] +.... # Configure Jetty for StdErrLog Logging org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StrErrLog # Overall Logging Level is INFO org.eclipse.jetty.LEVEL=INFO # Detail Logging for WebSocket org.eclipse.jetty.websocket.LEVEL=DEBUG ----- +.... There are a number of properties that can be defined in the configuration that will affect the behavior of `StdErrLog`. `.LEVEL=`:: - Sets the logging level for all loggers within the `name` specified to the level, which can be (in increasing order of restriction) `ALL`, `DEBUG`, `INFO`, `WARN`, `OFF`. + Sets the logging level for all loggers within the `name` specified to the level, which can be (in increasing order of restriction) `ALL`, `DEBUG`, `INFO`, `WARN`, `OFF`. The name (or hierarchy) can be a specific fully qualified class or a package namespace. - For example, `org.eclipse.jetty.http.LEVEL=DEBUG` is a package namespace approach to turn all loggers in the Jetty HTTP package to DEBUG level, and `org.eclipse.jetty.io.ChanelEndPoint.LEVEL=ALL` turns on all logging events for the specific class, including `DEBUG`, `INFO`, `WARN` (and even special internally ignored exception classes). + For example, `org.eclipse.jetty.http.LEVEL=DEBUG` is a package namespace approach to turn all loggers in the Jetty HTTP package to DEBUG level, and `org.eclipse.jetty.io.ChanelEndPoint.LEVEL=ALL` turns on all logging events for the specific class, including `DEBUG`, `INFO`, `WARN` (and even special internally ignored exception classes). If more than one system property specifies a logging level, the most specific one applies. `.SOURCE=`:: - Named Logger specific, attempts to print the Java source file name and line number from where the logging event originated. - Name must be a fully qualified class name (this configurable does not support package name hierarchy). - Default is false. + Named Logger specific, attempts to print the Java source file name and line number from where the logging event originated. + Name must be a fully qualified class name (this configurable does not support package name hierarchy). + Default is false. Be aware that this is a slow operation and has an impact on performance. `.STACKS=`:: - Named Logger specific, controls the display of stacktraces. + Named Logger specific, controls the display of stacktraces. Name must be a fully qualified class name (this configurable does not support package name hierarchy). Default is true. `org.eclipse.jetty.util.log.stderr.SOURCE=`:: - Special Global Configuration. - Attempts to print the Java source file name and line number from where the logging event originated. + Special Global Configuration. + Attempts to print the Java source file name and line number from where the logging event originated. Default is false. `org.eclipse.jetty.util.log.stderr.LONG=`:: - Special Global Configuration. - When true, outputs logging events to `STDERR` using long form, fully qualified class names. + Special Global Configuration. + When true, outputs logging events to `STDERR` using long form, fully qualified class names. When false, uses abbreviated package names. Default is false. - + ++ * Example when set to false: - + ++ [source, screen, subs="{sub-order}"] .... 2014-06-03 14:36:16.013:INFO:oejs.Server:main: jetty-9.2.0.v20140526 @@ -93,9 +86,9 @@ There are a number of properties that can be defined in the configuration that w 2014-06-03 14:36:17.880:INFO:oejs.ServerConnector:main: Started ServerConnector@34f2d11a{HTTP/1.1}{0.0.0.0:8080} 2014-06-03 14:36:17.888:INFO:oejs.Server:main: Started @257ms .... - + ++ * Example when set to true: - + ++ [source, screen, subs="{sub-order}"] .... 2014-06-03 14:38:19.019:INFO:org.eclipse.jetty.server.Server:main: jetty-9.2.0.v20140526 @@ -108,7 +101,7 @@ There are a number of properties that can be defined in the configuration that w [[deprecated-parameters]] ==== Deprecated Parameters -These parameters existed in prior versions of Jetty, and are no longer supported. +These parameters existed in prior versions of Jetty, and are no longer supported. They are included here for historical (and search engine) reasons. `org.eclipse.jetty.util.log.DEBUG`:: diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/example-apache-log4j.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/example-apache-log4j.adoc index 663ca27c8f4..92f72e8602b 100644 --- a/jetty-documentation/src/main/asciidoc/administration/logging/example-apache-log4j.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/logging/example-apache-log4j.adoc @@ -14,10 +14,9 @@ // You may elect to redistribute this code under either of these licenses. // ======================================================================== -[[example-logging-log4j]] === Example: Logging with Apache Log4j -It is possible to have the Jetty Server logging configured so that Log4j controls the output of logging events produced by Jetty. +It is possible to have the Jetty Server logging configured so that Log4j controls the output of logging events produced by Jetty. This is accomplished by configuring Jetty for logging to http://logging.apache.org/log4j/[Apache Log4j] via http://slf4j.org/manual.html[Slf4j] and the http://slf4j.org/manual.html#swapping[Slf4j binding layer for Log4j]. A convenient replacement `logging` module has been created to bootstrap your `${jetty.base}` directory for logging with log4j. diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/example-java-util-logging-native.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/example-java-util-logging-native.adoc index 9e29fbdbbfe..08e26d6518e 100644 --- a/jetty-documentation/src/main/asciidoc/administration/logging/example-java-util-logging-native.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/logging/example-java-util-logging-native.adoc @@ -14,7 +14,6 @@ // You may elect to redistribute this code under either of these licenses. // ======================================================================== -[[example-logging-java-util-logging-native]] === Example: Logging with Java's java.util.logging via JavaUtilLog It is possible to have the Jetty Server logging configured so that @@ -26,7 +25,7 @@ This example demonstrates how to configuring Jetty for logging to ____ [IMPORTANT] -While this is a valid setup, the Jetty project recommends always using the link:#example-logging-java-util-logging[slf4j to java.util.logging configuration] for memory and performance reasons. +While this is a valid setup, the Jetty project recommends always using the link:#example-logging-java-util-logging[slf4j to java.util.logging configuration] for memory and performance reasons. This native implementation is very non-performant and is not guaranteed to exist in the future. ____ @@ -87,4 +86,4 @@ Other logging frameworks are more reliable in that they always initialize and co * While it is possible to configure `java.util.logging` sooner, even at JVM startup, the example demonstrated here does not show this technique. For more information consult the official `java.util.logging.LogManager` javadoc http://docs.oracle.com/javase/7/docs/api/java/util/logging/LogManager.html[documentation from Oracle]. -____ \ No newline at end of file +____ diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/example-java-util-logging.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/example-java-util-logging.adoc index 1e26e70a928..34ef7396576 100644 --- a/jetty-documentation/src/main/asciidoc/administration/logging/example-java-util-logging.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/logging/example-java-util-logging.adoc @@ -14,7 +14,6 @@ // You may elect to redistribute this code under either of these licenses. // ======================================================================== -[[example-logging-java-util-logging]] === Example: Logging with Java's java.util.logging via Slf4j It is possible to have the Jetty Server logging configured so that `java.util.logging` controls the output of logging events produced by Jetty. @@ -82,4 +81,4 @@ Other logging frameworks are more reliable in that they always initialize and co * While it is possible to configure `java.util.logging` sooner, even at JVM startup, the example demonstrated here does not show this technique. For more information consult the official `java.util.logging.LogManager` javadoc http://docs.oracle.com/javase/7/docs/api/java/util/logging/LogManager.html[documentation from Oracle]. -____ \ No newline at end of file +____ diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/example-logback.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/example-logback.adoc index 9cfadf26f72..f24dfc2d795 100644 --- a/jetty-documentation/src/main/asciidoc/administration/logging/example-logback.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/logging/example-logback.adoc @@ -14,10 +14,9 @@ // You may elect to redistribute this code under either of these licenses. // ======================================================================== -[[example-logging-logback]] === Example: Logging with Logback -It is possible to have the Jetty Server logging configured so that Logback controls the output of logging events produced by Jetty. +It is possible to have the Jetty Server logging configured so that Logback controls the output of logging events produced by Jetty. This is accomplished by configuring Jetty for logging to `Logback`, which uses http://slf4j.org/manual.html[Slf4j] and the http://logback.qos.ch/[Logback Implementation for Slf4j]. A convenient replacement `logging` module has been created to bootstrap the `${jetty.base}` directory for logging with logback. diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/chapter.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/chapter.adoc index cf8e60419dc..675d0fe9629 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/chapter.adoc @@ -29,6 +29,7 @@ include::session-configuration-jdbc.adoc[] include::session-configuration-mongodb.adoc[] include::session-configuration-infinispan.adoc[] include::session-configuration-gcloud.adoc[] +include::session-configuration-gcloud-module.adoc[] //include::setting-session-characteristics.adoc[] //include::using-persistent-sessions.adoc[] //include::session-clustering-jdbc.adoc[] diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-gcloud-datastore.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-gcloud-datastore.adoc index 9d9ccd40ab1..028eb52d720 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-gcloud-datastore.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-gcloud-datastore.adoc @@ -17,12 +17,12 @@ [[session-clustering-gcloud-datastore]] === Session Clustering with Google Cloud Datastore -Jetty can support session clustering by persisting sessions to https://cloud.google.com/datastore/docs/concepts/overview[Google Cloud Datastore]. -Each Jetty instance locally caches sessions for which it has received requests, writing any changes to the session through to the Datastore as the request exits the server. +Jetty can support session clustering by persisting sessions to https://cloud.google.com/datastore/docs/concepts/overview[Google Cloud Datastore]. +Each Jetty instance locally caches sessions for which it has received requests, writing any changes to the session through to the Datastore as the request exits the server. Sessions must obey the Serialization contract, and servlets must call the `Session.setAttribute()` method to ensure that changes are persisted. -The persistent session mechanism works in conjunction with a load balancer that supports stickiness. -Stickiness can be based on various data items, such as source IP address or characteristics of the session ID or a load-balancer specific mechanism. +The persistent session mechanism works in conjunction with a load balancer that supports stickiness. +Stickiness can be based on various data items, such as source IP address or characteristics of the session ID or a load-balancer specific mechanism. For those load balancers that examine the session ID, the Jetty persistent session mechanism appends a node ID to the session ID, which can be used for routing. ==== Configuration @@ -36,16 +36,16 @@ These managers also cooperate and collaborate with the `org.eclipse.jetty.server ==== The gcloud-sessions Module -When using the jetty distribution, to enable Cloud Datastore session persistence, you will first need to enable the `gcloud-sessions` link:#startup-modules[module] for your link:#creating-jetty-base[base] using the `--add-to-start` or `--add-to-startd` argument to the link:#startup-overview[start.jar]. +When using the jetty distribution, to enable Cloud Datastore session persistence, you will first need to enable the `gcloud-sessions` link:#startup-modules[module] for your link:#creating-jetty-base[base] using the `--add-to-start` argument to the link:#startup-overview[start.jar]. -As part of the module installation, the necessary jars will be dynamically downloaded and installed to your `${jetty.base}/lib/gcloud` directory. -If you need to up or downgrade the version of the jars, then you can delete the jars that were automatically installed and replace them. -Once you've done that, you will need to prevent jetty's startup checks from detecting the missing jars. +As part of the module installation, the necessary jars will be dynamically downloaded and installed to your `${jetty.base}/lib/gcloud` directory. +If you need to up or downgrade the version of the jars, then you can delete the jars that were automatically installed and replace them. +Once you've done that, you will need to prevent jetty's startup checks from detecting the missing jars. To do that, you can use `--skip-file-validation=glcoud-sessions` argument to start.jar on the command line, or place that line inside `${jetty.base}/start.ini` to ensure it is used for every start. ===== Configuring the GCloudSessionIdManager -The gcloud-sessions module will have installed file called `${jetty.home}/etc/jetty-gcloud-sessions.xml`. +The gcloud-sessions module will have installed file called `${jetty.home}/etc/jetty-gcloud-sessions.xml`. This file configures an instance of the `GCloudSessionIdManager` that will be shared across all webapps deployed on that server. It looks like this: [source, xml, subs="{sub-order}"] @@ -53,13 +53,13 @@ This file configures an instance of the `GCloudSessionIdManager` that will be sh include::{SRCDIR}/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/etc/jetty-gcloud-sessions.xml[] ---- -You configure it by setting values for properties. +You configure it by setting values for properties. The properties will either be inserted as commented out in your `start.ini`, or your `start.d/gcloud-sessions.ini` file, depending on how you enabled the module. The only property you always need to set is the name of the node in the cluster: jetty.gcloudSession.workerName:: - The name that uniquely identifies this node in the cluster. + The name that uniquely identifies this node in the cluster. This value will also be used by the sticky load balancer to identify the node. Don't forget to change the value of this property on *each* node on which you enable gcloud datastore session clustering. @@ -95,7 +95,7 @@ Follow the instructions on the https://cloud.google.com/datastore/docs/tools/dat ===== Configuring the GCloudSessionManager -As mentioned elsewhere, there must be one `SessionManager` per context (e.g. webapp). +As mentioned elsewhere, there must be one `SessionManager` per context (e.g. webapp). Each SessionManager needs to reference the single `GCloudSessionIdManager`. The way you configure a `GCloudSessionManager` depends on whether you're configuring from a context xml file, a `jetty-web.xml` file or code. @@ -104,7 +104,7 @@ The basic difference is how you get a reference to the Jetty `org.eclipse.jetty. From a context xml file, you reference the Server instance as a Ref: [source, xml, subs="{sub-order}"] ----- +---- @@ -152,23 +152,23 @@ From a `WEB-INF/jetty-web.xml` file, you can reference the Server instance direc The `GCloudSessionManager` supports the following configuration setters: scavengeIntervalSec:: - Time in seconds between runs of a scavenger task that looks for expired old sessions to delete. - The default is 10 minutes. + Time in seconds between runs of a scavenger task that looks for expired old sessions to delete. + The default is 10 minutes. If set to 0, no scavenging is done. staleIntervalSec:: The length of time a session can be in memory without being checked against the cluster. A value of 0 indicates that the session is never checked against the cluster - the current node is considered to be the master for the session. maxQueryResults:: - The maximum number of results to return for a query to find expired sessions. - For efficiency it is important to limit the size of the result. - The default is 100. + The maximum number of results to return for a query to find expired sessions. + For efficiency it is important to limit the size of the result. + The default is 100. If 0 or negative numbers are set, the default is used instead. ===== The gcloud-memcached-sessions module As an optimization, you can have Jetty store your session data into GCloud Datastore but also cache it into memcached. This serves two purposes: faster read-accesses and also better support for non-sticky load balancers (although using a non-sticky load balancer is highly undesirable and not recommended). -You will need to enable the `gcloud-memcached-sessions` link:#startup-modules[module] for your link:#creating-jetty-base[base] using the `--add-to-start` or `--add-to-startd` argument to the link:#startup-overview[start.jar]. +You will need to enable the `gcloud-memcached-sessions` link:#startup-modules[module] for your link:#creating-jetty-base[base] using the `--add-to-start` argument to the link:#startup-overview[start.jar]. If you already enabled the gcloud-sessions module, that's fine as the gcloud-memcached-sessions module depends on it anyway. @@ -191,7 +191,7 @@ If you have installed memcached on a host and port other than the defaults of `l *Note that* you will be configuring a `GCloudMemcachedSessionManager` 'instead of' a `GCloudSessionManager`. -As usual, there must be only one per context (e.g. webapp). +As usual, there must be only one per context (e.g. webapp). Each GCloudMemcachedSessionManager needs to reference the single `GCloudSessionIdManager`. @@ -201,7 +201,7 @@ The basic difference is how you get a reference to the Jetty `org.eclipse.jetty. From a context xml file, you reference the Server instance as a Ref: [source, xml, subs="{sub-order}"] ----- +---- @@ -255,16 +255,16 @@ From a `WEB-INF/jetty-web.xml` file, you can reference the Server instance direc The `GCloudMemcachedSessionManager` supports the following configuration setters: scavengeIntervalSec:: - Time in seconds between runs of a scavenger task that looks for expired old sessions to delete. - The default is 10 minutes. + Time in seconds between runs of a scavenger task that looks for expired old sessions to delete. + The default is 10 minutes. If set to 0, no scavenging is done. staleIntervalSec:: The length of time a session can be in memory without being checked against the cluster. A value of 0 indicates that the session is never checked against the cluster - the current node is considered to be the master for the session. maxQueryResults:: - The maximum number of results to return for a query to find expired sessions. - For efficiency it is important to limit the size of the result. - The default is 100. + The maximum number of results to return for a query to find expired sessions. + For efficiency it is important to limit the size of the result. + The default is 100. If 0 or negative numbers are set, the default is used instead. host:: The address of the host where the memcached server is running. Defaults to "localhost". diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-infinispan.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-infinispan.adoc index bc1c92aa540..756526f27a2 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-infinispan.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-infinispan.adoc @@ -36,7 +36,7 @@ These managers also cooperate and collaborate with the `org.eclipse.jetty.server ==== The Infinispan Module -When using the jetty distribution, to enable Infinispan session persistence, you will first need to enable the Infinispan link:#startup-modules[module] for your link:#creating-jetty-base[base] using the `--add-to-start` or `--add-to-startd` argument to the link:#startup-overview[start.jar]. +When using the jetty distribution, to enable Infinispan session persistence, you will first need to enable the Infinispan link:#startup-modules[module] for your link:#creating-jetty-base[base] using the `--add-to-start` argument to the link:#startup-overview[start.jar]. As part of the module installation, the necessary Infinispan jars will be dynamically downloaded and installed to your `${jetty.base}/lib/infinispan` directory. If you need to up or downgrade the version of the Infinispan jars, then you can delete the jars that were automatically installed and replace them. diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-jdbc.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-jdbc.adoc index 969de5945dd..8c4cbfda027 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-jdbc.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-jdbc.adoc @@ -17,16 +17,16 @@ [[session-clustering-jdbc]] === Session Clustering with a Database -Jetty can support session clustering by persisting sessions to a shared database. -Each Jetty instance locally caches sessions for which it has received requests, writing any changes to the session through to the database as the request exits the server. +Jetty can support session clustering by persisting sessions to a shared database. +Each Jetty instance locally caches sessions for which it has received requests, writing any changes to the session through to the database as the request exits the server. Sessions must obey the Serialization contract, and servlets must call the `Session.setAttribute()` method to ensure that changes are persisted. -The persistent session mechanism works in conjunction with a load balancer that supports stickiness. -Stickiness can be based on various data items, such as source IP address or characteristics of the session ID or a load-balancer specific mechanism. +The persistent session mechanism works in conjunction with a load balancer that supports stickiness. +Stickiness can be based on various data items, such as source IP address or characteristics of the session ID or a load-balancer specific mechanism. For those load balancers that examine the session ID, the Jetty persistent session mechanism appends a node ID to the session ID, which can be used for routing. -In this type of solution, the database can become both a bottleneck and a single point of failure. -Jetty takes steps to reduce the load on the database (discussed below), but in a heavily loaded environment you might need to investigate other optimization strategies such as local caching and database replication. +In this type of solution, the database can become both a bottleneck and a single point of failure. +Jetty takes steps to reduce the load on the database (discussed below), but in a heavily loaded environment you might need to investigate other optimization strategies such as local caching and database replication. You should also consult your database vendor's documentation for information on how to ensure high availability and failover of your database. ==== Configuration @@ -40,7 +40,7 @@ These managers also cooperate and collaborate with the `org.eclipse.jetty.server ==== The jdbc-session Module -When using the jetty distribution, to enable jdbc session persistence, you will first need to enable the jdbc-session link:#startup-modules[module] for your link:#creating-jetty-base[base] using the `--add-to-start` or `--add-to-startd` argument to the link:#startup-overview[start.jar]. +When using the jetty distribution, to enable jdbc session persistence, you will first need to enable the jdbc-session link:#startup-modules[module] for your link:#creating-jetty-base[base] using the `--add-to-start` argument to the link:#startup-overview[start.jar]. You will also find the following properties, either in your base's start.d/jdbc-session.ini file or appended to your start.ini, depending on how you enabled the module: @@ -56,26 +56,26 @@ jetty.jdbcSession.connectionURL=jdbc:derby:sessions;create=true ---- jetty.jdbcSession.workerName:: - The name that uniquely identifies this node in the cluster. + The name that uniquely identifies this node in the cluster. This value will also be used by the sticky load balancer to identify the node. Don't forget to change the value of this property on *each* node on which you enable jdbc session clustering. jetty.jdbcSession.scavenge:: - The time in seconds between sweeps of a task which scavenges old expired sessions. - The default is 10 minutess. + The time in seconds between sweeps of a task which scavenges old expired sessions. + The default is 10 minutess. Increasing the frequency is not recommended as doing so increases the load on the database with very little gain. jetty.jdbcSession.datasource:: - The name of a `javax.sql.DataSource` that gives access to the database that holds the session information. + The name of a `javax.sql.DataSource` that gives access to the database that holds the session information. You should configure *either* this or the jdbc driver information described next. jetty.jdbcSession.datasource and jetty.jdbcSession.connectionURL:: - This is the name of the jdbc driver class, and a jdbc connection url suitable for that driver. + This is the name of the jdbc driver class, and a jdbc connection url suitable for that driver. You should configure *either* this or the jdbc datasource name described above. These properties are applied to the `JDBCSessionIdManager` described below. ===== Configuring the JDBCSessionIdManager -The jdbc-session module will have installed file called `$\{jetty.home}/etc/jetty-jdbc-sessions.xml`. -This file configures an instance of the `JDBCSessionIdManager` that will be shared across all webapps deployed on that server. +The jdbc-session module will have installed file called `$\{jetty.home}/etc/jetty-jdbc-sessions.xml`. +This file configures an instance of the `JDBCSessionIdManager` that will be shared across all webapps deployed on that server. It looks like this: [source, xml, subs="{sub-order}"] @@ -88,7 +88,7 @@ As well as uncommenting and setting up appropriate values for the properties dis As Jetty configuration files are direct mappings of XML to Java, it is straight forward to do this in code: [source, java, subs="{sub-order}"] ----- +---- Server server = new Server(); ... JDBCSessionIdManager idMgr = new JDBCSessionIdManager(server); @@ -96,7 +96,7 @@ idMgr.setWorkerName("node1"); idMgr.setDriverInfo("com.mysql.jdbc.Driver", "jdbc:mysql://127.0.0.1:3306/sessions?user=janb"); idMgr.setScavengeInterval(600); server.setSessionIdManager(idMgr); - + ---- ====== Configuring the Database Schema @@ -108,7 +108,7 @@ The defaults used are: [options="header"] |=========================== |table name |JettySessionIds -|columns |id +|columns |id |=========================== .Default Values for Session Table @@ -121,10 +121,10 @@ accessTime, lastAccessTime, createTime, cookieTime, lastSavedTime, expiryTime, maxInterval, map |======================================================================= -To change these values, use the link:{JDURL}/org/eclipse/jetty/server/session/SessionIdTableSchema.html[org.eclipse.jetty.server.session.SessionIdTableSchema] and link:{JDURL}/org/eclipse/jetty/server/session/SessionTableSchema.html[org.eclipse.jetty.server.session.SessionTableSchema] classes. +To change these values, use the link:{JDURL}/org/eclipse/jetty/server/session/SessionIdTableSchema.html[org.eclipse.jetty.server.session.SessionIdTableSchema] and link:{JDURL}/org/eclipse/jetty/server/session/SessionTableSchema.html[org.eclipse.jetty.server.session.SessionTableSchema] classes. These classes have getter/setter methods for the table name and all columns. -Here's an example of changing the name of `JettySessionsId` table and its single column. +Here's an example of changing the name of `JettySessionsId` table and its single column. This example will use java code, but as explained above, you may also do this via a Jetty xml configuration file: [source, java, subs="{sub-order}"] @@ -137,7 +137,7 @@ idTableSchema.setIdColumn("theid"); idManager.setSessionIdTableSchema(idTableSchema); ---- -In a similar fashion, you can change the names of the table and columns for the `JettySessions` table. +In a similar fashion, you can change the names of the table and columns for the `JettySessions` table. *Note* that both the `SessionIdTableSchema` and the `SessionTableSchema` instances are set on the `JDBCSessionIdManager` class. [source, java, subs="{sub-order}"] @@ -156,13 +156,13 @@ sessionTableSchema.setLastAccessTimeColumn("latime"); sessionTableSchema.setLastNodeColumn("lnode"); sessionTableSchema.setLastSavedTimeColumn("lstime"); sessionTableSchema.setMapColumn("mo"); -sessionTableSchema.setMaxIntervalColumn("mi"); +sessionTableSchema.setMaxIntervalColumn("mi"); idManager.setSessionTableSchema(sessionTableSchema); ---- ===== Configuring the JDBCSessionManager -As mentioned elsewhere, there should be one `JDBCSessionManager` per context (e.g. webapp). +As mentioned elsewhere, there should be one `JDBCSessionManager` per context (e.g. webapp). It will need to reference the single `JDBCSessionIdManager` configured previously for the Server. The way you configure a `JDBCSessionManager` depends on whether you're configuring from a context xml file, a `jetty-web.xml` file or code. @@ -192,7 +192,7 @@ From a `WEB-INF/jetty-web.xml` file, you can reference the Server instance direc [source, xml, subs="{sub-order}"] ---- - + @@ -216,7 +216,7 @@ If you're embedding this in code: //assuming you have already set up the JDBCSessionIdManager as shown earlier //and have a reference to the Server instance: - + WebAppContext wac = new WebAppContext(); ... //configure your webapp context JDBCSessionManager jdbcMgr = new JDBCSessionManager(); diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-mongodb.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-mongodb.adoc index 03b0eec2a13..98eb5bb21e8 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-mongodb.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/legacy/session-clustering-mongodb.adoc @@ -17,17 +17,17 @@ [[session-clustering-mongodb]] === Session Clustering with MongoDB -Jetty can support session clustering by persisting sessions into http://www.mogodb.org[MongoDB]. -Each Jetty instance locally caches sessions for which it has received requests, writing any changes to the session through to the cluster as the request exits the server. +Jetty can support session clustering by persisting sessions into http://www.mogodb.org[MongoDB]. +Each Jetty instance locally caches sessions for which it has received requests, writing any changes to the session through to the cluster as the request exits the server. Sessions must obey the Serialization contract, and servlets must call the `Session.setAttribute()` method to ensure that changes are persisted. -The session persistence mechanism works in conjunction with a load balancer that supports stickiness. -Stickiness can be based on various data items, such as source IP address or characteristics of the session ID or a load-balancer specific mechanism. +The session persistence mechanism works in conjunction with a load balancer that supports stickiness. +Stickiness can be based on various data items, such as source IP address or characteristics of the session ID or a load-balancer specific mechanism. For those load balancers that examine the session ID, the Jetty persistent session mechanism appends a node ID to the session ID, which can be used for routing. -In this type of solution, the traffic on the network needs to be carefully watched and tends to be the bottleneck. -You are probably investigating this solution in order to scale to large amount of users and sessions, so careful attention should be paid to your usage scenario. -Applications with a heavy write profile to their sessions will consume more network bandwidth than profiles that are predominately read oriented. +In this type of solution, the traffic on the network needs to be carefully watched and tends to be the bottleneck. +You are probably investigating this solution in order to scale to large amount of users and sessions, so careful attention should be paid to your usage scenario. +Applications with a heavy write profile to their sessions will consume more network bandwidth than profiles that are predominately read oriented. We recommend using this session manager with largely read based session scenarios. ==== Configuration @@ -41,12 +41,12 @@ These managers also cooperate and collaborate with the `org.eclipse.jetty.server ==== The nosql Module -When using the jetty distribution, to enable the MongoDB session persistence mechanism, you will first need to enable the nosql link:#startup-modules[module] for your link:#creating-jetty-base[base] using the `--add-to-start` or `--add-to-startd` argument to the link:#startup-overview[start.jar]. +When using the jetty distribution, to enable the MongoDB session persistence mechanism, you will first need to enable the nosql link:#startup-modules[module] for your link:#creating-jetty-base[base] using the `--add-to-start` argument to the link:#startup-overview[start.jar]. This module will automatically download the `mongodb-java-driver` and install it to your base's `lib/nosql` directory. -As part of the module installation, the necessary mongo java driver jars will be dynamically downloaded and installed to your `${jetty.base}/lib/nosql` directory. -If you need to up or downgrade the version of these jars, then you can delete the jars that were automatically installed and replace them. -Once you've done that, you will need to prevent Jetty's startup checks from detecting the missing jars. +As part of the module installation, the necessary mongo java driver jars will be dynamically downloaded and installed to your `${jetty.base}/lib/nosql` directory. +If you need to up or downgrade the version of these jars, then you can delete the jars that were automatically installed and replace them. +Once you've done that, you will need to prevent Jetty's startup checks from detecting the missing jars. To do that, you can use `--skip-file-validation=nosql` argument to start.jar on the command line, or place that line inside `${jetty.base}/start.ini` to ensure it is used for every start. You will also find the following properties, either in your base's `start.d/nosql.ini` file or appended to your `start.ini`, depending on how you enabled the module: @@ -61,8 +61,8 @@ jetty.nosqlSession.workerName=node1 jetty.nosqlSession.scavenge=1800 ---- -The `jetty.nosqlSession.workerName` is the unique name for this Jetty Server instance. -It will be used by the sticky load balancer to uniquely identify the node. +The `jetty.nosqlSession.workerName` is the unique name for this Jetty Server instance. +It will be used by the sticky load balancer to uniquely identify the node. You should change this value on *each* node to which you install MongoDB session management. The `jetty.nosqlSession.scavenge` property defines the time in seconds between runs of the scavenger: the scavenger is a task which runs periodically to clean out sessions that have expired but become stranded in the database for whatever reason. @@ -71,8 +71,8 @@ These properties are substituted into the configuration of the `MongoDBSessionId ===== Configuring the MongoSessionIdManager -The nosql module will have installed file called `$\{jetty.home}/etc/jetty-nosql.xml`. -This file configures an instance of the `MongoSessionIdManager` that will be shared across all webapps deployed on that server. +The nosql module will have installed file called `$\{jetty.home}/etc/jetty-nosql.xml`. +This file configures an instance of the `MongoSessionIdManager` that will be shared across all webapps deployed on that server. It looks like this: [source, xml, subs="{sub-order}"] @@ -80,8 +80,8 @@ It looks like this: include::{SRCDIR}/jetty-nosql/src/main/config/etc/jetty-nosql.xml[] ---- -The `MongoSessionIdManager` needs access to a MongoDB cluster, and the `jetty-nosql.xml` file assumes the defaults of localhost and default MongoDB port. -If you need to configure something else, you will need to edit this file. +The `MongoSessionIdManager` needs access to a MongoDB cluster, and the `jetty-nosql.xml` file assumes the defaults of localhost and default MongoDB port. +If you need to configure something else, you will need to edit this file. Here's an example of a more complex setup to use a remote MongoDB instance: [source, xml, subs="{sub-order}"] @@ -122,31 +122,31 @@ Here's an example of a more complex setup to use a remote MongoDB instance: - - + + ---- As Jetty configuration files are direct mappings of XML to Java, it is straight forward to do this in code: [source, java, subs="{sub-order}"] ---- - + Server server = new Server(); ... MongoSessionIdManager idMgr = newMongoSessionIdManager(server); idMgr.setWorkerName("node1"); idMgr.setScavengePeriod(1800); server.setSessionIdManager(idMgr); - + ---- -The MongoSessionIdManager has slightly different options than some of our more traditional session options. -The `MongoDBSessionIdManager` has the same scavenge timers which govern the setting of a valid session to invalid after a certain period of inactivity. -New to this session id manager is the extra purge setting which governs removal from the MongoDB cluster. -This can be configured through the 'purge' option. Purge is by default set to true and by default runs daily for each node on the cluster. -Also able to be configured is the age in which an invalid session will be retained which is set to 1 day by default. -This means that invalid sessions will be removed after lingering in the MongoDB instance for a day. -There is also an option for purging valid sessions that have not been used recently. +The MongoSessionIdManager has slightly different options than some of our more traditional session options. +The `MongoDBSessionIdManager` has the same scavenge timers which govern the setting of a valid session to invalid after a certain period of inactivity. +New to this session id manager is the extra purge setting which governs removal from the MongoDB cluster. +This can be configured through the 'purge' option. Purge is by default set to true and by default runs daily for each node on the cluster. +Also able to be configured is the age in which an invalid session will be retained which is set to 1 day by default. +This means that invalid sessions will be removed after lingering in the MongoDB instance for a day. +There is also an option for purging valid sessions that have not been used recently. The default time for this is 1 week. You can disable these behaviors by setting purge to false. scavengeDelay:: @@ -154,8 +154,8 @@ scavengeDelay:: scavengePeriod:: How much time after a scavenge has completed should you wait before doing it again? scavengeBlockSize:: - Number of session ids to which to limit each scavenge query. - If you have a very large number of sessions in memory then setting this to a non 0 value may help speed up scavenging by breaking the scavenge into multiple, queries. + Number of session ids to which to limit each scavenge query. + If you have a very large number of sessions in memory then setting this to a non 0 value may help speed up scavenging by breaking the scavenge into multiple, queries. The default is 0, which means that all session ids are considered in a single query. purge (Boolean):: Do you want to purge (delete) sessions that are invalid from the session store completely? @@ -164,11 +164,11 @@ purgeDelay:: purgeInvalidAge:: How old should an invalid session be before it is eligible to be purged? purgeValidAge:: - How old should a valid session be before it is eligible to be marked invalid and purged? + How old should a valid session be before it is eligible to be marked invalid and purged? Should this occur at all? purgeLimit:: - Integer value that represents how many items to return from a purge query. - The default is 0, which is unlimited. + Integer value that represents how many items to return from a purge query. + The default is 0, which is unlimited. If you have a lot of old expired orphaned sessions then setting this value may speed up the purge process. preserveOnStop:: Whether or not to retain all sessions when the session manager stops. @@ -176,16 +176,16 @@ preserveOnStop:: ===== Configuring a MongoSessionManager -As mentioned elsewhere, there should be one `MongoSessionManager` per context (e.g. webapp). +As mentioned elsewhere, there should be one `MongoSessionManager` per context (e.g. webapp). It will need to reference the single `MongoSessionIdManager` configured previously for the Server. -The way you configure a link:{JDURL}/org/eclipse/jetty/nosql/MongoSessionManager.html[org.eclipse.jetty.nosql.mongodb.MongoSessionManager] depends on whether you're configuring from a link:#deployable-descriptor-file[context xml] file or a link:#jetty-web-xml-config[jetty-web.xml] file or code. +The way you configure a link:{JDURL}/org/eclipse/jetty/nosql/MongoSessionManager.html[org.eclipse.jetty.nosql.mongodb.MongoSessionManager] depends on whether you're configuring from a link:#deployable-descriptor-file[context xml] file or a link:#jetty-web-xml-config[jetty-web.xml] file or code. The basic difference is how you get a reference to the Jetty `org.eclipse.jetty.server.Server` instance. From a context xml file, you reference the Server instance as a Ref: [source, xml, subs="{sub-order}"] ----- +---- @@ -229,7 +229,7 @@ If you're embedding this in code: ---- //assuming you have already set up the MongoSessionIdManager as shown earlier //and have a reference to the Server instance: - + WebAppContext wac = new WebAppContext(); ... //configure your webapp context MongoSessionManager mongoMgr = new MongoSessionManager(); diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-file-system.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-file-system.adoc index 7cda85feadc..e3a78ed8a53 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-file-system.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-file-system.adoc @@ -16,12 +16,15 @@ [[configuring-sessions-file-system]] -=== Configuring Session Management using the File System +=== Non-Clustered Session Management: File System When using the Jetty distribution, you will first need to enable the `session-store-file` link:#startup-modules[module] for your link:#startup-base-and-home[Jetty base] using the `--add-to-start` argument on the command line. [source, screen, subs="{sub-order}"] ---- +$ java -jar ../start.jar --create-startd +INFO : Base directory was modified + $ java -jar ../start.jar --add-to-start=session-store-file INFO : server initialised (transitively) in ${jetty.base}/start.d/server.ini INFO : sessions initialised (transitively) in ${jetty.base}/start.d/sessions.ini @@ -32,12 +35,12 @@ INFO : Base directory was modified //TODO - Callout default Session file location - note it is configurable Doing this enables the File System Session module and any dependent modules or files needed for it to run on the server. -The example above is running an fresh `{$jetty.base}` with nothing enabled. +The example above is running an fresh `${jetty.base}` with nothing enabled. When the `--add-to-start` argument was added to the command line, it enabled the the `session-store-file` module as well as the `sessions` and `server` modules, which are required for the File System session management to operate. Additionally a `${jetty.base}/sessions` directory was created. By default Session files will be saved to this directory. -In addition to adding these modules to the classpath of the server it also added several ini configuration files to the `start.d` directory of the `{$jetty.base}`. +In addition to adding these modules to the classpath of the server it also added several ini configuration files to the `start.d` directory of the `${jetty.base}`. Opening the `start.d/session-store-file.ini` will show a list of all the configurable options for the file system session module: @@ -49,12 +52,12 @@ Opening the `start.d/session-store-file.ini` will show a list of all the configu # --------------------------------------- --module=session-store-file -jetty.session.storeDir=${jetty.base}/sessions -#jetty.session.deleteUnrestorableFiles=false +jetty.session.file.storeDir=${jetty.base}/sessions +#jetty.session.file.deleteUnrestorableFiles=false ---- jetty.session.storeDir:: This defines the location for storage of Session files. -jetty.session.deleteUnrestorableFiles:: +jetty.session.file.deleteUnrestorableFiles:: Boolean. If set to true, unreadable files will be deleted: this is useful to prevent repeated logging of the same error when the scavenger periodically (re-) attempts to load the corrupted information for a session in order to expire it. diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-gcloud.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-gcloud.adoc index 0ae281c6272..62d64b5f601 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-gcloud.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-gcloud.adoc @@ -15,26 +15,71 @@ // ======================================================================== [[configuring-sessions-gcloud]] +=== Clustered Session Management: Google Cloud DataStore -=== Configuring Google Cloud DataStore +==== Preparation + +You will first need to create a project and enable the Google Cloud api: https://cloud.google.com/docs/authentication#preparation. +Take note of the project id that you create in this step as you need to supply it in later steps. + +===== Communicating with GCloudDataStore + +====== When running Jetty outside of google infrastructure + +Before running Jetty, you will need to choose one of the following methods to set up the local environment to enable remote GCloud DataStore communications. + +1. Using the GCloud SDK: + * Ensure you have the GCloud SDK installed: https://cloud.google.com/sdk/?hl=en. + * Use the GCloud tool to set up the project you created in the preparation step: `gcloud config set project PROJECT_ID` + * Use the GCloud tool to authenticate a google account associated with the project created in the preparation step: `gcloud auth login ACCOUNT` + +2. Using environment variables + * Define the environment variable `GCLOUD_PROJECT` with the project id you created in the preparation step. + * Generate a JSON link:https://cloud.google.com/storage/docs/authentication?hl=en#service_accounts[service account key] and then define the environment variable `GOOGLE_APPLICATION_CREDENTIALS=/path/to/my/key.json` + + +====== When Running Jetty Inside of Google Infrastructure + +The Google deployment tools will automatically configure the project and authentication information for you. + +==== Configuring Indexes for Session Data + +Regardless of whether you're running inside or outside google infrastructure you will need to upload a file that defines some indexes that are needed by the GCloud datastore session data store. +This file is named `index.yaml` and you can find it in your distribution in `${jetty.base}/etc/sessions/gcloud/index.yaml`. + +//TODO - Add index.yaml properties? Test with new 9.4.x. It needs uploaded to Google as part of config + +Follow the instructions link:https://cloud.google.com/datastore/docs/tools/#the_development_workflow_using_gcloud[here] to upload the pre-generated `index.yaml` file. + +===== Communicating with the GCloudDataStore Emulator + +To enable communication using the GCloud Emulator: + + * Ensure you have the GCloud SDK installed: https://cloud.google.com/sdk/?hl=en + * Follow the instructions link:https://cloud.google.com/datastore/docs/tools/datastore-emulator[here] on how to start the GCloud datastore emulator, and how to propagate the environment variables that it creates to the terminal in which you run Jetty. + +==== Configuring the Google Cloud DataStore Module When using the Jetty distribution, you will first need to enable the `session-store-gcloud` link:#startup-modules[module] for your link:#startup-base-and-home[Jetty base] using the `--add-to-start` argument on the command line. [source, screen, subs="{sub-order}"] ---- +$ java -jar ../start.jar --create-startd +INFO : Base directory was modified + $ java -jar ../start.jar --add-to-start=session-store-gcloud ALERT: There are enabled module(s) with licenses. The following 1 module(s): - + contains software not provided by the Eclipse Foundation! - + contains software not covered by the Eclipse Public License! - + has not been audited for compliance with its license ++ contains software not provided by the Eclipse Foundation! ++ contains software not covered by the Eclipse Public License! ++ has not been audited for compliance with its license - Module: session-store-gcloud - + GCloudDatastore is an open source project hosted on Github and released under the Apache 2.0 license. - + https://github.com/GoogleCloudPlatform/gcloud-java - + http://www.apache.org/licenses/LICENSE-2.0.html +Module: session-store-gcloud + + GCloudDatastore is an open source project hosted on Github and released under the Apache 2.0 license. + + https://github.com/GoogleCloudPlatform/gcloud-java + + http://www.apache.org/licenses/LICENSE-2.0.html Proceed (y/N)? y INFO : server initialised (transitively) in ${jetty.base}/start.d/server.ini @@ -79,11 +124,11 @@ WARN : Module session-store-gcloud requires jcl-api from one of [jcl, jcl-slf4j] WARN : Unsatisfied module dependencies: session-store-gcloud,session-store-gcloud Usage: java -jar $JETTY_HOME/start.jar [options] [properties] [configs] - java -jar $JETTY_HOME/start.jar --help # for more information + java -jar $JETTY_HOME/start.jar --help # for more information ---- Doing this enables the GCloud Session module and any dependent session modules or files needed for it to run on the server. -The example above is running an fresh `{$jetty.base}` with nothing enabled. +The example above is running an fresh `${jetty.base}` with nothing enabled. Because the Google Cloud DataStore is not a technology provided by the Eclipse Foundation, users are prompted to assent to the licenses of the external vendor (Apache in this case). You will notice, however, that the above output presented a warning: GCloud requires certain Java Commons Logging features to work correctly. As such, you will also need to enable either the `jcl` or `jcl-slf4j` module. @@ -94,13 +139,13 @@ $ java -jar ../start.jar --add-to-start=jcl ALERT: There are enabled module(s) with licenses. The following 1 module(s): - + contains software not provided by the Eclipse Foundation! - + contains software not covered by the Eclipse Public License! - + has not been audited for compliance with its license ++ contains software not provided by the Eclipse Foundation! ++ contains software not covered by the Eclipse Public License! ++ has not been audited for compliance with its license - Module: jcl - + Log4j is released under the Apache 2.0 license. - + http://www.apache.org/licenses/LICENSE-2.0.html +Module: jcl + + Log4j is released under the Apache 2.0 license. + + http://www.apache.org/licenses/LICENSE-2.0.html Proceed (y/N)? y INFO : jcl initialised in ${jetty.base}/start.d/jcl.ini @@ -109,14 +154,14 @@ INFO : Base directory was modified ---- When the `--add-to-start` argument was added to the command line the first time, it enabled the the `session-store-gcloud` module as well as the `sessions` and `server` modules, which are required for GCloud session management to operate; the `jcl` module was added when we ran it the second time. -In addition to adding these modules to the classpath of the server it also added several ini configuration files to the `start.d` directory of the `{$jetty.base}`. +In addition to adding these modules to the classpath of the server it also added several ini configuration files to the `start.d` directory of the `${jetty.base}`. ____ [NOTE] If you have updated versions of the jar files automatically downloaded by Jetty, you can place them in the associated `${jetty.base}/lib/` directory and use the `--skip-file-validation=` command line option to prevent errors when starting your server. ____ -Opening the `start.d/session-store-gcloud.ini` will show a list of all the configurable options for the Google Cloud DataStore module: +Opening the `start.d/session-store-gcloud.ini` will show a list of all the configurable properties for the Google Cloud DataStore module: [source, screen, subs="{sub-order}"] ---- @@ -128,13 +173,23 @@ Opening the `start.d/session-store-gcloud.ini` will show a list of all the confi ## GCloudDatastore Session config -#jetty.gcloudSession.maxRetries=5 -#jetty.gcloudSession.backoffMs=1000 +#jetty.session.gcloud.maxRetries=5 +#jetty.session.gcloud.backoffMs=1000 +#jetty.session.gcloud.model.kind=GCloudSession +#jetty.session.gcloud.model.id=id +#jetty.session.gcloud.model.contextPath=contextPath +#jetty.session.gcloud.model.vhost=vhost +#jetty.session.gcloud.model.accessed=accessed +#jetty.session.gcloud.model.lastAccessed=lastAccessed +#jetty.session.gcloud.model.createTime=createTime +#jetty.session.gcloud.model.cookieSetTime=cookieSetTime +#jetty.session.gcloud.model.lastNode=lastNode +#jetty.session.gcloud.model.expiry=expiry +#jetty.session.gcloud.model.maxInactive=maxInactive +#jetty.session.gcloud.model.attributes=attributes ---- -jetty.gcloudSession.maxRetries:: +jetty.session.gcloud.maxRetries:: Maxmium number of tries to connect to GCloud DataStore to write sessions. -jetty.gcloudSession.backoffMs:: +jetty.session.gcloud.backoffMs:: Amount of time, in milliseconds, between attempts to connect to the GCloud DataStore to write sessions. - -//TODO - Add index.yaml properties? diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-infinispan.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-infinispan.adoc index 727c74d1138..0828d884ad9 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-infinispan.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-infinispan.adoc @@ -16,12 +16,15 @@ [[configuring-sessions-infinispan]] -=== Configuring Remote Inifinspan Clustering +=== Clustered Session Management: Inifinspan When using the Jetty distribution, you will first need to enable the `session-store-infinispan-remote` link:#startup-modules[module] for your link:#startup-base-and-home[Jetty base] using the `--add-to-start` argument on the command line. [source, screen, subs="{sub-order}"] ---- +$ java -jar ../start.jar --create-startd +INFO : Base directory was modified + $ java -jar ../start.jar --add-to-start=session-store-infinispan-remote ALERT: There are enabled module(s) with licenses. @@ -45,11 +48,11 @@ INFO : Base directory was modified ---- Doing this enables the remote Infinispan Session module and any dependent modules or files needed for it to run on the server. -The example above is running an fresh `{$jetty.base}` with nothing enabled. +The example above is running an fresh `${jetty.base}` with nothing enabled. Because Infinispan is not a technology provided by the Eclipse Foundation, users are prompted to assent to the licenses of the external vendor (Apache in this case). When the `--add-to-start` argument was added to the command line, it enabled the the `session-store-infinispan-remote` module as well as the `sessions` and `server` modules, which are required for Infinispan session management to operate. It also downloaded the needed Infinispan-specific jar files and created a directory named `${jetty.base}/lib/infinispan/` to house them. -In addition to adding these modules to the classpath of the server it also added several ini configuration files to the `start.d` directory of the `{$jetty.base}`. +In addition to adding these modules to the classpath of the server it also added several ini configuration files to the `start.d` directory of the `${jetty.base}`. ____ [NOTE] @@ -66,18 +69,20 @@ Opening the `start.d/session-store-infinispan-remote.ini` will show a list of al # --------------------------------------- --module=session-store-infinispan-remote -#jetty.session.remoteInfinispanCache.name=sessions -#jetty.session.infinispanIdleTimeout.seconds=0 +#jetty.session.infinispan.remoteCacheName=sessions +#jetty.session.infinispan.idleTimeout.seconds=0 #jetty.session.gracePeriod.seconds=3600 ---- -jetty.session.remoteInfinispanCache.name:: -jetty.session.infinispanIdleTimeout.seconds:: +jetty.session.infinispan.remoteCacheName:: +Name of the cache in Infinispan where sessions will be stored. +jetty.session.infinispan.idleTimeout.seconds:: +Amount of time, in seconds, that the system allows the connector to remain idle before closing the connection. jetty.session.gracePeriod.seconds:: Amount of time, in seconds, to wait for other nodes to be checked to verify an expired session is in fact expired throughout the cluster before closing it. -=== Configuring Embedded Inifinspan Clustering +==== Configuring Embedded Inifinspan Clustering During testing, it can be helpful to run an in-process instance of Infinispan. To enable this you will first need to enable the `session-store-infinispan-embedded` link:#startup-modules[module] for your link:#startup-base-and-home[Jetty base] using the `--add-to-start` argument on the command line. @@ -106,8 +111,8 @@ INFO : Base directory was modified ---- Doing this enables the embedded Infinispan Session module and any dependent modules or files needed for it to run on the server. -The example above is running an fresh `{$jetty.base}` with nothing enabled. +The example above is running an fresh `${jetty.base}` with nothing enabled. Because Infinispan is not a technology provided by the Eclipse Foundation, users are prompted to assent to the licenses of the external vendor (Apache in this case). When the `--add-to-start` argument was added to the command line, it enabled the the `session-store-infinispan-embedded` module as well as the `sessions` and `server` modules, which are required for Infinispan session management to operate. It also downloaded the needed Infinispan-specific jar files and created a directory named `${jetty.base}/lib/infinispan/` to house them. -In addition to adding these modules to the classpath of the server it also added several ini configuration files to the `start.d` directory of the `{$jetty.base}`. +In addition to adding these modules to the classpath of the server it also added several ini configuration files to the `start.d` directory of the `${jetty.base}`. diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-jdbc.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-jdbc.adoc index 7e9377a4ae6..e09ff40a3c4 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-jdbc.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-jdbc.adoc @@ -16,12 +16,15 @@ [[configuring-sessions-jdbc]] -=== Configuring JDBC Clustering +=== Clustered Session Management: JDBC When using the Jetty distribution, you will first need to enable the `session-store-jdbc` link:#startup-modules[module] for your link:#startup-base-and-home[Jetty base] using the `--add-to-start` argument on the command line. [source, screen, subs="{sub-order}"] ---- +$ java -jar ../start.jar --create-startd +INFO : Base directory was modified + $ java -jar ../start.jar --add-to-start=session-store-jdbc INFO : server initialised (transitively) in ${jetty.base}/start.d/server.ini INFO : sessions initialised (transitively) in ${jetty.base}/start.d/sessions.ini @@ -30,9 +33,9 @@ INFO : Base directory was modified ---- Doing this enables the JDBC Session module and any dependent modules or files needed for it to run on the server. -The example above is running an fresh `{$jetty.base}` with nothing enabled. +The example above is running an fresh `${jetty.base}` with nothing enabled. When the `--add-to-start` argument was added to the command line, it enabled the the `session-store-jdbc` module as well as the `sessions` and `server` modules, which are required for JDBC session management to operate. -In addition to adding these modules to the classpath of the server it also added several ini configuration files to the `start.d` directory of the `{$jetty.base}`. +In addition to adding these modules to the classpath of the server it also added several ini configuration files to the `start.d` directory of the `${jetty.base}`. Opening the `start.d/session-store-jdbc.ini` will show a list of all the configurable options for the JDBC module: @@ -52,49 +55,40 @@ Opening the `start.d/session-store-jdbc.ini` will show a list of all the configu ## Connection type:Datasource db-connection-type=datasource -#jetty.session.datasourceName=/jdbc/sessions +#jetty.session.jdbc.datasourceName=/jdbc/sessions ## Connection type:driver #db-connection-type=driver -#jetty.session.driverClass= -#jetty.session.driverUrl= +#jetty.session.jdbc.driverClass= +#jetty.session.jdbc.driverUrl= ## Session table schema -#jetty.sessionTableSchema.accessTimeColumn=accessTime -#jetty.sessionTableSchema.contextPathColumn=contextPath -#jetty.sessionTableSchema.cookieTimeColumn=cookieTime -#jetty.sessionTableSchema.createTimeColumn=createTime -#jetty.sessionTableSchema.expiryTimeColumn=expiryTime -#jetty.sessionTableSchema.lastAccessTimeColumn=lastAccessTime -#jetty.sessionTableSchema.lastSavedTimeColumn=lastSavedTime -#jetty.sessionTableSchema.idColumn=sessionId -#jetty.sessionTableSchema.lastNodeColumn=lastNode -#jetty.sessionTableSchema.virtualHostColumn=virtualHost -#jetty.sessionTableSchema.maxIntervalColumn=maxInterval -#jetty.sessionTableSchema.mapColumn=map -#jetty.sessionTableSchema.table=JettySessions +#jetty.session.jdbc.schema.accessTimeColumn=accessTime +#jetty.session.jdbc.schema.contextPathColumn=contextPath +#jetty.session.jdbc.schema.cookieTimeColumn=cookieTime +#jetty.session.jdbc.schema.createTimeColumn=createTime +#jetty.session.jdbc.schema.expiryTimeColumn=expiryTime +#jetty.session.jdbc.schema.lastAccessTimeColumn=lastAccessTime +#jetty.session.jdbc.schema.lastSavedTimeColumn=lastSavedTime +#jetty.session.jdbc.schema.idColumn=sessionId +#jetty.session.jdbc.schema.lastNodeColumn=lastNode +#jetty.session.jdbc.schema.virtualHostColumn=virtualHost +#jetty.session.jdbc.schema.maxIntervalColumn=maxInterval +#jetty.session.jdbc.schema.mapColumn=map +#jetty.session.jdbc.schema.table=JettySessions ---- jetty.session.gracePeriod.seconds:: Amount of time, in seconds, to wait for other nodes to be checked to verify an expired session is in fact expired throughout the cluster before closing it. db-connection-type:: -jetty.session.datasourceName:: +Set to either `datasource` or `driver` depending on the type of connection being used. +jetty.session.jdbc.datasourceName:: +Name of the remote datasource. +jetty.session.jdbc.driverClass:: +Name of the JDBC driver that controls access to the remote database, such as `com.mysql.jdbc.Driver` +jetty.session.jdbc.driverUrl:: +Url of the database which includes the driver type, host name and port, service name and any specific attributes unique to the database, such as a username. +As an example, here is a mysql connection with the username appended: `jdbc:mysql://127.0.0.1:3306/sessions?user=sessionsadmin`. -db-connection-type:: -jetty.session.driverClass:: -jetty.session.driverUrl:: - -jetty.sessionTableSchema.accessTimeColumn:: -jetty.sessionTableSchema.contextPathColumn:: -jetty.sessionTableSchema.cookieTimeColumn:: -jetty.sessionTableSchema.createTimeColumn:: -jetty.sessionTableSchema.expiryTimeColumn:: -jetty.sessionTableSchema.lastAccessTimeColumn:: -jetty.sessionTableSchema.lastSavedTimeColumn:: -jetty.sessionTableSchema.idColumn:: -jetty.sessionTableSchema.lastNodeColumn:: -jetty.sessionTableSchema.virtualHostColumn:: -jetty.sessionTableSchema.maxIntervalColumn:: -jetty.sessionTableSchema.mapColumn:: -jetty.sessionTableSchema.table:: +The `jetty.sessionTableSchema` values represent the names for the columns in the JDBC database and can be changed to suit your environment. diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-mongodb.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-mongodb.adoc index 7b93701bb8d..9b171ae54d0 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-mongodb.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-mongodb.adoc @@ -16,12 +16,15 @@ [[configuring-sessions-mongo]] -=== Configuring MongoDB Clustering +=== Clustered Session Management: MongoDB When using the Jetty distribution, you will first need to enable the `session-store-mongo` link:#startup-modules[module] for your link:#startup-base-and-home[Jetty base] using the `--add-to-start` argument on the command line. [source, screen, subs="{sub-order}"] ---- +$ java -jar ../start.jar --create-startd +INFO : Base directory was modified + $ java -jar ../start.jar --add-to-start=session-store-mongo ALERT: There are enabled module(s) with licenses. @@ -44,11 +47,11 @@ INFO : Base directory was modified ---- Doing this enables the MongoDB Session module and any dependent modules or files needed for it to run on the server. -The example above is running an fresh `{$jetty.base}` with nothing enabled. +The example above is running an fresh `${jetty.base}` with nothing enabled. Because MongoDB is not a technology provided by the Eclipse Foundation, users are prompted to assent to the licenses of the external vendor (Apache in this case). When the `--add-to-start` argument was added to the command line, it enabled the the `session-store-mongo` module as well as the `sessions` and `server` modules, which are required for MongoDB session management to operate.. It also downloaded the needed Mongo-specific jar file and created a directory named `${jetty.base}/lib/nosql/` to house it. -In addition to adding these modules to the classpath of the server it also added several ini configuration files to the `start.d` directory of the `{$jetty.base}`. +In addition to adding these modules to the classpath of the server it also added several ini configuration files to the `start.d` directory of the `${jetty.base}`. ____ [NOTE] @@ -65,14 +68,20 @@ Opening the `start.d/session-store-mongo.ini` will show a list of all the config # --------------------------------------- --module=session-store-mongo -#jetty.session.dbName=HttpSessions -#jetty.session.collectionName=jettySessions +#jetty.session.mongo.dbName=HttpSessions +#jetty.session.mongo.collectionName=jettySessions +#jetty.session.mongo.host=localhost +#jetty.session.mongo.port=27017 #jetty.session.gracePeriod.seconds=3600 ---- -jetty.session.dbName:: +jetty.session.mongo.dbName:: Name of the database in Mongo used to store the Session collection. -jetty.session.collectionName:: +jetty.session.mongo.collectionName:: Name of the collection in Mongo used to keep all of the Sessions. +jetty.session.mongo.host:: +Host name or address for the remote Mongo instance. +jetty.session.mongo.port:: +Port number for the remote Mongo instance. jetty.session.gracePeriod.seconds:: Amount of time, in seconds, to wait for other nodes to be checked to verify an expired session is in fact expired throughout the cluster before closing it. diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/session-hierarchy.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/session-hierarchy.adoc index 8d9c0456dff..7142a78da0c 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/session-hierarchy.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/session-hierarchy.adoc @@ -42,12 +42,18 @@ However, it is possible to provide your own implementation that never shares Ses Where the `SessionCache` handles Session information, Session data is stored in a `SessionDataStore` that is specific to the clustering technology being implemented. There is only one (1) `SessionDataStore` per `SessionCache`. +//TODO : Information on memcache-d, when to use different config options. "Configuration Scenarios?" +// Null cache, memcache, non-sticky load-balancer +// in-memory caching + Visually the Session Hierarchy can be represented like this: image::images/SessionsHierarchy.png[] ==== Configuring Sessions in the Jetty Distribution -Jetty provides support for several different Session Management/Clustering technologies including JDBC, MongoDB, Inifinispan, Google Cloud Datastore and one for local file storage. +Jetty provides support for several different Session Management technologies. +Both link:#configuring-sessions-file-system[local file storage] and in-memory session management can be implemented for standard implementations. +For implementations using clustered technologies, link:#configuring-sessions-jdbc[JDBC], link:#configuring-sessions-mongo[MongoDB], link:#configuring-sessions-infinispan[Inifinispan] and link:#configuring-sessions-gcloud[Google Cloud Datastore] are all supported. Setting up these technologies is as easy as enabling it's link:#startup-modules[module] and editing it's associated ini file with any usernames, passwords or changes you need to make for your instance. The following sections will cover how exactly to enable the required modules as well as an overview of what options are available for customization. diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/chapter.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/chapter.adoc index 2f79813b11c..c623d89464f 100644 --- a/jetty-documentation/src/main/asciidoc/administration/startup/chapter.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/startup/chapter.adoc @@ -20,8 +20,8 @@ include::startup-overview.adoc[] include::start-jar.adoc[] include::startup-base-vs-home.adoc[] -include::startup-xml-config.adoc[] include::startup-classpath.adoc[] include::startup-modules.adoc[] +include::startup-xml-config.adoc[] include::startup-unix-service.adoc[] include::startup-windows-service.adoc[] diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/start-jar.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/start-jar.adoc index a436e05694d..2d95c3d16a0 100644 --- a/jetty-documentation/src/main/asciidoc/administration/startup/start-jar.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/startup/start-jar.adoc @@ -95,40 +95,31 @@ Enables debugging output of the startup procedure. *Note*: This does not set up debug logging for Jetty itself. For information on logging, please see the section on <> --start-log-file=:: - Sends all startup output to the filename specified. -+ +Sends all startup output to the filename specified. Filename is relative to `${jetty.base}`. This is useful for capturing startup issues where the Jetty-specific logger has not yet kicked in due to a possible startup configuration error. --list-modules:: Lists all the modules defined by the system. -+ Looks for module files using the link:#startup-base-and-home[normal `${jetty.base}` and `${jetty.home}` resolution logic]. -+ Also lists enabled state based on information present on the command line, and all active startup INI files. --module=,()*:: Enables one or more modules by name (use `--list-modules` to see the list of available modules). -+ This enables all transitive (dependent) modules from the module system as well. -+ If you use this from the shell command line, it is considered a temporary effect, useful for testing out a scenario. If you want this module to always be enabled, add this command to your `${jetty.base}/start.ini.` +--create-startd:: +Creates a `${jetty.base}/start.d/` directory. +If a `${jetty.base}/start.ini` file already exists, it is copied to the `${jetty.base}/start.d` directory. --add-to-start=,()*:: Enables a module by appending lines to the `${jetty.base}/start.ini` file. -+ The lines that are added are provided by the module-defined INI templates. -+ Note: Transitive modules are also appended. ---add-to-startd=,()*:: -Enables a module via creation of a module-specific INI file in the `${jetty.base}/start.d/` directory. -+ -The content of the new INI is provided by the module-defined ini templates. -+ -Note: Transitive modules are also created in the same directory as their own INI files. [NOTE] -- With respect to `start.ini` and `start.d/*.ini` files, only *one* of these methods should be implemented. Mixing a `start.ini` with module specific ini files in the `{$jetty.base}/start.d` directory can lead to server issues unless great care is taken. +Please see link:#start-vs-startd[Start.ini vs. Start.d] for more information. -- --write-module-graph=:: diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/startup-modules.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/startup-modules.adoc index 1bfd639afa0..654d8e74c01 100644 --- a/jetty-documentation/src/main/asciidoc/administration/startup/startup-modules.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/startup/startup-modules.adoc @@ -17,7 +17,7 @@ [[startup-modules]] === Managing Startup Modules -Starting with Jetty 9.1, a new Module system was introduced, replacing the previous `start.config` + `OPTIONS` techniques from past Jetty Distributions. +Jetty 9.1 a new Module system replacing the previous `start.config` + `OPTIONS` techniques from past Jetty Distributions. The standard Jetty Distribution ships with several modules defined in `${jetty.home}/modules/`. @@ -43,7 +43,7 @@ List of Jetty IoC XML Configurations:: If the default XML is not sufficient to satisfy your needs, you can override this XML by making your own in the `${jetty.base}/etc/` directory, with the same name. The resolution steps for Jetty Base and Jetty Home will ensure that your copy from `${jetty.base}` will be picked up over the default one in `${jetty.home}`. Jetty INI Template:: - Each module can optionally declare a startup ini template that is used to insert/append/inject sample configuration elements into the `start.ini` or `start.d/*.ini` files when using the `--add-to-start=` or `--add-to-startd=` command line arguments in `start.jar`. + Each module can optionally declare a startup ini template that is used to insert/append/inject sample configuration elements into the `start.ini` or `start.d/*.ini` files when using the `--add-to-start=` command line argument in `start.jar`. Commonly used to present some of the parameterized property options from the Jetty IoC XML configuration files also referenced in the same module. The `[ini-template]` section declares this section of sample configuration. Required Files and Directories:: @@ -62,15 +62,15 @@ Download File;; [[enabling-modules]] ==== Enabling Modules -Jetty ships with many modules defined, and a small subset predefined in the `start.ini` found in the jetty distribution. - ____ [TIP] -The default distribution has a co-mingled `${jetty.home}` and `${jetty.base}`. Where the directories for `${jetty.home}` and `${jetty.base}` point to the same location. +The default distribution has a co-mingled `${jetty.home}` and `${jetty.base}` where the directories for `${jetty.home}` and `${jetty.base}` point to the same location. It is highly encouraged that you learn about the differences in link:#startup-base-and-home[Jetty Base vs Jetty Home] and take full advantage of this setup. ____ -When you want enable a module, you can use the `--module=` syntax on the command line to enable that module and all of its dependent modules. +Jetty ships with many modules defined in `${jetty.home}/modules`. +Enabling a module is a simple process: simply add the `--add-to-start` syntax on the command line. +Doing this will enable the module and any dependent modules. An example of this, with a new, empty, base directory. We can see from this output, that the directory is new. @@ -95,14 +95,95 @@ include::screen-http-webapp-deploy-listconfig.adoc[] You now have a configured and functional server, albeit with no webapps deployed. At this point you can place a webapp (war file) in the `mybase/webapps/` directory and and start Jetty. +[[start-vs-startd]] + +==== Start.ini vs. Start.d + +In the above example, when a module is activated the contents of that module file are added in `${jetty.base}/start.ini`. +As additional modules are added, their contents are appended to this file. +This can be beneficial if you want all of your module configurations in a single file, but for large server instances with lots of modules it can pose a challenge to quickly find and make changes or to remove a module. + +As an alternative to a single `start.ini` file you can opt to house modules in a `${jetty.base}/start.d` directory. +Modules activated when a `start.d` directory exists will be stored as a single file per module. +Below is an example of a fresh `${jetty.base}` that will create a `start.d` directory and activate several modules. + +[source, screen, subs="{sub-order}"] +.... +[jetty.home]$ mkdir mybase +[jetty.home]$ cd mybase/ +[mybase]$ java -jar ../start.jar --create-startd +INFO : Base directory was modified +[mybase]$ ls -all +total 0 +drwxr-xr-x 3 staff staff 102 Aug 29 15:16 . +drwxr-xr-x@ 26 staff staff 884 Aug 29 15:16 .. +drwxr-xr-x 6 staff staff 204 Aug 29 15:19 start.d + +[mybase]$ java -jar ../start.jar --add-to-start=server,client,webapp,websocket +INFO : webapp initialised in ${jetty.base}/start.d/webapp.ini +INFO : server initialised in ${jetty.base}/start.d/server.ini +INFO : websocket initialised in ${jetty.base}/start.d/websocket.ini +INFO : client initialised in ${jetty.base}/start.d/client.ini +INFO : Base directory was modified +[mybase]$ cd start.d/ +[mybase]$ ls -all +total 32 +drwxr-xr-x 6 staff staff 204 Aug 29 15:19 . +drwxr-xr-x 3 staff staff 102 Aug 29 15:16 .. +-rw-r--r-- 1 staff staff 175 Aug 29 15:19 client.ini +-rw-r--r-- 1 staff staff 2250 Aug 29 15:19 server.ini +-rw-r--r-- 1 staff staff 265 Aug 29 15:19 webapp.ini +-rw-r--r-- 1 staff staff 177 Aug 29 15:19 websocket.ini +.... + +In the example, we first create a new `${jetty.base}` and then create the `start.d` directory with the `--create-startd` command. +Next, we use the `--add-to-start` command which activates the modules and creates their respective ini files in the `start.d` directory. + +If you have an existing `start.ini` file but would like to use the `start.d` structure for additional modules, you can use the `--create-startd` command as well. +Doing this will create the `start.d` directory and copy your existing `start.ini` file in to it. +Any new modules added to the server will have their own `.ini` file created in the `start.d` directory. + +[source, screen, subs="{sub-order}"] +.... +[mybase]$ java -jar ../start.jar --add-to-start=server,client,webapp,websocket +INFO : webapp initialised in ${jetty.base}/start.ini +INFO : server initialised in ${jetty.base}/start.ini +INFO : websocket initialised in ${jetty.base}/start.ini +INFO : client initialised in ${jetty.base}/start.ini +INFO : Base directory was modified + +[mybase]$ java -jar ../start.jar --create-startd +INFO : Base directory was modified +[mybase]$ tree +. +└── start.d + └── start.ini + +[mybase]$ java -jar ../start.jar --add-to-start=ssl +INFO : ssl initialised in ${jetty.base}/start.d/ssl.ini +INFO : Base directory was modified +[mybase]$ tree +. +├── etc +│   └── keystore +└── start.d + ├── ssl.ini + └── start.ini +.... + +[NOTE] +-- +It is *not* recommended to use both a `${jetty.base}/start.ini` file and a `${jetty.base}/start.d` directory at the same time and doing so can cause issues. +-- + [[startup-configuring-modules]] ==== Configuring Modules Once a module has been enabled for the server, it can be further configured to meet your needs. This is done by editing the associated ini file for the module. -If your server setup is using a centralized ini configuration, you will edit the `{$jetty.base}/server.ini` file. -If you have elected to manage each module within it's own ini file, you can find these files in the `{$jetty.base}/start.d` directory. +If your server setup is using a centralized ini configuration, you will edit the `${jetty.base}/server.ini` file. +If you have elected to manage each module within it's own ini file, you can find these files in the `${jetty.base}/start.d` directory. When a module is activated, a number of properties are set by default. To view these defaults, open up the associated ini file. diff --git a/jetty-documentation/src/main/asciidoc/administration/tuning/high-load.adoc b/jetty-documentation/src/main/asciidoc/administration/tuning/high-load.adoc index 3e0d781d0d3..c435332b82d 100644 --- a/jetty-documentation/src/main/asciidoc/administration/tuning/high-load.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/tuning/high-load.adoc @@ -136,7 +136,7 @@ Make sure to use persistent HTTP/1.1 connections. ====== JVM Tuning -* Tune the link:garbage-collection.html#examples[Garbage Collection] +* Tune the link:#tuning-examples[Garbage Collection] * Allocate sufficient memory * Use the -server option * Jetty Tuning diff --git a/jetty-documentation/src/main/asciidoc/configuring/connectors/configuring-ssl.adoc b/jetty-documentation/src/main/asciidoc/configuring/connectors/configuring-ssl.adoc index 3510224f181..a26491a2dea 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/connectors/configuring-ssl.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/connectors/configuring-ssl.adoc @@ -24,29 +24,28 @@ This document provides an overview of how to configure SSL and TLS for Jetty. Which browser/OS supports which protocols can be https://en.wikipedia.org/wiki/Transport_Layer_Security#Web_browsers[found on Wikipedia]. -* TLS v1.1 and v1.2: The protocols which should be used wherever possible. +* TLS v1.2: The protocol which should be used wherever possible. All CBC based ciphers are supported since Java 7, the new GCM modes are supported since Java 8. ===== Older Protocols -Both TLS v1.0 and SSL v3 are no longer supported by default. If your Jetty implementation requires these protocols for legacy support, they can be enabled manually. +TLS v1.0, v1.1 and SSL v3 are no longer supported by default. If your Jetty implementation requires these protocols for legacy support, they can be enabled manually. ____ [NOTE] -Once TLS v1.3 is released, there will be no workaround available for TLS v1.0. +Once TLS v1.3 is released, there will be no workaround available for TLS v1.0 or v1.1. Plans for TLS v1.3 include banning ciphers with known vulnerabilities from being present at any level. It is recommended to upgrade any clients using these ciphers as soon as possible or face being locked into a outdated version of Jetty, Java or even OS. ____ -By default, Jetty exclused these ciphers in the link:{GITBROWSEURL}/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SslContextFactory.java#L253-L256[`SslContextFactory`.] +By default, Jetty excludes these ciphers in the link:{GITBROWSEURL}/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SslContextFactory.java#L249-L256[`SslContextFactory`.] You can re-enable these by re-declaring the ciphers you want excluded in code: [source, java, subs="{sub-order}"] ---- SslContextFactory sslContextFactory = new SslContextFactory(); sslContextFactory.setExcludeCipherSuites( - "SSL_DHE_DSS_WITH_DES_CBC_SHA", - "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"); + "^.*_(MD5|SHA|SHA1)$"); ---- If, after making these changes, you still have issues using these ciphers they are likely being blocked at the JVM level. @@ -355,6 +354,254 @@ $ keytool -importkeystore -srckeystore jetty.pkcs12 -srcstoretype PKCS12 -destke If you are updating your configuration to use a newer certificate, as when the old one is expiring, just load the newer certificate as described in the section, xref:loading-keys-and-certificates[]. If you imported the key and certificate originally using the PKCS12 method, use an alias of "1" rather than "jetty", because that is the alias the PKCS12 process enters into the keystore. +==== Configuring SSL in Jetty Distribution + +For those of you using the Jetty Distribution, enabling SSL support is as easy as activating the `ssl` module. + +An example of this setup: + +[source, plain, subs="{sub-order}"] +---- +$ cd /path/to/mybase +$ java -jar /path/to/jetty-dist/start.jar --add-to-start=ssl +INFO : server initialised (transitively) in ${jetty.base}/start.d/server.ini +INFO : ssl initialised in ${jetty.base}/start.d/ssl.ini +INFO : Base directory was modified +$ tree +. +├── etc +│   └── keystore +└── start.d + ├── server.ini + └── ssl.ini +---- + +When you open `start.d/ssl.ini`, you will see many commented properties ready for you to configure the `SslContextFactory` basics. + +To highlight some of the more commonly used properties: + +jetty.ssl.host:: + Configures which interfaces the SSL/TLS Connector should listen on. +jetty.ssl.port:: + Configures which port the SSL/TLS Connector should listen on. +jetty.httpConfig.securePort:: + If a webapp needs to redirect to a secure version of the same resource, then this is the port reported back on the response `location` line (having this be separate is useful if you have something sitting in front of Jetty, such as a Load Balancer or proxy). +jetty.sslContext.keyStorePath:: + Sets the location of the `keystore` that you configured with your certificates. +jetty.sslContext.keyStorePassword:: + Sets the Password for the `keystore`. + +[[two-way-authentication]] +==== Two Way Authentication + +To enable two-way authentication, you first need to activate the ssl module as shown in the previous section. + +[source%nowrap,ini,linenums] +.start.d/ssl.ini +---- +--module=ssl +jetty.secure.port=8443 +jetty.keystore=etc/keystore +jetty.keystore.password=OBF: +jetty.keymanager.password=OBF: +jetty.truststore=etc/truststore +jetty.truststore.password=OBF: +# enable two way authentication +jetty.ssl.needClientAuth=true +---- + +[[layout-of-keystore-and-truststore]] +===== Layout of `keystore` and `truststore` + +`keystore` only contains the server's private key and certificate. + +[source%nowrap,plain,linenums] +---- +$ keytool -list -keystore keystore -storetype jks -storepass '' -v + +Keystore type: JKS +Keystore provider: SUN + +Your keystore contains 1 entry + +Alias name: *.example.com +Creation date: Sep 12, 2016 +Entry type: PrivateKeyEntry +Certificate chain length: 1 +Certificate[1]: +Owner: CN=*.example.com, OU=Web Servers, O="Example.com Co.,Ltd.", C=CN +Issuer: CN="Example.com Co.,Ltd. ETP CA", OU=CA Center, O="Example.com Co.,Ltd.", C=CN +Serial number: b63af619ff0b4c368735113ba5db8997 +Valid from: Mon Sep 12 15:09:49 CST 2016 until: Wed Sep 12 15:09:49 CST 2018 +Certificate fingerprints: + MD5: D9:26:CC:27:77:9D:26:FE:67:4C:BE:FF:E3:95:1E:97 + SHA1: AF:DC:D2:65:6A:33:42:E3:81:9E:4D:19:0D:22:20:C7:6F:2F:11:D0 + SHA256: 43:E8:21:5D:C6:FB:A0:7D:5D:7B:9C:8B:8D:E9:4B:52:BF:50:0D:90:4F:61:C2:18:9E:89:AA:4C:C2:93:BD:32 + Signature algorithm name: SHA256withRSA + Version: 3 + +Extensions: + +#1: ObjectId: 2.5.29.35 Criticality=false +AuthorityKeyIdentifier [ +KeyIdentifier [ +0000: 44 9B AD 31 E7 FE CA D5 5A 8E 17 55 F9 F0 1D 6B D..1....Z..U...k +0010: F5 A5 8F C1 .... +] +] + +#2: ObjectId: 2.5.29.19 Criticality=true +BasicConstraints:[ + CA:false + PathLen: undefined +] + +#3: ObjectId: 2.5.29.37 Criticality=true +ExtendedKeyUsages [ + serverAuth + clientAuth +] + +#4: ObjectId: 2.5.29.15 Criticality=true +KeyUsage [ + DigitalSignature + Key_Encipherment + Data_Encipherment +] + +#5: ObjectId: 2.5.29.14 Criticality=false +SubjectKeyIdentifier [ +KeyIdentifier [ +0000: 7D 26 36 73 61 5E 08 94 AD 25 13 46 DB DB 95 25 .&6sa^...%.F...% +0010: BF 82 5A CA ..Z. +] +] + + + +******************************************* +******************************************* + +---- + +`truststore` contains intermediary CA and root CA. + +[source%nowrap,plain,linenums] +---- +$ keytool -list -keystore truststore -storetype jks -storepass '' -v + +Keystore type: JKS +Keystore provider: SUN + +Your keystore contains 2 entries + +Alias name: example.com co.,ltd. etp ca +Creation date: Sep 12, 2016 +Entry type: trustedCertEntry + +Owner: CN="Example.com Co.,Ltd. ETP CA", OU=CA Center, O="Example.com Co.,Ltd.", C=CN +Issuer: CN="Example.com Co.,Ltd. Root CA", OU=CA Center, O="Example.com Co.,Ltd.", C=CN +Serial number: f6e7b86f6fdb467f9498fb599310198f +Valid from: Wed Nov 18 00:00:00 CST 2015 until: Sun Nov 18 00:00:00 CST 2035 +Certificate fingerprints: + MD5: ED:A3:91:57:D8:B8:6E:B1:01:58:55:5C:33:14:F5:99 + SHA1: D9:A4:93:9D:A6:F8:A3:F9:FD:85:51:E2:C5:2E:0B:EE:80:E7:D0:22 + SHA256: BF:54:7A:F6:CA:0C:FA:EF:93:B6:6B:6E:2E:D7:44:A8:40:00:EC:69:3A:2C:CC:9A:F7:FE:8E:6F:C0:FA:22:38 + Signature algorithm name: SHA256withRSA + Version: 3 + +Extensions: + +#1: ObjectId: 2.5.29.35 Criticality=false +AuthorityKeyIdentifier [ +KeyIdentifier [ +0000: A6 BD 5F B3 E8 7D 74 3D 20 44 66 1A 16 3B 1B DF .._...t= Df..;.. +0010: E6 E6 04 46 ...F +] +] + +#2: ObjectId: 2.5.29.19 Criticality=true +BasicConstraints:[ + CA:true + PathLen:2147483647 +] + +#3: ObjectId: 2.5.29.15 Criticality=true +KeyUsage [ + Key_CertSign + Crl_Sign +] + +#4: ObjectId: 2.5.29.14 Criticality=false +SubjectKeyIdentifier [ +KeyIdentifier [ +0000: 44 9B AD 31 E7 FE CA D5 5A 8E 17 55 F9 F0 1D 6B D..1....Z..U...k +0010: F5 A5 8F C1 .... +] +] + + + +******************************************* +******************************************* + + +Alias name: example.com co.,ltd. root ca +Creation date: Sep 12, 2016 +Entry type: trustedCertEntry + +Owner: CN="Example.com Co.,Ltd. Root CA", OU=CA Center, O="Example.com Co.,Ltd.", C=CN +Issuer: CN="Example.com Co.,Ltd. Root CA", OU=CA Center, O="Example.com Co.,Ltd.", C=CN +Serial number: f0a45bc9972c458cbeae3f723055f1ac +Valid from: Wed Nov 18 00:00:00 CST 2015 until: Sun Nov 18 00:00:00 CST 2114 +Certificate fingerprints: + MD5: 50:61:62:22:71:60:F7:69:2E:27:42:6B:62:31:82:79 + SHA1: 7A:6D:A6:48:B1:43:03:3B:EA:A0:29:2F:19:65:9C:9B:0E:B1:03:1A + SHA256: 05:3B:9C:5B:8E:18:61:61:D1:9C:AA:0E:8C:B1:EA:44:C2:6E:67:5D:96:30:EC:8C:F6:6F:E1:EC:AD:00:60:F1 + Signature algorithm name: SHA256withRSA + Version: 3 + +Extensions: + +#1: ObjectId: 2.5.29.35 Criticality=false +AuthorityKeyIdentifier [ +KeyIdentifier [ +0000: A6 BD 5F B3 E8 7D 74 3D 20 44 66 1A 16 3B 1B DF .._...t= Df..;.. +0010: E6 E6 04 46 ...F +] +] + +#2: ObjectId: 2.5.29.19 Criticality=true +BasicConstraints:[ + CA:true + PathLen:2147483647 +] + +#3: ObjectId: 2.5.29.15 Criticality=true +KeyUsage [ + Key_CertSign + Crl_Sign +] + +#4: ObjectId: 2.5.29.14 Criticality=false +SubjectKeyIdentifier [ +KeyIdentifier [ +0000: A6 BD 5F B3 E8 7D 74 3D 20 44 66 1A 16 3B 1B DF .._...t= Df..;.. +0010: E6 E6 04 46 ...F +] +] + + + +******************************************* +******************************************* +---- + +____ +[NOTE] +If you use a keystore which contains only one `PrivateKeyEntry` item as the `keystore` and the `truststore`, you may get a `javax.net.ssl.SSLHandshakeException` with `null cert chain` message. +____ + [[configuring-sslcontextfactory]] ==== Configuring the Jetty SslContextFactory @@ -401,52 +648,17 @@ setExcludeProtocols / setIncludeProtocols:: ____ [NOTE] -When working with Includes / Excludes, it is important to know that Excludes will always win. +When working with Includes / Excludes, it is important to know that *Excludes will always win.* The selection process is to process the JVM list of available Cipher Suites or Protocols against the include list, then remove the excluded ones. Be aware that each Include / Exclude list has a Set method (replace the list) or Add method (append the list). ____ ____ [CAUTION] -The key and truststore passwords may also be set using the system properties: `org.eclipse.jetty.ssl.keypassword` `org.eclipse.jetty.ssl.password`. +The keystore and truststore passwords may also be set using the system properties: `org.eclipse.jetty.ssl.keypassword` `org.eclipse.jetty.ssl.password`. This is _not_ a recommended usage. ____ -==== Configuring SSL in Jetty Distribution - -For those of you using the Jetty Distribution, the provided modules for https and http2 will automatically setup the `SslContextFactory`, the appropriate `SslConnectionFactory`, and associated `ServerConnectors` for you in the correct order. - -An example of this setup: - -[source, plain, subs="{sub-order}"] ----- -$ cd /path/to/mybase -$ java -jar /path/to/jetty-dist/start.jar --add-to-start=https -INFO: ssl initialised (transitively) in ${jetty.base}/start.ini -INFO: https initialised in ${jetty.base}/start.ini -INFO: Base directory was modified -$ ls -l -drwxrwxr-x. 2 user group 4096 Feb 2 11:47 etc/ --rw-rw-r--. 1 user group 4259 Feb 2 11:47 start.ini -$ ls -l etc --rw-rw-r--. 1 user group 3697 Feb 2 11:47 keystore ----- - -When you check the `start.ini`, you'll see many commented properties ready for you to configure the `SslContextFactory` basics. - -To highlight some of the more commonly used properties: - -jetty.ssl.host:: - Configures which interfaces the SSL/TLS Connector should listen on. -jetty.ssl.port:: - Configures which port the SSL/TLS Connector should listen on. -jetty.httpConfig.securePort:: - If a webapp needs to redirect to a secure version of the same resource, then this is the port reported back on the response `location` line (having this be separate is useful if you have something sitting in front of Jetty, such as a Load Balancer or proxy). -jetty.sslContext.keyStorePath:: - Sets the location of the `keystore` that you configured with your certificates. -jetty.sslContext.keyStorePassword:: - Sets the Password for the `keystore`. - ==== Configuring SNI From Java 8, the JVM contains support for the http://en.wikipedia.org/wiki/Server_Name_Indication[Server Name Indicator (SNI)] extension, which allows a SSL connection handshake to indicate one or more DNS names that it applies to. diff --git a/jetty-documentation/src/main/asciidoc/configuring/connectors/setting-port80-access-for-non-root-user.adoc b/jetty-documentation/src/main/asciidoc/configuring/connectors/setting-port80-access-for-non-root-user.adoc index 998ec6f4199..976d45dbf1c 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/connectors/setting-port80-access-for-non-root-user.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/connectors/setting-port80-access-for-non-root-user.adoc @@ -81,8 +81,8 @@ For more information on the alternatives see the section on link:#startup-module ____ . Edit the configuration for the `setuid` module to substitute the `userid` and `groupid` of the user to switch to after starting. -If you used the `--add-to-start` command, this configuration is in the `start.ini` file. -If you used the `--add-to-startd` command instead, this configuration is in the `start.d/setuid.ini` file instead. +If your server instance has a `${jetty.base/start.d}` directory, this configuration is in the `start.d/setuid.ini` file instead. +Otherwise. this configuration is in the `${jetty.base}start.ini` file. Below are the lines to configure: + diff --git a/jetty-documentation/src/main/asciidoc/configuring/deploying/quickstart-webapp.adoc b/jetty-documentation/src/main/asciidoc/configuring/deploying/quickstart-webapp.adoc index a9c15ea735d..c7cacca4760 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/deploying/quickstart-webapp.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/deploying/quickstart-webapp.adoc @@ -21,7 +21,7 @@ The auto discovery features of the Servlet specification can make deployments sl Auto discovery of Web Application configuration can be useful during the development of a webapp as it allows new features and frameworks to be enabled simply by dropping in a jar file. However, for deployment, the need to scan the contents of many jars can have a significant impact of the start time of a webapp. -From Jetty release 9.2.0.v20140526, the included quickstart module allows a webapp to be pre-scanned and preconfigured. +With the release of Jetty 9.2, a quickstart module was included which allows a webapp to be pre-scanned and preconfigured. This means that all the scanning is done prior to deployment and all configuration is encoded into an effective `web.xml`, called `WEB-INF/quickstart-web.xml`, which can be inspected to understand what will be deployed before deploying. Not only does the `quickstart-web.xml` contain all the discovered Servlets, Filters and Constraints, but it also encodes as context parameters all discovered: @@ -31,33 +31,91 @@ Not only does the `quickstart-web.xml` contain all the discovered Servlets, Filt With the quickstart mechanism, Jetty is able to entirely bypass all scanning and discovery modes and start a webapp in a predictable and fast way. Tests have shown that webapps that took many seconds to scan and deploy can now be deployed in a few hundred milliseconds. +Additionally, if debug logging is enabled, the generated quickstart information is tagged with the origin of every element, which can be useful for debugging purposes. ==== Setting up Quickstart -To use quickstart the module has to be available to the Jetty instance. -In a maven project this is done by adding a dependency on the artifact ID `jetty-quickstart`. -In a standard Jetty distribution it can be configured with the following command: +===== Prerequisites + +====== Jetty Distribution + +In a standard Jetty distribution the quickstart module can be configured with the following command: [source, screen, subs="{sub-order}"] ---- -$ java -jar $JETTY_HOME/start.jar --add-to-startd=quickstart +$ java -jar $JETTY_HOME/start.jar --add-to-start=quickstart ---- -Deployed webapps need to be instances of link:{JDURL}/org/eclipse/jetty/quickstart/QuickStartWebApp.html[`org.eclipse.jetty.quickstart.QuickStartWebApp`] rather than the normal `org.eclipse.jetty.webapp.WebAppContext`. -If a web application already has a `webapps/myapp.xml` file, simply change the class in the Configure element. -Otherwise, create a `webapps/myapp.xml` file as follows: +====== Embedded + +In a Maven project you add a dependency on the artifact `jetty-quickstart`. + +[source, xml, subs="{sub-order}"] +---- + + org.eclipse.jetty + jetty-quickstart + {VERSION} + +---- + + + +===== Configuration + +Webapps need to be instances of link:{JDURL}/org/eclipse/jetty/quickstart/QuickStartWebApp.html[`org.eclipse.jetty.quickstart.QuickStartWebApp`] rather than the normal `org.eclipse.jetty.webapp.WebAppContext`. + +`org.eclipse.jetty.quickstart.QuickStartWebApp` instances offer the same setters as the familiar `org.eclipse.jetty.webapp.WebAppContext`, with the addition of: + +autoPreconfigure:: + (true/false). + If true, the first time the webapp is run, the WEB-INF/quickstart-web.xml is generated BEFORE the webapp is deployed. + Subsequent runs use the previously generated quickstart file. + +====== In XML +If a web application already has a context xml file, eg `webapps/myapp.xml` file, simply change the class in the `Configure` element. +Otherwise, create a context xml file with the following information (in addition to the usual setting of contextPath, war etc): [source, xml, subs="{sub-order}"] ---- - + - /benchmark.war - /benchmark true ---- +====== In Code + +Create an instance of link:{JDURL}/org/eclipse/jetty/quickstart/QuickStartWebApp.html[`org.eclipse.jetty.quickstart.QuickStartWebApp`] rather than the normal `org.eclipse.jetty.webapp.WebAppContext`. You then use the QuickStartWebApp instance in exactly the same way that you would a WebAppContext. + +Here's a snippet: + +[source, java] +---- + QuickStartWebApp webapp = new QuickStartWebApp(); + webapp.setAutoPreconfigure(true); +---- + + +====== Pre-generating the quickstart-web.xml file + +Rather than use the `autoPreconfigure` feature of the QuickStartWebApp - which lazily generates the `quickstart-web.xml` file - you can eagerly pre-generate it for an existing war by invoking as a main class link:{JDURL}/org/eclipse/jetty/quickstart/PreconfigureQuickStartWar.html[`org.eclipse.jetty.quickstart.PreconfigureQuickStartWar`]. +Note that you will need to provide all necessary jetty jars on the command line classpath. +This will unpack the war if necessary, and create the `quickstart-web.xml` before the first deployment: + + +[source, screen, subs="{sub-order}"] +---- +$ java -cp [jetty classpath] org.eclipse.jetty.quickstart.PreconfigureQuickStartWar myapp.war +---- + +Run the class with no arguments to see other runtime options. + +Alternatively, you could use the link:#get-up-and-running[Jetty Maven Plugin] goal link:#jetty-effective-web-xml[`jetty:effective-web-xml`]: this will generate quickstart information, but print it to stderr. +The goal provides a configuration option to save the output to a file, which you can then copy into your webapp's WEB-INF dir. +Note that as the Jetty Maven Plugin is a general tool for running webapps, it may have more jars on its classpath than are needed by your application, and thus may generate extra quickstart information: we recommend that you use this goal only as a quick guide to the type of information that quickstart generates. + // ==== Preconfiguring the web application // // If the `QuickStateWebApp` method `setAutoPreconfigure(true)` is called (see example in myapp.xml above), then the first time the webapp is deployed a `WEB-INF/quickstart-web.xml` file will be generated that contains the effective `web.xml` for all the discovered configuration. @@ -65,14 +123,8 @@ Otherwise, create a `webapps/myapp.xml` file as follows: // // It is also possible to preconfigure a war file manually by running the class link:{JDURL}/org/eclipse/jetty/quickstart/PreconfigureQuickStartWar.html[org.eclipse.jetty.quickstart.PreconfigureQuickStartWar] with the jetty-all-uber (aggregate) jar: // -// [source, screen, subs="{sub-order}"] -// ---- -// $ java -cp jetty-all-{VERSION}-uber.jar org.eclipse.jetty.quickstart.PreconfigureQuickStartWar myapp.war -// ---- // // This will create the `quickstart-web.xml` file before the first deployment. -// Note that this can also be a good debugging tool for discovered configuration and if run with debug turned on the origin of every element is included in the `quickstart-web.xml` file. -// Run the class with no arguments to see other runtime options. ==== Avoiding TLD Scans with precompiled JSPs diff --git a/jetty-documentation/src/main/asciidoc/configuring/security/jaas-support.adoc b/jetty-documentation/src/main/asciidoc/configuring/security/jaas-support.adoc index 8dfb189ab1b..50020f42f04 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/security/jaas-support.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/security/jaas-support.adoc @@ -148,10 +148,10 @@ There are 2 aspects to this: To accomplish the above, use the Jetty link:#startup-overview[startup] link:#startup-modules[modules mechanism] to add the JAAS link:#startup-modules[module]: -[source,bash] ----- -java -jar start.jar --add-to-startd=jaas ----- +[source, screen, subs="{sub-order}"] +.... +java -jar start.jar --add-to-start=jaas +.... ____ [NOTE] diff --git a/jetty-documentation/src/main/asciidoc/development/frameworks/spring-usage.adoc b/jetty-documentation/src/main/asciidoc/development/frameworks/spring-usage.adoc index 9b0c57feb74..b8aff850236 100644 --- a/jetty-documentation/src/main/asciidoc/development/frameworks/spring-usage.adoc +++ b/jetty-documentation/src/main/asciidoc/development/frameworks/spring-usage.adoc @@ -28,7 +28,7 @@ For example: [source, screen, subs="{sub-order}"] .... -$ java -jar start.jar --add-to-startd=spring +$ java -jar start.jar --add-to-start=spring .... This (or the alternative link:#start-jar[--add-to-start]=spring command) creates a `${jetty.home}/lib/spring` directory and populates it with the jetty-spring integration jar. @@ -42,7 +42,7 @@ The following is an example mimicking the default jetty startup configuration. [source, xml, subs="{sub-order}"] ---- - + @@ -98,5 +98,5 @@ The following is an example mimicking the default jetty startup configuration. - + ---- diff --git a/jetty-documentation/src/main/asciidoc/development/maven/jetty-maven-plugin.adoc b/jetty-documentation/src/main/asciidoc/development/maven/jetty-maven-plugin.adoc index c0db940dcea..2edd474e926 100644 --- a/jetty-documentation/src/main/asciidoc/development/maven/jetty-maven-plugin.adoc +++ b/jetty-documentation/src/main/asciidoc/development/maven/jetty-maven-plugin.adoc @@ -723,6 +723,7 @@ mvn jetty:stop The `stopPort` must be free on the machine you are running on. If this is not the case, you will get an "Address already in use" error message after the "Started ServerConnector ..." message. +[[jetty-effective-web-xml]] ==== jetty:effective-web-xml This goal calculates a synthetic `web.xml` (the "effective web.xml") according to the rules of the Servlet Specification taking into account all sources of discoverable configuration of web components in your application: descriptors (`webdefault.xml`, `web.xml`, `web-fragment.xml`s, `web-override.xml`) and discovered annotations (`@WebServlet`, `@WebFilter`, `@WebListener`). diff --git a/jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-running.adoc b/jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-running.adoc index d5301f0a0d3..97b15f32440 100644 --- a/jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-running.adoc +++ b/jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-running.adoc @@ -32,9 +32,9 @@ To start Jetty on the default port of 8080, run the following command: 2015-06-04 10:50:45.030:INFO:oejs.Server:main: Started @558ms ---- -You can point a browser at this server at link:http://localhost:8080[]. -However, as there are no webapps deployed in the $JETTY_HOME directory, you will see a 404 error page served by Jetty. -*Note* the HomeBase warning - it is _not_ recommended to run Jetty from the $JETTY_HOME directory. +You can point a browser at this server at link:http://localhost:8080[]. +However, as there are no webapps deployed in the $JETTY_HOME directory, you will see a 404 error page served by Jetty. +*Note* the HomeBase warning - it is _not_ recommended to run Jetty from the $JETTY_HOME directory. Instead, see how to link:#creating-jetty-base[create a Jetty Base] below. [[demo-webapps-base]] @@ -89,15 +89,15 @@ You can see the configuration of the demo-base by using the following commands: ... ---- - The `--list-modules` command will return a complete list of available and enabled modules for the server. - It will also display the location of the modules, how and in what order they are implemented, dependent modules, and associated jar files. + The `--list-modules` command will return a complete list of available and enabled modules for the server. + It will also display the location of the modules, how and in what order they are implemented, dependent modules, and associated jar files. The `--list-config` command displays a trove of information about the server including the Java and Jetty environments, the configuration order, any JVM arguments or System Properties set, general server properties, a full listing of the Jetty server class path, and active Jetty XML files. [[creating-jetty-base]] ==== Creating a new Jetty Base -The `demo-base` directory described above is an example of the link:#startup-base-and-home[jetty.base] mechanism added in Jetty 9.1. -A Jetty base directory allows the configuration and web applications of a server instance to be stored separately from the Jetty distribution, so that upgrades can be done with minimal disruption. +The `demo-base` directory described above is an example of the link:#startup-base-and-home[jetty.base] mechanism added in Jetty 9.1. +A Jetty base directory allows the configuration and web applications of a server instance to be stored separately from the Jetty distribution, so that upgrades can be done with minimal disruption. Jetty's default configuration is based on two properties: jetty.home:: @@ -127,7 +127,9 @@ WARNING: Nothing to start, exiting ... Usage: java -jar start.jar [options] [properties] [configs] java -jar start.jar --help # for more information -> java -jar $JETTY_HOME/start.jar --add-to-startd=http,deploy +> java -jar $JETTY_HOME/start.jar --create-startd +INFO : Base directory was modified +> java -jar $JETTY_HOME/start.jar --add-to-start=http,deploy INFO: server initialised (transitively) in ${jetty.base}/start.d/server.ini INFO: http initialised in ${jetty.base}/start.d/http.ini @@ -163,7 +165,7 @@ You can configure Jetty to run on a different port by setting the `jetty.http.po ... ---- -Alternatively, property values can be added to the effective command line built from either the `start.ini` file or `start.d/http.ini` files. +Alternatively, property values can be added to the effective command line built from either the `start.ini` file or `start.d/http.ini` files. By default, the Jetty distribution defines the `jetty.http.port` property in the `start.d/http.ini` file, which may be edited to set another value. ____ @@ -186,7 +188,7 @@ To add HTTPS and HTTP2 connectors to a Jetty configuration, the modules can be a [source, screen, subs="{sub-order}"] ---- -> java -jar $JETTY_HOME/start.jar --add-to-startd=https,http2 +> java -jar $JETTY_HOME/start.jar --add-to-start=https,http2 [...] > java -jar $JETTY_HOME/start.jar @@ -196,7 +198,7 @@ To add HTTPS and HTTP2 connectors to a Jetty configuration, the modules can be a [...] ---- -The `--add-to-startd` command sets up the effective command line in the ini files to run an ssl connection that supports the HTTPS and HTTP2 protocols as follows: +The `--add-to-start` command sets up the effective command line in the ini files to run an ssl connection that supports the HTTPS and HTTP2 protocols as follows: * creates `start.d/ssl.ini` that configures an SSL connector (eg port, keystore etc.) by adding `etc/jetty-ssl.xml` and `etc/jetty-ssl-context.xml` to the effective command line. * creates `start.d/alpn.ini` that configures protocol negotiation on the SSL connector by adding `etc/jetty-alpn.xml` to the effective command line. @@ -204,11 +206,6 @@ The `--add-to-startd` command sets up the effective command line in the ini file * creates `start.d/http2.ini` that configures the HTTP/2 protocol on the SSL connector by adding `etc/jetty-http2.xml` to the effective command line. * checks for the existence of a `etc/keystore` file and if not present, downloads a demonstration keystore file. -____ -[NOTE] -If a single `start.ini` file is preferred over individual `start.d/*.ini` files, then the option --add-to-start=module may be used to append the module activation to the start.ini file rather than create a file in start.d -____ - [[quickstart-changing-https-port]] ===== Changing the Jetty HTTPS Port @@ -220,13 +217,12 @@ You can configure the SSL connector to run on a different port by setting the `j > java -jar $JETTY_HOME/start.jar jetty.ssl.port=8444 ---- -Alternatively, property values can be added to the effective command line built from the `start.ini` file and `start.d/*.ini` files. -If you used the `--add-to-startd` command to enable HTTPS , then you can edit this property in the `start.d/https.ini` file. -If you used `--add-to-start` command, then you can edit this property in the `start.ini` file. +Alternatively, property values can be added to the effective command line built from the `start.ini` file or `start.d/*.ini` files, depending on your set up. +Please see the section on link:#start-vs-startd[Start.ini vs. Start.d] for more information. ==== More start.jar options -The job of the `start.jar` is to interpret the command line, `start.ini` and `start.d` directory (and associated .ini files) to build a Java classpath and list of properties and configuration files to pass to the main class of the Jetty XML configuration mechanism. +The job of the `start.jar` is to interpret the command line, `start.ini` and `start.d` directory (and associated .ini files) to build a Java classpath and list of properties and configuration files to pass to the main class of the Jetty XML configuration mechanism. The `start.jar` mechanism has many options which are documented in the xref:startup[] administration section and you can see them in summary by using the command: [source, screen, subs="{sub-order}"] diff --git a/jetty-documentation/src/main/asciidoc/quick-start/introduction/what-version.adoc b/jetty-documentation/src/main/asciidoc/quick-start/introduction/what-version.adoc index e43193a8f06..a4657f313cb 100644 --- a/jetty-documentation/src/main/asciidoc/quick-start/introduction/what-version.adoc +++ b/jetty-documentation/src/main/asciidoc/quick-start/introduction/what-version.adoc @@ -27,7 +27,8 @@ While many people continue to use older versions of Jetty, we generally recommen |Version |Year |Home |JVM |Protocols |Servlet |JSP |Status |9.3 |2015 |Eclipse |1.8 |HTTP/1.1 (RFC 7230), HTTP/2 (RFC 7540), WebSocket (RFC 6455, JSR 356), FastCGI |3.1 |2.3 |Stable |9.2 |2014 |Eclipse |1.7 |HTTP/1.1 RFC2616, javax.websocket, SPDY v3 |3.1 |2.3 |Stable -|8 |2009- |Eclipse/Codehaus |1.6 |HTTP/1.1 RFC2616, WebSocket RFC 6455, SPDY v3 |3.0 |2.2 |Venerable +|8.2 |2009- |Eclipse/Codehaus |1.7 |HTTP/1.1 RFC2616, WebSocket RFC 6455, SPDY v3 |3.0 |2.2 |Venerable +|8.1 |2009- |Eclipse/Codehaus |1.6 |HTTP/1.1 RFC2616, WebSocket RFC 6455, SPDY v3 |3.0 |2.2 |Venerable |7 |2008- |Eclipse/Codehaus |1.5 |HTTP/1.1 RFC2616, WebSocket RFC 6455, SPDY v3 |2.5 |2.1 |Venerable |6 |2006-2010 |Codehaus |1.4-1.5 |HTTP/1.1 RFC2616 |2.5 |2.0 |Deprecated |5 |2003-2009 |Sourceforge |1.2-1.5 |HTTP/1.1 RFC2616 |2.4 |2.0 |Deprecated diff --git a/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-web-xml-config.adoc b/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-web-xml-config.adoc index 154518ab115..4d42bfb6b49 100644 --- a/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-web-xml-config.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-web-xml-config.adoc @@ -30,15 +30,12 @@ For a more in-depth look at the syntax, see xref:jetty-xml-syntax[]. [source, xml, subs="{sub-order}"] ---- - .. - - ---- ____ diff --git a/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-xml-syntax.adoc b/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-xml-syntax.adoc index 6915889615a..cae32fe2abb 100644 --- a/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-xml-syntax.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-xml-syntax.adoc @@ -53,7 +53,7 @@ The following XML configuration file creates some Java objects and sets some att demo2 - + ---- The XML above is equivalent to the following Java code: @@ -72,7 +72,7 @@ bar.init(false); foo.setNested(bar); bar.setWibble(20); -bar.getParent().setName("demo2"); +bar.getParent().setName("demo2"); ---- ==== Overview @@ -80,41 +80,27 @@ bar.getParent().setName("demo2"); ===== Understanding DTD and Parsing The document type descriptor -(link:{GITBROWSEURL}/jetty-xml/src/main/resources/org/eclipse/jetty/xml/configure_9_0.dtd?h=release-9[configure.dtd]) -describes all valid elements in a Jetty XML configuration file using the -Jetty IoC format. The first two lines of an XML must reference the DTD -to be used to validate the XML like: +(link:{GITBROWSEURL}/jetty-xml/src/main/resources/org/eclipse/jetty/xml/configure_9_0.dtd?h=release-9[configure.dtd]) describes all valid elements in a Jetty XML configuration file using the Jetty IoC format. +The first two lines of an XML must reference the DTD to be used to validate the XML like: [source, xml, subs="{sub-order}"] ---- - ... - - ---- -Typcically a good XML editor will fetch the DTD from the URL and use it -to give syntax highlighting and validation while a configuration file is -being edited. Some editors also allows DTD files to be locally cached. -The URL may point to configure.dtd if you want the latest current -version, or to a specific version like configure_9_0.dtd if you want a -particular validation feature set. +Typcically a good XML editor will fetch the DTD from the URL and use it to give syntax highlighting and validation while a configuration file is being edited. +Some editors also allows DTD files to be locally cached. +The URL may point to configure.dtd if you want the latest current version, or to a specific version like configure_9_0.dtd if you want a particular validation feature set. -Files that conform to the configure.dtd format are processed in Jetty by -the `XmlConfiguration` class which may also validate the XML (using a -version of the DTD from the classes jar file), but is by default run in -a forgiving mode that tries to work around validation failures. +Files that conform to the configure.dtd format are processed in Jetty by the `XmlConfiguration` class which may also validate the XML (using a version of the DTD from the classes jar file), but is by default run in a forgiving mode that tries to work around validation failures. ===== Jetty XML Configuration Scope -The configuration of object instances with Jetty IoC XML is done on a -scoped basis, so that for any given XML element there is a corresponding -Object in scope and the nested XML elements apply to that. The outer -most scope is given by a Configure element and elements like Call, New -and Get establish new scopes. The following example uses the name fields -to explain the scope +The configuration of object instances with Jetty IoC XML is done on a scoped basis, so that for any given XML element there is a corresponding Object in scope and the nested XML elements apply to that. +The outer most scope is given by a Configure element and elements like Call, New and Get establish new scopes. +The following example uses the name fields to explain the scope. [source, xml, subs="{sub-order}"] ---- @@ -134,50 +120,36 @@ to explain the scope - ---- ===== Coercing Arguments to a Type -When trying to match XML elements to java elements, Jetty -XmlConfiguration may need to coerces values to match method arguments. -By default it does so on a best effort basis, but you can also specify -explicit types with the `type` attribute. Supported values for type are: -String, Character, Short, Byte, Integer, Long, Boolean, Float, Double, -char, short, byte, int, long, boolean, float, double, URL, InetAddress, -InetAddrPort, void +When trying to match XML elements to java elements, Jetty `XmlConfiguration` may need to coerces values to match method arguments. +By default it does so on a best effort basis, but you can also specify explicit types with the `type` attribute. +Supported values for type are: `String`, `Character`, `Short`, `Byte`, `Integer`, `Long`, `Boolean`, `Float`, `Double`, `char`, `short`, `byte`, `int`, `long`, `boolean`, `float`, `double`, `URL`, `InetAddress`, `InetAddrPort`, and `void`. ===== Referring to a Class -If you do not specify the classname, Jetty assumes you are calling the -method on the object that is current in scope (eg the object of the -surrounding Configure, New or Get clause). If the class attribute is -specified to a fully-qualified class name, then it is either used to -create a new instance (Configure and New elements) or is used to access -a static (Call, Set or Get elements). +If you do not specify the classname, Jetty assumes you are calling the method on the object that is current in scope (eg the object of the surrounding `Configure`, `New` or `Get` clause). +If the class attribute is specified to a fully-qualified class name, then it is either used to create a new instance (`Configure` and `New` elements) or is used to access a static (`Call`, `Set` or `Get` elements). ===== Referring to an Object -You can use the id attribute to store a reference to the current object -when first creating or referring to this object. You can then use the -link:#jetty-xml-ref[Ref element] to reference the object later. The id -must be unique for each object you create. +You can use the id attribute to store a reference to the current object when first creating or referring to this object. +You can then use the link:#jetty-xml-ref[Ref element] to reference the object later. +The ID must be unique for each object you create. ===== Attribute vs Element Style -For XML elements that contain only other XML Elements, there is a choice -of using attributes or elements style. The following is an example of -attribute style: +For XML elements that contain only other XML Elements, there is a choice of using attributes or elements style. +The following is an example of attribute style: .... .... -Attribute style has the benefit of brevity, but is limited by: values -can only be Strings; multivalued items can not contain ','; values may -not be subject to property expansion or other elements that return -values. Thus the more verbose element style is available and the -following is semantically equivalent to the attribute style above: +Attribute style has the benefit of brevity, but is limited by: values can only be Strings; multivalued items can not contain ','; values may not be subject to property expansion or other elements that return values. +Thus, the more verbose element style is available and the following is semantically equivalent to the attribute style above: .... @@ -189,11 +161,8 @@ following is semantically equivalent to the attribute style above: .... -Note that multivalued elements like Arg, must be repeated and may not be -comma separated like they are when provided as attributes. It is -possible to use a mix of styles and the following example shows a more -typical example that uses property expansion as the reason for element -style: +Note that multivalued elements like `Arg` must be repeated and may not be comma-separated like they are when provided as attributes. +It is possible to use a mix of styles and the following example shows a moretypical example that uses property expansion as the reason for element style: .... @@ -205,16 +174,14 @@ style: .... -Attributes may not be expressed as elements when their parent element is -one that contains data. Thus Arg, Item, Set, Put and Get elements may -not have their attributes expressed as elements. +Attributes may not be expressed as elements when their parent element is one that contains data. +Thus `Arg`, `Item`, `Set`, `Put` and `Get` elements may not have their attributes expressed as elements. [[jetty-xml-configure]] ==== -This is the root element that specifies the class of object that is to -be configured. It is usually either the Server, in `jetty.xml`, or a -WebAppContext in `jetty-web.xml`. +This is the root element that specifies the class of object that is to be configured. +It is usually either the Server, in `jetty.xml`, or a `WebAppContext` in `jetty-web.xml`. [cols=",,",options="header",] |======================================================================= @@ -226,8 +193,8 @@ You can use this to break up configuration of an object (such as the Server) across multiple files. |class |no |The fully qualified classname of the object to be -configured. Could be org.eclipse.jetty.server.Server, -org.eclipse.jetty.webapp.WebAppContext, a handler, etc. +configured. Could be `org.eclipse.jetty.server.Server`, +`org.eclipse.jetty.webapp.WebAppContext`, a handler, etc. |======================================================================= ===== Can Contain @@ -246,7 +213,7 @@ link:#jetty-xml-property[Property element] ---- 8080 - + ---- This is equivalent to: @@ -254,46 +221,43 @@ This is equivalent to: [source, java, subs="{sub-order}"] ---- org.eclipse.jetty.server.Server server = new org.eclipse.jetty.server.Server(); -server.setPort(8080); +server.setPort(8080); ---- -====== Using id to break up configuration of one object across multiple -files +====== Using id to break up configuration of one object across multiple files -(etc/jetty.xml) +In `etc/jetty.xml`: [source, xml, subs="{sub-order}"] ---- - + ---- -(etc/jetty-logging.xml) +In `etc/jetty-logging.xml`: [source, xml, subs="{sub-order}"] ---- - + ---- Then run the combined configuration using: .... -java -jar start.jar etc/jetty.xml jetty-logging.xml +java -jar start.jar etc/jetty.xml jetty-logging.xml .... [[jetty-xml-set]] ==== -A Set element maps to a call to a setter method or field on the current -object. It can contain text and/or elements such as Call, New, -SystemProperty, etc., as values. The name and optional type attributes -are used to select the setter method. If you do not specify a value -type, white space is trimmed out of the value. If it contains multiple -elements as values, they are added as strings before being converted to -any specified type. +A Set element maps to a call to a setter method or field on the current object. +It can contain text and/or elements such as `Call`, `New`, `SystemProperty`, etc., as values. +The name and optional type attributes are used to select the setter method. +If you do not specify a value type, white space is trimmed out of the value. +If it contains multiple elements as values, they are added as strings before being converted to any specified type. [cols=",,",options="header",] |======================================================================= @@ -325,7 +289,7 @@ link:#jetty-xml-property[Property element] ---- 8080 - + ---- ====== Set via a System Property @@ -334,7 +298,7 @@ link:#jetty-xml-property[Property element] ---- - + ---- ====== Creating a NewObject and Setting It on the Server @@ -348,7 +312,7 @@ link:#jetty-xml-property[Property element] 1000 - + ---- This is equivalent to: @@ -361,7 +325,7 @@ org.eclipse.jetty.util.thread.QueuedThreadPool threadPool = new org.eclipse.jett threadPool.setMinThreads(10); threadPool.setMaxThreads(1000); -server.setThreadPool(threadPool); +server.setThreadPool(threadPool); ---- ====== Invoking a Static Setter @@ -370,15 +334,14 @@ server.setThreadPool(threadPool); ---- loggerName - + ---- [[jetty-xml-get]] ==== -A Get element maps to a call to a getter method or field on the current -object. It can contain nested elements such as Set, Put, Call, etc.; -these act on the object returned by the Get call. +A Get element maps to a call to a getter method or field on the current object. +It can contain nested elements such as `Set`, `Put`, `Call`, etc.; these act on the object returned by the `Get` call. [cols=",,",options="header",] |======================================================================= @@ -406,14 +369,14 @@ link:#jetty-xml-property[Property element] ====== Basic Example -This simple example doesn't do much on its own. You would normally use -this in conjunction with a . +This simple example doesn't do much on its own. +You would normally use this in conjunction with a ``. [source, xml, subs="{sub-order}"] ---- - + ---- ====== Invoking a Static Getter and Call Methods on the Returned Object @@ -426,18 +389,16 @@ this in conjunction with a . Server version is: - + ---- [[jetty-xml-put]] ==== -A Put element maps to a call to a put method on the current object, -which must implement the Map interface. It can contain text and/or -elements such as Call, New, SystemProperty, etc. as values. If you do -not specify a no value type, white space is trimmed out of the value. If -it contains multiple elements as values, they are added as strings -before being converted to any specified type. +A Put element maps to a call to a put method on the current object, which must implement the Map interface. +It can contain text and/or elements such as `Call`, `New`, `SystemProperty`, etc. as values. +If you do not specify a no value type, white space is trimmed out of the value. +If it contains multiple elements as values, they are added as strings before being converted to any specified type. [cols=",,",options="header",] |======================================================================= @@ -450,7 +411,7 @@ Arg for how to define null and empty string values. ===== Can Contain -value text , link:#jetty-xml-get[Get element], link:#jetty-xml-call[Call +value text, link:#jetty-xml-get[Get element], link:#jetty-xml-call[Call element], link:#jetty-xml-new[New element], link:#jetty-xml-ref[Ref element], link:#jetty-xml-array[Array element], link:#jetty-xml-map[Map element], link:#jetty-xml-system-property[System Property element], @@ -462,17 +423,15 @@ link:#jetty-xml-property[Property element] ---- objectValue - + ---- [[jetty-xml-call]] ==== -A Call element maps to an arbitrary call to a method on the current -object. It can contain a sequence of Arg elements followed by a sequence -of configuration elements, such as Set, Put, Call. The s are passed -as arguments to the method; the sequence of configuration elements act -on the object returned by the original call. +A `Call` element maps to an arbitrary call to a method on the current object. +It can contain a sequence of Arg elements followed by a sequence of configuration elements, such as Set, Put, Call. +The s are passed as arguments to the method; the sequence of configuration elements act on the object returned by the original call. [cols=",,",options="header",] |======================================================================= @@ -507,7 +466,7 @@ element], link:#jetty-xml-property[Property element] bar 1, 2, 3 - + ---- This is equivalent to: @@ -515,7 +474,7 @@ This is equivalent to: [source, java, subs="{sub-order}"] ---- Object o2 = o1.doFoo("bar"); -o2.setTest("1, 2, 3"); +o2.setTest("1, 2, 3"); ---- ====== Invoking a static method @@ -524,14 +483,14 @@ o2.setTest("1, 2, 3"); ---- somestring - + ---- -which is equivalent to: +Which is equivalent to: [source, java, subs="{sub-order}"] ---- -com.acme.Foo.setString("somestring"); +com.acme.Foo.setString("somestring"); ---- ====== Invoking the Actual MethodInstead of Relying on Getter/Setter Magic @@ -545,15 +504,15 @@ com.acme.Foo.setString("somestring"); - + ---- -which is equivalent to: +Which is equivalent to: [source, java, subs="{sub-order}"] ---- org.mortbay.jetty.Server server = new org.mortbay.jetty.Server(); -com.acme.Environment.setPort( server.getPort() ); +com.acme.Environment.setPort( server.getPort() ); ---- [[jetty-xml-arg]] @@ -562,13 +521,11 @@ com.acme.Environment.setPort( server.getPort() ); An Arg element can be an argument of either a method or a constructor. Use it within xref:jetty-syntax-call[] and xref:jetty-syntax-new[]. -It can contain text and/or elements, such as Call, New, SystemProperty, -etc., as values. The optional type attribute can force the type of the -value. If you don't specify a type, white space is trimmed out of the -value. If it contains multiple elements as values, they are added as -strings before being converted to any specified type. Simple String -arguments can also be specified as a string separated arg attribute on -the parent element. +It can contain text and/or elements, such as `Call`, `New`, `SystemProperty`, etc., as values. +The optional type attribute can force the type of the value. +If you don't specify a type, white space is trimmed out of the value. +If it contains multiple elements as values, they are added as strings before being converted to any specified type. +Simple `String` arguments can also be specified as a string separated arg attribute on the parent element. [cols=",,",options="header",] |======================================================================= @@ -597,7 +554,7 @@ link:#jetty-xml-property[Property element] 1 - ---- ====== Coercing Type @@ -606,13 +563,12 @@ This explicitly coerces the type to a boolean: [source, xml, subs="{sub-order}"] ---- -False +False ---- ====== As a Parameter -Here are a couple of examples of link:#jetty-xml-arg[Arg element] being -used as a parameter to methods and to constructors: +Here are a couple of examples of link:#jetty-xml-arg[Arg element] being used as a parameter to methods and to constructors: [source, xml, subs="{sub-order}"] ---- @@ -622,14 +578,14 @@ used as a parameter to methods and to constructors: bar - + ---- This is equivalent to: [source, java, subs="{sub-order}"] ---- -com.acme.Environment.setFoo(new com.acme.Foo("bar")); +com.acme.Environment.setFoo(new com.acme.Foo("bar")); ---- [source, xml, subs="{sub-order}"] @@ -640,26 +596,24 @@ com.acme.Environment.setFoo(new com.acme.Foo("bar")); 2 - + ---- This is equivalent to: [source, java, subs="{sub-order}"] ---- -new com.acme.Baz(com.acme.MyStaticObjectFactory.createObject(2)); +new com.acme.Baz(com.acme.MyStaticObjectFactory.createObject(2)); ---- [[jetty-xml-new]] ==== -Instantiates an object. Equivalent to new in Java, and allows the -creation of a new object. A New element can contain a sequence of -link:#jetty-xml-arg[Arg element]'s, followed by a sequence of -configuration elements (Set, Put, etc). link:#jetty-xml-arg[Arg -element]'s are used to select a constructor for the object to be -created. The sequence of configuration elements then acts on the -newly-created object. +Instantiates an object. +Equivalent to `new` in Java, and allows the creation of a new object. +A `New` element can contain a sequence of link:#jetty-xml-arg[`Arg` element]'s, followed by a sequence of configuration elements (`Set`, `Put`, etc). +link:#jetty-xml-arg[`Arg` element]'s are used to select a constructor for the object to be created. +The sequence of configuration elements then acts on the newly-created object. [cols=",,",options="header",] |======================================================================= @@ -691,28 +645,28 @@ element], link:#jetty-xml-property[Property element] ---- bar - + ---- -which is equivalent to: +Which is equivalent to: [source, java, subs="{sub-order}"] ---- -com.acme.Foo foo = new com.acme.Foo("bar"); +com.acme.Foo foo = new com.acme.Foo("bar"); ---- ====== Instantiate with the Default Constructor [source, xml, subs="{sub-order}"] ---- - + ---- -which is equivalent to: +Which is equivalent to: [source, java, subs="{sub-order}"] ---- -com.acme.Foo foo = new com.acme.Foo(); +com.acme.Foo foo = new com.acme.Foo(); ---- ====== Instantiate with Multiple Arguments, Then Configuring Further @@ -723,10 +677,10 @@ com.acme.Foo foo = new com.acme.Foo(); bar baz 1, 2, 3 - + ---- -which is equivalent to: +Which is equivalent to: [source, java, subs="{sub-order}"] ---- @@ -737,17 +691,14 @@ foo.setTest("1, 2, 3"); [[jetty-xml-ref]] ==== -A Ref element allows a previously created object to be referenced by a -unique id. It can contain a sequence of elements, such as Set or Put -which then act on the referenced object. You can also use a Ref element -as a value for other elements such as Set and Arg. +A `Ref` element allows a previously created object to be referenced by a unique id. +It can contain a sequence of elements, such as `Set` or `Put` which then act on the referenced object. +You can also use a `Ref` element as a value for other elements such as `Set` and `Arg`. -The Ref element provides convenience and eases readability. You can -usually achieve the effect of the Ref by nesting elements (method -calls), but this can get complicated very easily. The Ref element makes -it possible to refer to the same object if you're using it multiple -times, or passing it into multiple methods. It also makes it possible to -split up configuration across multiple files. +The `Ref` element provides convenience and eases readability. +You can usually achieve the effect of the `Ref` by nesting elements (method calls), but this can get complicated very easily. +The Ref element makes it possible to refer to the same object if you're using it multiple times, or passing it into multiple methods. +It also makes it possible to split up configuration across multiple files. [cols=",,",options="header",] |======================================================================= @@ -768,13 +719,12 @@ link:#jetty-xml-property[Property element] ====== Basic example -Use the referenced object as an argument to a method call or -constructor: +Use the referenced object as an argument to a method call or constructor: [source, xml, subs="{sub-order}"] ---- - + ---- This is equivalent to: @@ -782,7 +732,7 @@ This is equivalent to: [source, java, subs="{sub-order}"] ---- foo = getXFoo(); -setSomeMethod(foo); +setSomeMethod(foo); ---- ====== Manipulating the Object Returned by Ref @@ -792,7 +742,7 @@ setSomeMethod(foo); 1, 2, 3 - + ---- This is equivalent to: @@ -800,13 +750,13 @@ This is equivalent to: [source, java, subs="{sub-order}"] ---- foo = getXFoo(); -foo.setTest("1, 2, 3"); +foo.setTest("1, 2, 3"); ---- ====== Ref vs. Nested Elements -Here is an example of the difference in syntax between using the Ref -element, and nesting method calls. They are exactly equivalent: +Here is an example of the difference in syntax between using the `Ref` element, and nesting method calls. +They are exactly equivalent: [source, xml, subs="{sub-order}"] ---- @@ -822,11 +772,10 @@ element, and nesting method calls. They are exactly equivalent: true - + ---- -Here is a more practical example, taken from the handler configuration -section in ` etc/jetty.xml`: +Here is a more practical example, taken from the handler configuration section in `etc/jetty.xml`: [source, xml, subs="{sub-order}"] ---- @@ -862,13 +811,13 @@ section in ` etc/jetty.xml`: .... - + ---- [[jetty-xml-array]] ==== -An Array element allows the creation of a new array. +An `Array` element allows the creation of a new array. [cols=",,",options="header",] |================================================================== @@ -895,13 +844,13 @@ This is equivalent to: [source, java, subs="{sub-order}"] ---- -String[] a = new String[] { "value0", new String("value1") }; +String[] a = new String[] { "value0", new String("value1") }; ---- [[jetty-xml-item]] ==== -An Item element defines an entry for Array and Map elements. +An `Item` element defines an entry for Array and Map elements. [cols=",,",options="header",] |======================================================================= @@ -921,8 +870,7 @@ link:#jetty-xml-property[Property element] [[jetty-xml-map]] ==== -A Map element allows the creation of a new HashMap and to populate it -with (key, value) pairs. +A `Map` element allows the creation of a new HashMap and to populate it with `(key, value)` pairs. [cols=",,",options="header",] |================================================================ @@ -943,7 +891,7 @@ link:#jetty-xml-entry[Entry element] keyName value1 - + ---- This is equivalent to: @@ -951,14 +899,13 @@ This is equivalent to: [source, java, subs="{sub-order}"] ---- Map m = new HashMap(); -m.put("keyName", new String("value1")); +m.put("keyName", new String("value1")); ---- [[jetty-xml-entry]] ==== -An Entry element contains a key-value link:#jetty-xml-item[Item element] -pair for a Map. +An `Entry` element contains a key-value link:#jetty-xml-item[Item element] pair for a `Map`. ===== Can Contain @@ -967,8 +914,8 @@ link:#jetty-xml-item[Item element] [[jetty-xml-system-property]] ==== -A SystemProperty element gets the value of a JVM system property. It can -be used within elements that accept values, such as Set, Put, Arg. +A `SystemProperty` element gets the value of a JVM system property. +It can be used within elements that accept values, such as `Set`, `Put`, `Arg`. [cols=",,",options="header",] |======================================================================= @@ -983,31 +930,30 @@ later. ===== Can Contain -Only attributes as Elements (Id, Name, Default). +Only attributes as Elements (`Id`, `Name`, `Default`). ===== Example [source, xml, subs="{sub-order}"] ---- - + ---- That is equivalent to: [source, java, subs="{sub-order}"] ---- -System.getProperty("jetty.http.port", "8080"); +System.getProperty("jetty.http.port", "8080"); ---- -Both try to retrieve the value of jetty.http.port. If jetty.http.port is -not set, then 8080 is used. +Both try to retrieve the value of `jetty.http.port`. +If `jetty.http.port` is not set, then 8080 is used. [[jetty-xml-property]] ==== -A Property element allows arbitrary properties to be retrieved by name. -It can contain a sequence of elements, such as Set, Put, Call that act -on the retrieved object. +A `Property` element allows arbitrary properties to be retrieved by name. +It can contain a sequence of elements, such as `Set`, `Put`, `Call` that act on the retrieved object. [cols=",,",options="header",] |======================================================================= @@ -1020,17 +966,13 @@ on the retrieved object. later. |======================================================================= -The `name` attribute may be a comma separated list of property names, -with the first property name being the "official" name, and the others -names being old, deprecated property names that are kept for backward -compatibility. A warning log is issued when deprecated property names -are used. The `default` attribute contains the value to use in case none -of the property names is found. +The `Name` attribute may be a comma separated list of property names, with the first property name being the "official" name, and the others names being old, deprecated property names that are kept for backward compatibility. +A warning log is issued when deprecated property names are used. +The `Default` attribute contains the value to use in case none of the property names is found. ===== Can Contain -The attributes may be expressed as contained Elements (Id, Name, -Default). +The attributes may be expressed as contained Elements (`Id`, `Name`, `Default`). ===== Example @@ -1040,5 +982,5 @@ Default). jdbcIdMgr - +
---- diff --git a/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-xml-usage.adoc b/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-xml-usage.adoc index 43a4afb6186..c86edafe06e 100644 --- a/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-xml-usage.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/jetty-xml/jetty-xml-usage.adoc @@ -18,7 +18,7 @@ === Jetty XML Usage Jetty provides an XML-based configuration. -It is grounded in Java's Reflection API. Classes in the java.lang.reflect represent Java methods and classes, such that you can instantiate objects and invoke their methods based on their names and argument types. +It is grounded in Java's Reflection API. Classes in the `java.lang.reflect` represent Java methods and classes, such that you can instantiate objects and invoke their methods based on their names and argument types. Behind the scenes, Jetty's XML config parser translates the XML elements and attributes into Reflection calls. [[using-jettyxml]] @@ -28,7 +28,7 @@ To use `jetty.xml`, specify it as a configuration file when running Jetty. [source, java, subs="{sub-order}"] ---- - java -jar start.jar etc/jetty.xml + java -jar start.jar etc/jetty.xml ---- ____ @@ -48,24 +48,24 @@ If you use the same ID across multiple configuration files, those configurations [[setting-parameters-in-configuration-files]] ==== Setting Parameters in Configuration Files -You can set parameters in configuration files either with system properties (using ` `) or properties files (using ``) passed via the command line. +You can set parameters in configuration files either with system properties (using ``) or properties files (using ``) passed via the command line. For example, this code in `jetty.xml` allows the port to be defined on the command line, falling back onto `8080`if the port is not specified: [source, xml, subs="{sub-order}"] ---- - + ---- Then you modify the port while running Jetty by using this command: [source, java, subs="{sub-order}"] ---- - java -Djetty.http.port=8888 -jar start.jar etc/jetty.xml + java -Djetty.http.port=8888 -jar start.jar etc/jetty.xml ---- An example of defining both system properties and properties files from the command line: [source, java, subs="{sub-order}"] ---- - java -Djetty.http.port=8888 -jar start.jar myjetty.properties etc/jetty.xml etc/other.xml + java -Djetty.http.port=8888 -jar start.jar myjetty.properties etc/jetty.xml etc/other.xml ---- diff --git a/jetty-documentation/src/main/asciidoc/reference/jetty-xml/override-web-xml.adoc b/jetty-documentation/src/main/asciidoc/reference/jetty-xml/override-web-xml.adoc index 0fb49fad62e..60f26ea37df 100644 --- a/jetty-documentation/src/main/asciidoc/reference/jetty-xml/override-web-xml.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/jetty-xml/override-web-xml.adoc @@ -22,33 +22,31 @@ The challenge is to do so without changing the webapp itself. You can use a `jet But there are some changes that `jetty.xml` cannot accomplish, for example, modifications to servlet init-params and context init-params. Using `webdefault.xml` is not an option because Jetty applies `webdefault.xml` to a web application _before_ the application's own `WEB-INF/web.xml`, which means that it cannot override values inside the webapp's ` web.xml`. -The solution is `override-web.xml`. It is a `web.xml` file that Jetty applies to a web application _after_ the application's own `WEB-INF/web.xml`, which means that it can override values or add new elements. -You define it per-webapp, using the xref:jetty-xml-syntax[]. +The solution is `override-web.xml`. +It is a `web.xml` file that Jetty applies to a web application _after_ the application's own `WEB-INF/web.xml`, which means that it can override values or add new elements. +This is defined on a per-webapp basis, using the xref:jetty-xml-syntax[]. [[using-override-web-xml]] -==== Using `override-web.xml` +==== Using override-web.xml -You can specify the `override-web.xml` to use for an individual web application, in that webapp's xref:jetty-web-xml-config[]. +You can specify the `override-web.xml` to use for an individual web application in a deployable xml file located in Jetty webapps folder . +For example, if you had a webapp named MyApp, you would place a deployable xml file named `myapp.xml` in `${jetty.base}/webapps` which includes an `overrideDescriptor` entry for the `override-web.xml` file. [source, xml, subs="{sub-order}"] ---- - ... - /my/path/to/override-web.xml ... - - ---- The equivalent in code is: [source, java, subs="{sub-order}"] ---- - import org.eclipse.jetty.webapp.WebAppContext; ... @@ -58,11 +56,9 @@ import org.eclipse.jetty.webapp.WebAppContext; //Set the path to the override descriptor, based on your $(jetty.home) directory wac.setOverrideDescriptor(System.getProperty("jetty.home")+"/my/path/to/override-web.xml"); ... - - ---- -Alternatively, use the classloader (xref:jetty-classloading[]) to get the path to the override descriptor as a resource. +Alternatively, you can use the classloader (xref:jetty-classloading[]) to get the path to the override descriptor as a resource. [[override-using-jetty-maven-plugin]] ==== Using the Jetty Maven Plugin @@ -71,7 +67,6 @@ Use the `` tag as follows: [source, xml, subs="{sub-order}"] ---- - ... @@ -89,8 +84,6 @@ Use the `` tag as follows: ... - - ---- [[override-web-xml-additional-resources]] diff --git a/jetty-documentation/src/main/asciidoc/reference/jetty-xml/webdefault-xml.adoc b/jetty-documentation/src/main/asciidoc/reference/jetty-xml/webdefault-xml.adoc index 95110c6f8b5..588f5b56a8b 100644 --- a/jetty-documentation/src/main/asciidoc/reference/jetty-xml/webdefault-xml.adoc +++ b/jetty-documentation/src/main/asciidoc/reference/jetty-xml/webdefault-xml.adoc @@ -38,7 +38,7 @@ You can specify a custom `webdefault.xml` for an individual web application in t [source, xml, subs="{sub-order}"] ---- - + ... @@ -46,14 +46,14 @@ You can specify a custom `webdefault.xml` for an individual web application in t ... - + ---- The equivalent in code is: [source, java, subs="{sub-order}"] ---- - + import org.eclipse.jetty.webapp.WebAppContext; ... @@ -64,7 +64,7 @@ import org.eclipse.jetty.webapp.WebAppContext; wac.setDefaultsDescriptor("/my/path/to/webdefault.xml"); ... - + ---- Alternatively, you can use a xref:jetty-classloading[] to find the resource representing your custom `webdefault.xml`. @@ -86,7 +86,7 @@ Similarly, when using the link:#jetty-maven-plugin[Jetty Maven Plugin] you provi [source, xml, subs="{sub-order}"] ---- - + ... @@ -105,7 +105,7 @@ Similarly, when using the link:#jetty-maven-plugin[Jetty Maven Plugin] you provi ... - + ---- [[webdefault-xml-additional-resources]] diff --git a/jetty-documentation/src/main/assembly/html.xml b/jetty-documentation/src/main/assembly/html.xml index 21297570ca5..6c0dcf7c8b4 100644 --- a/jetty-documentation/src/main/assembly/html.xml +++ b/jetty-documentation/src/main/assembly/html.xml @@ -7,7 +7,7 @@ ${project.version} - ${project.basedir}/target/docbkx/html/index + ${project.basedir}/target/docbkx/html ** diff --git a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/Flusher.java b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/Flusher.java index 51d2b83a45c..d5f9b454a5f 100644 --- a/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/Flusher.java +++ b/jetty-fcgi/fcgi-client/src/main/java/org/eclipse/jetty/fcgi/generator/Flusher.java @@ -19,10 +19,10 @@ package org.eclipse.jetty.fcgi.generator; import java.nio.ByteBuffer; +import java.util.ArrayDeque; import java.util.Queue; import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.util.ConcurrentArrayQueue; import org.eclipse.jetty.util.IteratingCallback; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -31,7 +31,7 @@ public class Flusher { private static final Logger LOG = Log.getLogger(Flusher.class); - private final Queue queue = new ConcurrentArrayQueue<>(); + private final Queue queue = new ArrayDeque<>(); private final IteratingCallback flushCallback = new FlushCallback(); private final EndPoint endPoint; @@ -43,10 +43,26 @@ public class Flusher public void flush(Generator.Result... results) { for (Generator.Result result : results) - queue.offer(result); + offer(result); flushCallback.iterate(); } + private void offer(Generator.Result result) + { + synchronized (this) + { + queue.offer(result); + } + } + + private Generator.Result poll() + { + synchronized (this) + { + return queue.poll(); + } + } + public void shutdown() { flush(new ShutdownResult()); @@ -60,7 +76,7 @@ public class Flusher protected Action process() throws Exception { // Look if other writes are needed. - Generator.Result result = queue.poll(); + Generator.Result result = poll(); if (result == null) { // No more writes to do, return. @@ -71,7 +87,7 @@ public class Flusher // Most often there is another result in the // queue so this is a real optimization because // it sends both results in just one TCP packet. - Generator.Result other = queue.poll(); + Generator.Result other = poll(); if (other != null) result = result.join(other); @@ -106,7 +122,7 @@ public class Flusher while (true) { - Generator.Result result = queue.poll(); + Generator.Result result = poll(); if (result == null) break; result.failed(x); diff --git a/jetty-gcloud/jetty-gcloud-session-manager/pom.xml b/jetty-gcloud/jetty-gcloud-session-manager/pom.xml index c75e1f1614a..4bf6490fc26 100644 --- a/jetty-gcloud/jetty-gcloud-session-manager/pom.xml +++ b/jetty-gcloud/jetty-gcloud-session-manager/pom.xml @@ -18,7 +18,7 @@ com.google.cloud - gcloud-java-datastore + google-cloud-datastore ${gcloud.version} diff --git a/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/etc/sessions/gcloud/session-store.xml b/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/etc/sessions/gcloud/session-store.xml index 003d0e24f9e..e82adf8a0ca 100644 --- a/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/etc/sessions/gcloud/session-store.xml +++ b/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/etc/sessions/gcloud/session-store.xml @@ -11,8 +11,49 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/modules/gcloud-datastore.mod b/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/modules/gcloud-datastore.mod new file mode 100644 index 00000000000..43d1ea6e7b2 --- /dev/null +++ b/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/modules/gcloud-datastore.mod @@ -0,0 +1,72 @@ +[description] +Enables GCloud Datastore API and implementation + +[Tags] +3rdparty +gcloud + +[depends] +gcloud +jcl-api +jcl-impl + +[files] +maven://com.google.cloud/google-cloud-datastore/0.3.0|lib/gcloud/google-cloud-datastore-0.3.0.jar +maven://com.google.cloud/google-cloud-core/0.3.0|lib/gcloud/google-cloud-core-0.3.0.jar +maven://com.google.auth/google-auth-library-credentials/0.3.1|lib/gcloud/google-auth-library-credentials-0.3.1.jar +maven://com.google.auth/google-auth-library-oauth2-http/0.3.1|lib/gcloud/google-auth-library-oauth2-http-0.3.1.jar +maven://com.google.http-client/google-http-client-jackson2/1.19.0|lib/gcloud/google-http-client-jackson2-1.19.0.jar +maven://com.fasterxml.jackson.core/jackson-core/2.1.3|lib/gcloud/jackson-core-2.1.3.jar +maven://com.google.http-client/google-http-client/1.21.0|lib/gcloud/google-http-client-1.21.0.jar +maven://com.google.code.findbugs/jsr305/1.3.9|lib/gcloud/jsr305-1.3.9.jar +maven://org.apache.httpcomponents/httpclient/4.0.1|lib/gcloud/httpclient-4.0.1.jar +maven://org.apache.httpcomponents/httpcore/4.0.1|lib/gcloud/httpcore-4.0.1.jar +maven://commons-codec/commons-codec/1.3|lib/gcloud/commons-codec-1.3.jar +maven://com.google.oauth-client/google-oauth-client/1.21.0|lib/gcloud/google-oauth-client-1.21.0.jar +maven://com.google.guava/guava/19.0|lib/gcloud/guava-19.0.jar +maven://com.google.api-client/google-api-client-appengine/1.21.0|lib/gcloud/google-api-client-appengine-1.21.0.jar +maven://com.google.oauth-client/google-oauth-client-appengine/1.21.0|lib/gcloud/google-oauth-client-appengine-1.21.0.jar +maven://com.google.oauth-client/google-oauth-client-servlet/1.21.0|lib/gcloud/google-oauth-client-servlet-1.21.0.jar +maven://com.google.http-client/google-http-client-jdo/1.21.0|lib/gcloud/google-http-client-jdo-1.21.0.jar +maven://com.google.api-client/google-api-client-servlet/1.21.0|lib/gcloud/google-api-client-servlet-1.21.0.jar +maven://javax.jdo/jdo2-api/2.3-eb|lib/gcloud/jdo2-api-2.3-eb.jar +maven://javax.transaction/transaction-api/1.1|lib/gcloud/transaction-api-1.1.jar +maven://com.google.http-client/google-http-client-appengine/1.21.0|lib/gcloud/google-http-client-appengine-1.21.0.jar +maven://com.google.http-client/google-http-client-jackson/1.21.0|lib/gcloud/google-http-client-jackson-1.21.0.jar +maven://org.codehaus.jackson/jackson-core-asl/1.9.11|lib/gcloud/jackson-core-asl-1.9.11.jar +maven://joda-time/joda-time/2.9.2|lib/gcloud/joda-time-2.9.2.jar +maven://com.google.protobuf/protobuf-java/3.0.0-beta-3|lib/gcloud/protobuf-java-3.0.0-beta-3.jar +maven://com.google.api/gax/0.0.16|lib/gcloud/gax-0.0.16.jar +maven://io.grpc/grpc-all/0.15.0|lib/gcloud/grpc-all-0.15.0.jar +maven://io.grpc/grpc-auth/0.15.0|lib/gcloud/grpc-auth-0.15.0.jar +maven://io.grpc/grpc-netty/0.15.0|lib/gcloud/grpc-netty-0.15.0.jar +maven://io.netty/netty-codec-http2/4.1.1.Final|lib/gcloud/netty-codec-http2-4.1.1.jar +maven://io.netty/netty-codec-http/4.1.1.Final|lib/gcloud/netty-codec-http-4.1.1.Final.jar +maven://io.netty/netty-codec/4.1.1.Final|lib/gcloud/netty-codec-4.1.1.Final.jar +maven://io.netty/netty-handler/4.1.1.Final|lib/gcloud/netty-handler-4.1.1.Final.jar +maven://io.netty/netty-buffer/4.1.1.Final|lib/gcloud/netty-buffer-4.1.1.Final.jar +maven://io.netty/netty-common/4.1.1.Final|lib/gcloud/netty-common-4.1.1.Final.jar +maven://io.netty/netty-transport/4.1.1.Final|lib/gcloud/netty-transport-4.1.1.Final.jar +maven://io.netty/netty-resolver/4.1.1.Final|lib/gcloud/netty-resolver-4.1.1.Final.jar +maven://io.grpc/grpc-okhttp/0.15.0|lib/gcloud/grpc-okhttp-0.15.0.jar +maven://com.squareup.okio/okio/1.6.0|lib/gcloud/okio-1.6.0.jar +maven://com.squareup.okhttp/okhttp/2.5.0|lib/gcloud/okhttp-2.5.0.jar +maven://io.grpc/grpc-protobuf-nano/0.15.0|lib/gcloud/grpc-protobuf-nano-0.15.0.jar +maven://com.google.protobuf.nano/protobuf-javanano/3.0.0-alpha-5|lib/gcloud/protobuf-javanano-3.0.0-alpha-5.jar +maven://io.grpc/grpc-stub/0.15.0|lib/gcloud/grpc-stub-0.15.0.jar +maven://io.grpc/grpc-protobuf/0.15.0|lib/gcloud/grpc-protobuf-0.15.0.jar +maven://com.google.protobuf/protobuf-java-util/3.0.0-beta-3|lib/gcloud/protobuf-java-util-3.0.0-beta-3.jar +maven://com.google.code.gson/gson/2.3|lib/gcloud/gson-2.3.jar +maven://io.grpc/grpc-protobuf-lite/0.15.0|lib/gcloud/grpc-protobuf-lite-0.15.0.jar +maven://io.grpc/grpc-core/0.15.0|lib/gcloud/grpc-core-0.15.0.jar +maven://com.google.auto.value/auto-value/1.1|lib/gcloud/auto-value-1.1.jar +maven://com.google.inject/guice/4.0|lib/gcloud/guice-4.0.jar +maven://javax.inject/javax.inject/1|lib/gcloud/javax.inject-1.jar +maven://aopalliance/aopalliance/1.0|lib/gcloud/aopalliance-1.0.jar +maven://com.google.api.grpc/grpc-google-common-protos/0.0.7|lib/gcloud/grpc-google-common-protos-0.0.7.jar +maven://org.json/json/20151123|lib/gcloud/json-20151123.jar +maven://com.google.cloud.datastore/datastore-v1-protos/1.0.1|lib/gcloud/datastore-v1-protos-1.0.1-beta.jar +maven://com.google.cloud.datastore/datastore-v1-proto-client/1.1.0|lib/gcloud/datastore-v1-proto-client-1.1.0.jar +maven://com.google.http-client/google-http-client-protobuf/1.20.0|lib/gcloud/google-http-client-protobuf-1.20.0.jar +maven://com.google.api-client/google-api-client/1.20.0|lib/gcloud/google-api-client-1.20.0.jar +maven://com.google.guava/guava-jdk5/13.0|lib/gcloud/guava-jdk5-13.0.jar diff --git a/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/modules/gcloud.mod b/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/modules/gcloud.mod new file mode 100644 index 00000000000..2039280ee34 --- /dev/null +++ b/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/modules/gcloud.mod @@ -0,0 +1,18 @@ +[description] +Control GCloud API classpath + +[Tags] +3rdparty +gcloud + +[lib] +lib/gcloud/*.jar + +[license] +GCloudDatastore is an open source project hosted on Github and released under the Apache 2.0 license. +https://github.com/GoogleCloudPlatform/gcloud-java +http://www.apache.org/licenses/LICENSE-2.0.html + +[ini-template] +## Hide the gcloud libraries from deployed webapps +jetty.webapp.addServerClasses,=file:${jetty.base}/lib/gcloud/ diff --git a/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/etc/sessions/gcloud/index.yaml b/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/modules/gcloud/index.yaml similarity index 100% rename from jetty-gcloud/jetty-gcloud-session-manager/src/main/config/etc/sessions/gcloud/index.yaml rename to jetty-gcloud/jetty-gcloud-session-manager/src/main/config/modules/gcloud/index.yaml diff --git a/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/modules/session-store-gcloud.mod b/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/modules/session-store-gcloud.mod index 418d0cd92bc..c5e933032fa 100644 --- a/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/modules/session-store-gcloud.mod +++ b/jetty-gcloud/jetty-gcloud-session-manager/src/main/config/modules/session-store-gcloud.mod @@ -1,67 +1,44 @@ [description] Enables GCloudDatastore session management. +[Tags] +session +gcloud + [provides] session-store [depends] +gcloud-datastore annotations webapp sessions -jcl-api -jcl-impl [files] -basehome:etc/sessions/gcloud/index.yaml|etc/index.yaml -maven://com.google.cloud/gcloud-java-datastore/0.2.3|lib/gcloud/gcloud-java-datastore-0.2.3.jar -maven://com.google.cloud/gcloud-java-core/0.2.3|lib/gcloud/gcloud-java-core-0.2.3.jar -maven://com.google.auth/google-auth-library-credentials/0.3.1|lib/gcloud/google-auth-library-credentials-0.3.1.jar -maven://com.google.auth/google-auth-library-oauth2-http/0.3.1|lib/gcloud/google-auth-library-oauth2-http-0.3.1.jar -maven://com.google.http-client/google-http-client-jackson2/1.19.0|lib/gcloud/google-http-client-jackson2-1.19.0.jar -maven://com.fasterxml.jackson.core/jackson-core/2.1.3|lib/gcloud/jackson-core-2.1.3.jar -maven://com.google.http-client/google-http-client/1.21.0|lib/gcloud/google-http-client-1.21.0.jar -maven://com.google.code.findbugs/jsr305/1.3.9|lib/gcloud/jsr305-1.3.9.jar -maven://org.apache.httpcomponents/httpclient/4.0.1|lib/gcloud/httpclient-4.0.1.jar -maven://org.apache.httpcomponents/httpcore/4.0.1|lib/gcloud/httpcore-4.0.1.jar -maven://commons-codec/commons-codec/1.3|lib/gcloud/commons-codec-1.3.jar -maven://com.google.oauth-client/google-oauth-client/1.21.0|lib/gcloud/google-oauth-client-1.21.0.jar -maven://com.google.guava/guava/19.0|lib/gcloud/guava-19.0.jar -maven://com.google.api-client/google-api-client-appengine/1.21.0|lib/gcloud/google-api-client-appengine-1.21.0.jar -maven://com.google.oauth-client/google-oauth-client-appengine/1.21.0|lib/gcloud/google-oauth-client-appengine-1.21.0.jar -maven://com.google.oauth-client/google-oauth-client-servlet/1.21.0|lib/gcloud/google-oauth-client-servlet-1.21.0.jar -maven://com.google.http-client/google-http-client-jdo/1.21.0|lib/gcloud/google-http-client-jdo-1.21.0.jar -maven://com.google.api-client/google-api-client-servlet/1.21.0|lib/gcloud/google-api-client-servlet-1.21.0.jar -maven://javax.jdo/jdo2-api/2.3-eb|lib/gcloud/jdo2-api-2.3-eb.jar -maven://javax.transaction/transaction-api/1.1|lib/gcloud/transaction-api-1.1.jar -maven://com.google.http-client/google-http-client-appengine/1.21.0|lib/gcloud/google-http-client-appengine-1.21.0.jar -maven://com.google.http-client/google-http-client-jackson/1.21.0|lib/gcloud/google-http-client-jackson-1.21.0.jar -maven://org.codehaus.jackson/jackson-core-asl/1.9.11|lib/gcloud/jackson-core-asl-1.9.11.jar -maven://joda-time/joda-time/2.9.2|lib/gcloud/joda-time-2.9.2.jar -maven://org.json/json/20151123|lib/gcloud/json-20151123.jar -maven://com.google.cloud.datastore/datastore-v1beta3-protos/1.0.0-beta|lib/gcloud/datastore-v1beta3-protos-1.0.0-beta.jar -maven://com.google.protobuf/protobuf-java/3.0.0-beta-1|lib/gcloud/protobuf-java-3.0.0-beta-1.jar -maven://com.google.cloud.datastore/datastore-v1beta3-proto-client/1.0.0-beta.2|lib/gcloud/datastore-v1beta3-proto-client-1.0.0-beta.2.jar -maven://com.google.http-client/google-http-client-protobuf/1.20.0|lib/gcloud/google-http-client-protobuf-1.20.0.jar -maven://com.google.api-client/google-api-client/1.20.0|lib/gcloud/google-api-client-1.20.0.jar -maven://com.google.guava/guava-jdk5/13.0|lib/gcloud/guava-jdk5-13.0.jar - - +basehome:modules/gcloud/index.yaml|etc/index.yaml [lib] lib/jetty-gcloud-session-manager-${jetty.version}.jar -lib/gcloud/*.jar [xml] etc/sessions/gcloud/session-store.xml -[license] -GCloudDatastore is an open source project hosted on Github and released under the Apache 2.0 license. -https://github.com/GoogleCloudPlatform/gcloud-java -http://www.apache.org/licenses/LICENSE-2.0.html - [ini-template] ## GCloudDatastore Session config -#jetty.gcloudSession.maxRetries=5 -#jetty.gcloudSession.backoffMs=1000 +#jetty.session.gcloud.maxRetries=5 +#jetty.session.gcloud.backoffMs=1000 +#jetty.session.gcloud.namespace= +#jetty.session.gcloud.model.kind=GCloudSession +#jetty.session.gcloud.model.id=id +#jetty.session.gcloud.model.contextPath=contextPath +#jetty.session.gcloud.model.vhost=vhost +#jetty.session.gcloud.model.accessed=accessed +#jetty.session.gcloud.model.lastAccessed=lastAccessed +#jetty.session.gcloud.model.createTime=createTime +#jetty.session.gcloud.model.cookieSetTime=cookieSetTime +#jetty.session.gcloud.model.lastNode=lastNode +#jetty.session.gcloud.model.expiry=expiry +#jetty.session.gcloud.model.maxInactive=maxInactive +#jetty.session.gcloud.model.attributes=attributes diff --git a/jetty-gcloud/jetty-gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStore.java b/jetty-gcloud/jetty-gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStore.java index cd5a86b98cb..72fa3ce5d10 100644 --- a/jetty-gcloud/jetty-gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStore.java +++ b/jetty-gcloud/jetty-gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStore.java @@ -59,38 +59,327 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore { private final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session"); - public static final String ID = "id"; - public static final String CONTEXTPATH = "contextPath"; - public static final String VHOST = "vhost"; - public static final String ACCESSED = "accessed"; - public static final String LASTACCESSED = "lastAccessed"; - public static final String CREATETIME = "createTime"; - public static final String COOKIESETTIME = "cookieSetTime"; - public static final String LASTNODE = "lastNode"; - public static final String EXPIRY = "expiry"; - public static final String MAXINACTIVE = "maxInactive"; - public static final String ATTRIBUTES = "attributes"; - public static final String KIND = "GCloudSession"; public static final int DEFAULT_MAX_QUERY_RESULTS = 100; public static final int DEFAULT_MAX_RETRIES = 5; public static final int DEFAULT_BACKOFF_MS = 1000; - private Datastore _datastore; - private KeyFactory _keyFactory; - private int _maxResults = DEFAULT_MAX_QUERY_RESULTS; - private int _maxRetries = DEFAULT_MAX_RETRIES; - private int _backoff = DEFAULT_BACKOFF_MS; + protected Datastore _datastore; + protected KeyFactory _keyFactory; + protected int _maxResults = DEFAULT_MAX_QUERY_RESULTS; + protected int _maxRetries = DEFAULT_MAX_RETRIES; + protected int _backoff = DEFAULT_BACKOFF_MS; - private boolean _dsProvided = false; + protected boolean _dsProvided = false; + protected boolean _indexesPresent = false; + protected EntityDataModel _model; + + + private String _namespace; + /** + * EntityDataModel + * + * Names of type of Entity and Entity properties for sessions. + */ + public static class EntityDataModel + { + public static final String ID = "id"; + public static final String CONTEXTPATH = "contextPath"; + public static final String VHOST = "vhost"; + public static final String ACCESSED = "accessed"; + public static final String LASTACCESSED = "lastAccessed"; + public static final String CREATETIME = "createTime"; + public static final String COOKIESETTIME = "cookieSetTime"; + public static final String LASTNODE = "lastNode"; + public static final String EXPIRY = "expiry"; + public static final String MAXINACTIVE = "maxInactive"; + public static final String ATTRIBUTES = "attributes"; + + public static final String KIND = "GCloudSession"; + protected String _kind = KIND; + protected String _id = ID; + protected String _contextPath = CONTEXTPATH; + protected String _vhost = VHOST; + protected String _accessed = ACCESSED; + protected String _lastAccessed = LASTACCESSED; + protected String _lastNode = LASTNODE; + protected String _createTime = CREATETIME; + protected String _cookieSetTime = COOKIESETTIME; + protected String _expiry = EXPIRY; + protected String _maxInactive = MAXINACTIVE; + protected String _attributes = ATTRIBUTES; + + + private void checkNotNull(String s) + { + if (s == null) + throw new IllegalArgumentException(s); + } + + /** + * @return the lastNode + */ + public String getLastNode() + { + return _lastNode; + } + + /** + * @param lastNode the lastNode to set + */ + public void setLastNode(String lastNode) + { + _lastNode = lastNode; + } + + /** + * @return the kind + */ + public String getKind() + { + return _kind; + } + /** + * @param kind the kind to set + */ + public void setKind(String kind) + { + checkNotNull(kind); + _kind = kind; + } + /** + * @return the id + */ + public String getId() + { + return _id; + } + /** + * @param id the id to set + */ + public void setId(String id) + { + checkNotNull(id); + _id = id; + } + /** + * @return the contextPath + */ + public String getContextPath() + { + return _contextPath; + } + /** + * @param contextPath the contextPath to set + */ + public void setContextPath(String contextPath) + { + checkNotNull(contextPath); + _contextPath = contextPath; + } + /** + * @return the vhost + */ + public String getVhost() + { + return _vhost; + } + /** + * @param vhost the vhost to set + */ + public void setVhost(String vhost) + { + checkNotNull(vhost); + _vhost = vhost; + } + /** + * @return the accessed + */ + public String getAccessed() + { + return _accessed; + } + /** + * @param accessed the accessed to set + */ + public void setAccessed(String accessed) + { + checkNotNull(accessed); + _accessed = accessed; + } + /** + * @return the lastAccessed + */ + public String getLastAccessed() + { + return _lastAccessed; + } + /** + * @param lastAccessed the lastAccessed to set + */ + public void setLastAccessed(String lastAccessed) + { + checkNotNull(lastAccessed); + _lastAccessed = lastAccessed; + } + /** + * @return the createTime + */ + public String getCreateTime() + { + return _createTime; + } + /** + * @param createTime the createTime to set + */ + public void setCreateTime(String createTime) + { + checkNotNull(createTime); + _createTime = createTime; + } + /** + * @return the cookieSetTime + */ + public String getCookieSetTime() + { + return _cookieSetTime; + } + /** + * @param cookieSetTime the cookieSetTime to set + */ + public void setCookieSetTime(String cookieSetTime) + { + checkNotNull(cookieSetTime); + _cookieSetTime = cookieSetTime; + } + /** + * @return the expiry + */ + public String getExpiry() + { + return _expiry; + } + /** + * @param expiry the expiry to set + */ + public void setExpiry(String expiry) + { + checkNotNull(expiry); + _expiry = expiry; + } + /** + * @return the maxInactive + */ + public String getMaxInactive() + { + return _maxInactive; + } + /** + * @param maxInactive the maxInactive to set + */ + public void setMaxInactive(String maxInactive) + { + checkNotNull(maxInactive); + _maxInactive = maxInactive; + } + /** + * @return the attributes + */ + public String getAttributes() + { + return _attributes; + } + /** + * @param attributes the attributes to set + */ + public void setAttributes(String attributes) + { + checkNotNull(attributes); + _attributes = attributes; + } + + } + + + /** + * ExpiryInfo + * + * Information related to session expiry + */ + public static class ExpiryInfo + { + String _id; + String _lastNode; + long _expiry; + + /** + * @param id session id + * @param lastNode last node id to manage the session + * @param expiry timestamp of expiry + */ + public ExpiryInfo (String id, String lastNode, long expiry) + { + _id = id; + _lastNode = lastNode; + _expiry = expiry; + } + + /** + * @return the id + */ + public String getId() + { + return _id; + } + + /** + * @return the lastNode + */ + public String getLastNode() + { + return _lastNode; + } + + /** + * @return the expiry time + */ + public long getExpiry() + { + return _expiry; + } + + + } + + public void setEntityDataModel(EntityDataModel model) + { + _model = model; + } + + + public EntityDataModel getEntityDataModel () + { + return _model; + } + + public void setBackoffMs (int ms) { _backoff = ms; } + public void setNamespace (String namespace) + { + _namespace = namespace; + } + + public String getNamespace () + { + return _namespace; + } public int getBackoffMs () { @@ -116,9 +405,22 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore protected void doStart() throws Exception { if (!_dsProvided) - _datastore = DatastoreOptions.defaultInstance().service(); + { + if (!StringUtil.isBlank(getNamespace())) + _datastore = DatastoreOptions.builder().namespace(getNamespace()).build().service(); + else + _datastore = DatastoreOptions.defaultInstance().service(); + } - _keyFactory = _datastore.newKeyFactory().kind(KIND); + if (_model == null) + _model = new EntityDataModel(); + + _keyFactory = _datastore.newKeyFactory().kind(_model.getKind()); + + _indexesPresent = checkIndexes(); + if (!_indexesPresent) + LOG.warn("Session indexes not uploaded, falling back to less efficient queries"); + super.doStart(); } @@ -198,43 +500,34 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore try { - //get up to maxResult number of sessions that have expired - Query query = Query.projectionEntityQueryBuilder() - .kind(KIND) - .projection(ID, LASTNODE, EXPIRY) - .filter(CompositeFilter.and(PropertyFilter.gt(EXPIRY, 0), PropertyFilter.le(EXPIRY, now))) - .limit(_maxResults) - .build(); - - QueryResults presults = _datastore.run(query); - - while (presults.hasNext()) + Set info = null; + if (_indexesPresent) + info = queryExpiryByIndex(); + else + info = queryExpiryByEntity(); + + for (ExpiryInfo item:info) { - ProjectionEntity pe = presults.next(); - String id = pe.getString(ID); - String lastNode = pe.getString(LASTNODE); - long expiry = pe.getLong(EXPIRY); - - if (StringUtil.isBlank(lastNode)) - expired.add(id); //nobody managing it + if (StringUtil.isBlank(item.getLastNode())) + expired.add(item.getId()); //nobody managing it else { - if (_context.getWorkerName().equals(lastNode)) - expired.add(id); //we're managing it, we can expire it + if (_context.getWorkerName().equals(item.getLastNode())) + expired.add(item.getId()); //we're managing it, we can expire it else { if (_lastExpiryCheckTime <= 0) { //our first check, just look for sessions that we managed by another node that //expired at least 3 graceperiods ago - if (expiry < (now - (1000L * (3 * _gracePeriodSec)))) - expired.add(id); + if (item.getExpiry() < (now - (1000L * (3 * _gracePeriodSec)))) + expired.add(item.getId()); } else { //another node was last managing it, only expire it if it expired a graceperiod ago - if (expiry < (now - (1000L * _gracePeriodSec))) - expired.add(id); + if (item.getExpiry() < (now - (1000L * _gracePeriodSec))) + expired.add(item.getId()); } } } @@ -254,8 +547,8 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore try { Query q = Query.keyQueryBuilder() - .kind(KIND) - .filter(PropertyFilter.eq(ID, s)) + .kind(_model.getKind()) + .filter(PropertyFilter.eq(_model.getId(), s)) .build(); QueryResults res = _datastore.run(q); if (!res.hasNext()) @@ -278,36 +571,152 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore } - - - + + /** + * A less efficient query to find sessions whose expiry time has passed: + * retrieves the whole Entity. + * @return set of ExpiryInfo representing the id, lastNode and expiry time of + * sessions that are expired + * @throws Exception if datastore experiences a problem + */ + protected Set queryExpiryByEntity () throws Exception + { + Set info = new HashSet<>(); + + //get up to maxResult number of sessions that have expired + Query query = Query.entityQueryBuilder() + .kind(_model.getKind()) + .filter(CompositeFilter.and(PropertyFilter.gt(_model.getExpiry(), 0), PropertyFilter.le(_model.getExpiry(), System.currentTimeMillis()))) + .limit(_maxResults) + .build(); + + QueryResults results; + if (LOG.isDebugEnabled()) + { + long start = System.currentTimeMillis(); + results = _datastore.run(query); + LOG.debug("Expiry query no index in {}ms", System.currentTimeMillis()-start); + } + else + results = _datastore.run(query); + while (results.hasNext()) + { + Entity entity = results.next(); + info.add(new ExpiryInfo(entity.getString(_model.getId()),entity.getString(_model.getLastNode()), entity.getLong(_model.getExpiry()))); + } + + return info; + } + + /** An efficient query to find sessions whose expiry time has passed: + * uses a projection query, which requires indexes to be uploaded. + * @return id,lastnode and expiry time of sessions that have expired + * @throws Exception if datastore experiences a problem + */ + protected Set queryExpiryByIndex () throws Exception + { + Set info = new HashSet<>(); + Query query = Query.projectionEntityQueryBuilder() + .kind(_model.getKind()) + .projection(_model.getId(), _model.getLastNode(), _model.getExpiry()) + .filter(CompositeFilter.and(PropertyFilter.gt(_model.getExpiry(), 0), PropertyFilter.le(_model.getExpiry(), System.currentTimeMillis()))) + .limit(_maxResults) + .build(); + + QueryResults presults; + + if (LOG.isDebugEnabled()) + { + long start = System.currentTimeMillis(); + presults = _datastore.run(query); + LOG.debug("Expiry query by index in {}ms", System.currentTimeMillis()-start); + } + else + presults = _datastore.run(query); + + while (presults.hasNext()) + { + ProjectionEntity pe = presults.next(); + info.add(new ExpiryInfo(pe.getString(_model.getId()),pe.getString(_model.getLastNode()), pe.getLong(_model.getExpiry()))); + } + + return info; + } + + + /** * @see org.eclipse.jetty.server.session.SessionDataStore#exists(java.lang.String) */ @Override public boolean exists(String id) throws Exception { - Query query = Query.projectionEntityQueryBuilder() - .kind(KIND) - .projection(EXPIRY) - .filter(PropertyFilter.eq(ID, id)) - .build(); - - - QueryResults presults = _datastore.run(query); - - if (presults.hasNext()) + if (_indexesPresent) { - ProjectionEntity pe = presults.next(); - long expiry = pe.getLong(EXPIRY); - if (expiry <= 0) - return true; //never expires + Query query = Query.projectionEntityQueryBuilder() + .kind(_model.getKind()) + .projection(_model.getExpiry()) + .filter(PropertyFilter.eq(_model.getId(), id)) + .build(); + + QueryResults presults; + if (LOG.isDebugEnabled()) + { + long start = System.currentTimeMillis(); + presults = _datastore.run(query); + LOG.debug("Exists query by index in {}ms", System.currentTimeMillis()-start); + } else - return (expiry > System.currentTimeMillis()); //not expired yet + presults = _datastore.run(query); + + if (presults.hasNext()) + { + ProjectionEntity pe = presults.next(); + return !isExpired(pe.getLong(_model.getExpiry())); + } + else + return false; } else + { + Query query = Query.entityQueryBuilder() + .kind(_model.getKind()) + .filter(PropertyFilter.eq(_model.getId(), id)) + .build(); + + QueryResults results; + if (LOG.isDebugEnabled()) + { + long start = System.currentTimeMillis(); + results = _datastore.run(query); + LOG.debug("Exists query no index in {}ms", System.currentTimeMillis()-start); + } + else + results = _datastore.run(query); + + if (results.hasNext()) + { + Entity entity = results.next(); + return !isExpired(entity.getLong(_model.getExpiry())); + } + else + return false; + } + } + + /** + * Check to see if the given time is in the past. + * + * @param timestamp the time to check + * @return false if the timestamp is 0 or less, true if it is in the past + */ + protected boolean isExpired (long timestamp) + { + if (timestamp <= 0) return false; + else + return timestamp < System.currentTimeMillis(); } /** @@ -371,21 +780,48 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore * @param context the session context * @return the key */ - private Key makeKey (String id, SessionContext context) + protected Key makeKey (String id, SessionContext context) { String key = context.getCanonicalContextPath()+"_"+context.getVhost()+"_"+id; return _keyFactory.newKey(key); } - - + + + /** + * Check to see if indexes are available, in which case + * we can do more performant queries. + * @return + */ + protected boolean checkIndexes () + { + try + { + Query query = Query.projectionEntityQueryBuilder() + .kind(_model.getKind()) + .projection(_model.getExpiry()) + .filter(PropertyFilter.eq(_model.getId(), "-")) + .build(); + _datastore.run(query); + return true; + } + catch (DatastoreException e) + { + //need to assume that the problem is the index doesn't exist, because there + //is no specific code for that + if (LOG.isDebugEnabled()) + LOG.debug("Check for indexes", e); + + return false; + } + } /** * Generate a gcloud datastore Entity from SessionData * @param session the session data * @param key the key * @return the entity - * @throws Exception + * @throws Exception if there is a deserialization error */ - private Entity entityFromSession (SessionData session, Key key) throws Exception + protected Entity entityFromSession (SessionData session, Key key) throws Exception { if (session == null) return null; @@ -400,17 +836,17 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore //turn a session into an entity entity = Entity.builder(key) - .set(ID, session.getId()) - .set(CONTEXTPATH, session.getContextPath()) - .set(VHOST, session.getVhost()) - .set(ACCESSED, session.getAccessed()) - .set(LASTACCESSED, session.getLastAccessed()) - .set(CREATETIME, session.getCreated()) - .set(COOKIESETTIME, session.getCookieSet()) - .set(LASTNODE,session.getLastNode()) - .set(EXPIRY, session.getExpiry()) - .set(MAXINACTIVE, session.getMaxInactiveMs()) - .set(ATTRIBUTES, BlobValue.builder(Blob.copyFrom(baos.toByteArray())).excludeFromIndexes(true).build()).build(); + .set(_model.getId(), session.getId()) + .set(_model.getContextPath(), session.getContextPath()) + .set(_model.getVhost(), session.getVhost()) + .set(_model.getAccessed(), session.getAccessed()) + .set(_model.getLastAccessed(), session.getLastAccessed()) + .set(_model.getCreateTime(), session.getCreated()) + .set(_model.getCookieSetTime(), session.getCookieSet()) + .set(_model.getLastNode(),session.getLastNode()) + .set(_model.getExpiry(), session.getExpiry()) + .set(_model.getMaxInactive(), session.getMaxInactiveMs()) + .set(_model.getAttributes(), BlobValue.builder(Blob.copyFrom(baos.toByteArray())).excludeFromIndexes(true).build()).build(); return entity; @@ -422,7 +858,7 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore * @return the session data * @throws Exception if unable to get the entity */ - private SessionData sessionFromEntity (Entity entity) throws Exception + protected SessionData sessionFromEntity (Entity entity) throws Exception { if (entity == null) return null; @@ -436,17 +872,17 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore try { //turn an Entity into a Session - String id = entity.getString(ID); - String contextPath = entity.getString(CONTEXTPATH); - String vhost = entity.getString(VHOST); - long accessed = entity.getLong(ACCESSED); - long lastAccessed = entity.getLong(LASTACCESSED); - long createTime = entity.getLong(CREATETIME); - long cookieSet = entity.getLong(COOKIESETTIME); - String lastNode = entity.getString(LASTNODE); - long expiry = entity.getLong(EXPIRY); - long maxInactive = entity.getLong(MAXINACTIVE); - Blob blob = (Blob) entity.getBlob(ATTRIBUTES); + String id = entity.getString(_model.getId()); + String contextPath = entity.getString(_model.getContextPath()); + String vhost = entity.getString(_model.getVhost()); + long accessed = entity.getLong(_model.getAccessed()); + long lastAccessed = entity.getLong(_model.getLastAccessed()); + long createTime = entity.getLong(_model.getCreateTime()); + long cookieSet = entity.getLong(_model.getCookieSetTime()); + String lastNode = entity.getString(_model.getLastNode()); + long expiry = entity.getLong(_model.getExpiry()); + long maxInactive = entity.getLong(_model.getMaxInactive()); + Blob blob = (Blob) entity.getBlob(_model.getAttributes()); SessionData session = newSessionData (id, createTime, accessed, lastAccessed, maxInactive); session.setLastNode(lastNode); diff --git a/jetty-gcloud/jetty-gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStoreFactory.java b/jetty-gcloud/jetty-gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStoreFactory.java index 8d6759916f0..c54d927b63a 100644 --- a/jetty-gcloud/jetty-gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStoreFactory.java +++ b/jetty-gcloud/jetty-gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStoreFactory.java @@ -30,10 +30,21 @@ import org.eclipse.jetty.server.session.SessionHandler; */ public class GCloudSessionDataStoreFactory extends AbstractSessionDataStoreFactory { + private String _namespace; private int _maxRetries; private int _backoffMs; + private GCloudSessionDataStore.EntityDataModel _model; + public GCloudSessionDataStore.EntityDataModel getEntityDataModel() + { + return _model; + } + + public void setEntityDataModel(GCloudSessionDataStore.EntityDataModel model) + { + _model = model; + } public int getMaxRetries() { @@ -56,6 +67,22 @@ public class GCloudSessionDataStoreFactory extends AbstractSessionDataStoreFacto } + /** + * @return the namespace + */ + public String getNamespace() + { + return _namespace; + } + + /** + * @param namespace the namespace to set + */ + public void setNamespace(String namespace) + { + _namespace = namespace; + } + /** * @see org.eclipse.jetty.server.session.SessionDataStoreFactory#getSessionDataStore(org.eclipse.jetty.server.session.SessionHandler) */ @@ -66,6 +93,7 @@ public class GCloudSessionDataStoreFactory extends AbstractSessionDataStoreFacto ds.setBackoffMs(getBackoffMs()); ds.setMaxRetries(getMaxRetries()); ds.setGracePeriodSec(getGracePeriodSec()); + ds.setNamespace(_namespace); return ds; } diff --git a/jetty-gcloud/pom.xml b/jetty-gcloud/pom.xml index 0a4d85f5612..d73a0ab7667 100644 --- a/jetty-gcloud/pom.xml +++ b/jetty-gcloud/pom.xml @@ -13,7 +13,7 @@ Jetty :: GCloud - 0.2.3 + 0.4.0 diff --git a/jetty-home/src/main/resources/modules/hawtio.mod b/jetty-home/src/main/resources/modules/hawtio.mod index fcc34d15048..2191e37595c 100644 --- a/jetty-home/src/main/resources/modules/hawtio.mod +++ b/jetty-home/src/main/resources/modules/hawtio.mod @@ -1,6 +1,9 @@ [description] Deploys the Hawtio console as a webapplication. +[Tags] +3rdparty + [depend] stats deploy @@ -13,6 +16,7 @@ etc/hawtio.xml etc/hawtio/ lib/hawtio/ https://oss.sonatype.org/content/repositories/public/io/hawt/hawtio-default/1.4.16/hawtio-default-1.4.16.war|lib/hawtio/hawtio.war +basehome:modules/hawtio/hawtio.xml|etc/hawtio.xml [license] Hawtio is a redhat JBoss project released under the Apache License, v2.0 diff --git a/jetty-home/src/main/resources/etc/hawtio.xml b/jetty-home/src/main/resources/modules/hawtio/hawtio.xml similarity index 100% rename from jetty-home/src/main/resources/etc/hawtio.xml rename to jetty-home/src/main/resources/modules/hawtio/hawtio.xml diff --git a/jetty-home/src/main/resources/modules/jamon.mod b/jetty-home/src/main/resources/modules/jamon.mod index 77cc3d1e9d7..5fe87c68754 100644 --- a/jetty-home/src/main/resources/modules/jamon.mod +++ b/jetty-home/src/main/resources/modules/jamon.mod @@ -1,6 +1,9 @@ [description] Deploys the JAMon webapplication +[Tags] +3rdparty + [depend] stats deploy @@ -12,8 +15,9 @@ etc/jamon.xml [files] lib/jamon/ -maven://com.jamonapi/jamon/2.79|lib/jamon/jamon-2.79.jar -maven://com.jamonapi/jamon_war/2.79/war|lib/jamon/jamon.war +maven://com.jamonapi/jamon/2.81|lib/jamon/jamon-2.81.jar +maven://com.jamonapi/jamon_war/2.81/war|lib/jamon/jamon.war +basehome:modules/jamon/jamon.xml|etc/jamon.xml [lib] lib/jamon/**.jar diff --git a/jetty-home/src/main/resources/etc/jamon.xml b/jetty-home/src/main/resources/modules/jamon/jamon.xml similarity index 100% rename from jetty-home/src/main/resources/etc/jamon.xml rename to jetty-home/src/main/resources/modules/jamon/jamon.xml diff --git a/jetty-home/src/main/resources/modules/jminix.mod b/jetty-home/src/main/resources/modules/jminix.mod index 4bd48c9e72d..6310834a283 100644 --- a/jetty-home/src/main/resources/modules/jminix.mod +++ b/jetty-home/src/main/resources/modules/jminix.mod @@ -1,6 +1,9 @@ [description] Deploys the Jminix JMX Console within the server +[Tags] +3rdparty + [depend] stats jmx @@ -26,6 +29,7 @@ maven://commons-collections/commons-collections/3.2|lib/jminix/commons-collectio maven://net.sf.ezmorph/ezmorph/1.0.6|lib/jminix/ezmorph-1.0.6.jar maven://org.jgroups/jgroups/2.12.1.3.Final|lib/jminix/jgroups-2.12.1.3.Final.jar maven://org.jasypt/jasypt/1.8|lib/jminix/jasypt-1.8.jar +basehome:modules/jminix/jminix.xml|etc/jminix.xml [lib] lib/jminix/**.jar diff --git a/jetty-home/src/main/resources/etc/jminix.xml b/jetty-home/src/main/resources/modules/jminix/jminix.xml similarity index 100% rename from jetty-home/src/main/resources/etc/jminix.xml rename to jetty-home/src/main/resources/modules/jminix/jminix.xml diff --git a/jetty-home/src/main/resources/modules/jolokia.mod b/jetty-home/src/main/resources/modules/jolokia.mod index efe8a59185e..a5d21a86ba4 100644 --- a/jetty-home/src/main/resources/modules/jolokia.mod +++ b/jetty-home/src/main/resources/modules/jolokia.mod @@ -1,6 +1,9 @@ [description] Deploys the Jolokia console as a web application. +[Tags] +3rdparty + [depend] stats deploy @@ -11,6 +14,7 @@ etc/jolokia.xml [files] maven://org.jolokia/jolokia-war/1.2.2/war|lib/jolokia/jolokia.war +basehome:modules/jolokia/jolokia.xml|etc/jolokia.xml [license] Jolokia is released under the Apache License 2.0 diff --git a/jetty-home/src/main/resources/etc/jolokia.xml b/jetty-home/src/main/resources/modules/jolokia/jolokia.xml similarity index 100% rename from jetty-home/src/main/resources/etc/jolokia.xml rename to jetty-home/src/main/resources/modules/jolokia/jolokia.xml diff --git a/jetty-http/pom.xml b/jetty-http/pom.xml index 8455a9d3248..9802a9f8a20 100644 --- a/jetty-http/pom.xml +++ b/jetty-http/pom.xml @@ -18,6 +18,11 @@ jetty-util ${project.version} + + org.eclipse.jetty + jetty-io + ${project.version} + org.eclipse.jetty.toolchain jetty-test-helper diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/GZIPContentDecoder.java b/jetty-http/src/main/java/org/eclipse/jetty/http/GZIPContentDecoder.java new file mode 100644 index 00000000000..122421c66c3 --- /dev/null +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/GZIPContentDecoder.java @@ -0,0 +1,423 @@ +// +// ======================================================================== +// Copyright (c) 1995-2016 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.http; + +import java.nio.ByteBuffer; +import java.util.zip.DataFormatException; +import java.util.zip.Inflater; +import java.util.zip.ZipException; + +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.component.Destroyable; + +/** + * Decoder for the "gzip" encoding. + *

+ * A decoder that inflates gzip compressed data that has been + * optimized for async usage with minimal data copies. + */ +public class GZIPContentDecoder implements Destroyable +{ + private final Inflater _inflater = new Inflater(true); + private final ByteBufferPool _pool; + private final int _bufferSize; + private State _state; + private int _size; + private int _value; + private byte _flags; + private ByteBuffer _inflated; + + public GZIPContentDecoder() + { + this(null,2048); + } + + public GZIPContentDecoder(int bufferSize) + { + this(null,bufferSize); + } + + public GZIPContentDecoder(ByteBufferPool pool, int bufferSize) + { + _bufferSize = bufferSize; + _pool = pool; + reset(); + } + + /** Inflate compressed data from a buffer. + * + * @param compressed Buffer containing compressed data. + * @return Buffer containing inflated data. + */ + public ByteBuffer decode(ByteBuffer compressed) + { + decodeChunks(compressed); + if (BufferUtil.isEmpty(_inflated) || _state==State.CRC || _state==State.ISIZE ) + return BufferUtil.EMPTY_BUFFER; + + ByteBuffer result = _inflated; + _inflated = null; + return result; + } + + /** Called when a chunk of data is inflated. + *

The default implementation aggregates all the chunks + * into a single buffer returned from {@link #decode(ByteBuffer)}. + * Derived implementations may choose to consume chunks individually + * and return false to prevent further inflation until a subsequent + * call to {@link #decode(ByteBuffer)} or {@link #decodeChunks(ByteBuffer)}. + * + * @param chunk The inflated chunk of data + * @return False if inflating should continue, or True if the call + * to {@link #decodeChunks(ByteBuffer)} or {@link #decode(ByteBuffer)} + * should return, allowing back pressure of compressed data. + */ + protected boolean decodedChunk(ByteBuffer chunk) + { + if (_inflated==null) + { + _inflated=chunk; + } + else + { + int size = _inflated.remaining() + chunk.remaining(); + if (size<=_inflated.capacity()) + { + BufferUtil.append(_inflated,chunk); + BufferUtil.put(chunk,_inflated); + release(chunk); + } + else + { + ByteBuffer bigger=acquire(size); + int pos=BufferUtil.flipToFill(bigger); + BufferUtil.put(_inflated,bigger); + BufferUtil.put(chunk,bigger); + BufferUtil.flipToFlush(bigger,pos); + release(_inflated); + release(chunk); + _inflated = bigger; + } + } + return false; + } + + /** + * Inflate compressed data. + *

Inflation continues until the compressed block end is reached, there is no + * more compressed data or a call to {@link #decodedChunk(ByteBuffer)} returns true. + * @param compressed Buffer of compressed data to inflate + */ + protected void decodeChunks(ByteBuffer compressed) + { + ByteBuffer buffer = null; + try + { + while (true) + { + switch (_state) + { + case INITIAL: + { + _state = State.ID; + break; + } + + case FLAGS: + { + if ((_flags & 0x04) == 0x04) + { + _state = State.EXTRA_LENGTH; + _size = 0; + _value = 0; + } + else if ((_flags & 0x08) == 0x08) + _state = State.NAME; + else if ((_flags & 0x10) == 0x10) + _state = State.COMMENT; + else if ((_flags & 0x2) == 0x2) + { + _state = State.HCRC; + _size = 0; + _value = 0; + } + else + { + _state = State.DATA; + continue; + } + break; + } + + case DATA: + { + while (true) + { + if (buffer==null) + buffer = acquire(_bufferSize); + + try + { + int length = _inflater.inflate(buffer.array(),buffer.arrayOffset(),buffer.capacity()); + buffer.limit(length); + } + catch (DataFormatException x) + { + throw new ZipException(x.getMessage()); + } + + if (buffer.hasRemaining()) + { + ByteBuffer chunk = buffer; + buffer = null; + if (decodedChunk(chunk)) + return; + } + else if (_inflater.needsInput()) + { + if (!compressed.hasRemaining()) + return; + if (compressed.hasArray()) + { + _inflater.setInput(compressed.array(),compressed.arrayOffset()+compressed.position(),compressed.remaining()); + compressed.position(compressed.limit()); + } + else + { + // TODO use the pool + byte[] input = new byte[compressed.remaining()]; + compressed.get(input); + _inflater.setInput(input); + } + } + else if (_inflater.finished()) + { + int remaining = _inflater.getRemaining(); + compressed.position(compressed.limit() - remaining); + _state = State.CRC; + _size = 0; + _value = 0; + break; + } + } + continue; + } + + default: + break; + } + + if (!compressed.hasRemaining()) + break; + + byte currByte = compressed.get(); + switch (_state) + { + case ID: + { + _value += (currByte & 0xFF) << 8 * _size; + ++_size; + if (_size == 2) + { + if (_value != 0x8B1F) + throw new ZipException("Invalid gzip bytes"); + _state = State.CM; + } + break; + } + case CM: + { + if ((currByte & 0xFF) != 0x08) + throw new ZipException("Invalid gzip compression method"); + _state = State.FLG; + break; + } + case FLG: + { + _flags = currByte; + _state = State.MTIME; + _size = 0; + _value = 0; + break; + } + case MTIME: + { + // Skip the 4 MTIME bytes + ++_size; + if (_size == 4) + _state = State.XFL; + break; + } + case XFL: + { + // Skip XFL + _state = State.OS; + break; + } + case OS: + { + // Skip OS + _state = State.FLAGS; + break; + } + case EXTRA_LENGTH: + { + _value += (currByte & 0xFF) << 8 * _size; + ++_size; + if (_size == 2) + _state = State.EXTRA; + break; + } + case EXTRA: + { + // Skip EXTRA bytes + --_value; + if (_value == 0) + { + // Clear the EXTRA flag and loop on the flags + _flags &= ~0x04; + _state = State.FLAGS; + } + break; + } + case NAME: + { + // Skip NAME bytes + if (currByte == 0) + { + // Clear the NAME flag and loop on the flags + _flags &= ~0x08; + _state = State.FLAGS; + } + break; + } + case COMMENT: + { + // Skip COMMENT bytes + if (currByte == 0) + { + // Clear the COMMENT flag and loop on the flags + _flags &= ~0x10; + _state = State.FLAGS; + } + break; + } + case HCRC: + { + // Skip HCRC + ++_size; + if (_size == 2) + { + // Clear the HCRC flag and loop on the flags + _flags &= ~0x02; + _state = State.FLAGS; + } + break; + } + case CRC: + { + _value += (currByte & 0xFF) << 8 * _size; + ++_size; + if (_size == 4) + { + // From RFC 1952, compliant decoders need not to verify the CRC + _state = State.ISIZE; + _size = 0; + _value = 0; + } + break; + } + case ISIZE: + { + _value += (currByte & 0xFF) << 8 * _size; + ++_size; + if (_size == 4) + { + if (_value != _inflater.getBytesWritten()) + throw new ZipException("Invalid input size"); + + // TODO ByteBuffer result = output == null ? BufferUtil.EMPTY_BUFFER : ByteBuffer.wrap(output); + reset(); + return ; + } + break; + } + default: + throw new ZipException(); + } + } + } + catch (ZipException x) + { + throw new RuntimeException(x); + } + finally + { + if (buffer!=null) + release(buffer); + } + } + + private void reset() + { + _inflater.reset(); + _state = State.INITIAL; + _size = 0; + _value = 0; + _flags = 0; + } + + @Override + public void destroy() + { + _inflater.end(); + } + + public boolean isFinished() + { + return _state == State.INITIAL; + } + + private enum State + { + INITIAL, ID, CM, FLG, MTIME, XFL, OS, FLAGS, EXTRA_LENGTH, EXTRA, NAME, COMMENT, HCRC, DATA, CRC, ISIZE + } + + /** + * @return An indirect buffer of the configured buffersize either from the pool or freshly allocated. + */ + public ByteBuffer acquire(int capacity) + { + return _pool==null?BufferUtil.allocate(capacity):_pool.acquire(capacity,false); + } + + /** + * Release an allocated buffer. + *

This method will called {@link ByteBufferPool#release(ByteBuffer)} if a buffer pool has + * been configured. This method should be called once for all buffers returned from {@link #decode(ByteBuffer)} + * or passed to {@link #decodedChunk(ByteBuffer)}. + * @param buffer The buffer to release. + */ + public void release(ByteBuffer buffer) + { + if (_pool!=null && buffer!=BufferUtil.EMPTY_BUFFER) + _pool.release(buffer); + } +} diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java index 5818e138e5f..0f146ccae1a 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java @@ -19,7 +19,7 @@ package org.eclipse.jetty.http; -import org.eclipse.jetty.util.StringUtil; +import org.eclipse.jetty.util.HostPort; @@ -28,57 +28,20 @@ import org.eclipse.jetty.util.StringUtil; */ public class HostPortHttpField extends HttpField { - private final String _host; - private final int _port; + final HostPort _hostPort; public HostPortHttpField(String authority) { this(HttpHeader.HOST,HttpHeader.HOST.asString(),authority); } - - public HostPortHttpField(HttpHeader header, String name, String authority) + + /* ------------------------------------------------------------ */ + protected HostPortHttpField(HttpHeader header, String name, String authority) { super(header,name,authority); - if (authority==null || authority.length()==0) - throw new IllegalArgumentException("No Authority"); try { - if (authority.charAt(0)=='[') - { - // ipv6reference - int close=authority.lastIndexOf(']'); - if (close<0) - throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad ipv6"); - _host=authority.substring(0,close+1); - - if (authority.length()>close+1) - { - if (authority.charAt(close+1)!=':') - throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad ipv6 port"); - _port=StringUtil.toInt(authority,close+2); - } - else - _port=0; - } - else - { - // ipv4address or hostname - int c = authority.lastIndexOf(':'); - if (c>=0) - { - _host=authority.substring(0,c); - _port=StringUtil.toInt(authority,c+1); - } - else - { - _host=authority; - _port=0; - } - } - } - catch (BadMessageException bm) - { - throw bm; + _hostPort=new HostPort(authority); } catch(Exception e) { @@ -92,7 +55,7 @@ public class HostPortHttpField extends HttpField */ public String getHost() { - return _host; + return _hostPort.getHost(); } /* ------------------------------------------------------------ */ @@ -101,6 +64,16 @@ public class HostPortHttpField extends HttpField */ public int getPort() { - return _port; + return _hostPort.getPort(); + } + + /* ------------------------------------------------------------ */ + /** Get the port. + * @param defaultPort The default port to return if no port set + * @return the port + */ + public int getPort(int defaultPort) + { + return _hostPort.getPort(defaultPort); } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java index 56928b316e9..78768705a16 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpField.java @@ -18,7 +18,6 @@ package org.eclipse.jetty.http; -import java.util.ArrayList; import java.util.Objects; import org.eclipse.jetty.util.StringUtil; @@ -85,113 +84,9 @@ public class HttpField { if (_value == null) return null; - - ArrayList list = new ArrayList<>(); - int state = 0; - int start=0; - int end=0; - StringBuilder builder = new StringBuilder(); - - for (int i=0;i<_value.length();i++) - { - char c = _value.charAt(i); - switch(state) - { - case 0: // initial white space - switch(c) - { - case '"': // open quote - state=2; - break; - - case ',': // ignore leading empty field - break; - - case ' ': // more white space - case '\t': - break; - - default: // character - start=i; - end=i; - state=1; - } - break; - - case 1: // In token - switch(c) - { - case ',': // next field - list.add(_value.substring(start,end+1)); - state=0; - break; - - case ' ': // more white space - case '\t': - break; - - default: - end=i; - } - break; - - case 2: // In Quoted - switch(c) - { - case '\\': // next field - state=3; - break; - - case '"': // end quote - list.add(builder.toString()); - builder.setLength(0); - state=4; - break; - - default: - builder.append(c); - } - break; - - case 3: // In Quoted Quoted - builder.append(c); - state=2; - break; - - case 4: // WS after end quote - switch(c) - { - case ' ': // white space - case '\t': // white space - break; - - case ',': // white space - state=0; - break; - - default: - throw new IllegalArgumentException("c="+(int)c); - - } - break; - } - } - - switch(state) - { - case 0: - break; - case 1: - list.add(_value.substring(start,end+1)); - break; - case 4: - break; - - default: - throw new IllegalArgumentException("state="+state); - } - - return list.toArray(new String[list.size()]); + + QuotedCSV list = new QuotedCSV(false,_value); + return list.getValues().toArray(new String[list.size()]); } /** diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java index 67294d615ca..2c8808f5a61 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java @@ -282,6 +282,100 @@ public class HttpFields implements Iterable return list; } + + /** + * Add comma separated values, but only if not already + * present. + * @param header The header to add the value(s) to + * @param values The value(s) to add + * @return True if headers were modified + */ + public boolean addCSV(HttpHeader header,String... values) + { + QuotedCSV existing = null; + for (HttpField f : this) + { + if (f.getHeader()==header) + { + if (existing==null) + existing = new QuotedCSV(false); + existing.addValue(f.getValue()); + } + } + + String value = addCSV(existing,values); + if (value!=null) + { + add(header,value); + return true; + } + return false; + } + + /** + * Add comma separated values, but only if not already + * present. + * @param name The header to add the value(s) to + * @param values The value(s) to add + * @return True if headers were modified + */ + public boolean addCSV(String name,String... values) + { + QuotedCSV existing = null; + for (HttpField f : this) + { + if (f.getName().equalsIgnoreCase(name)) + { + if (existing==null) + existing = new QuotedCSV(false); + existing.addValue(f.getValue()); + } + } + String value = addCSV(existing,values); + if (value!=null) + { + add(name,value); + return true; + } + return false; + } + + protected String addCSV(QuotedCSV existing,String... values) + { + // remove any existing values from the new values + boolean add = true; + if (existing!=null && !existing.isEmpty()) + { + add = false; + + for (int i=values.length;i-->0;) + { + String unquoted = QuotedCSV.unquote(values[i]); + if (existing.getValues().contains(unquoted)) + values[i] = null; + else + add = true; + } + } + + if (add) + { + StringBuilder value = new StringBuilder(); + for (String v:values) + { + if (v==null) + continue; + if (value.length()>0) + value.append(", "); + value.append(v); + } + if (value.length()>0) + return value.toString(); + } + + return null; + } + /** * Get multiple field values of the same name, split * as a {@link QuotedCSV} @@ -292,11 +386,17 @@ public class HttpFields implements Iterable */ public List getCSV(HttpHeader header,boolean keepQuotes) { - QuotedCSV values = new QuotedCSV(keepQuotes); + QuotedCSV values = null; for (HttpField f : this) + { if (f.getHeader()==header) + { + if (values==null) + values = new QuotedCSV(keepQuotes); values.addValue(f.getValue()); - return values.getValues(); + } + } + return values==null?Collections.emptyList():values.getValues(); } /** @@ -309,11 +409,17 @@ public class HttpFields implements Iterable */ public List getCSV(String name,boolean keepQuotes) { - QuotedCSV values = new QuotedCSV(keepQuotes); + QuotedCSV values = null; for (HttpField f : this) + { if (f.getName().equalsIgnoreCase(name)) + { + if (values==null) + values = new QuotedCSV(keepQuotes); values.addValue(f.getValue()); - return values.getValues(); + } + } + return values==null?Collections.emptyList():values.getValues(); } /** @@ -325,11 +431,18 @@ public class HttpFields implements Iterable */ public List getQualityCSV(HttpHeader header) { - QuotedQualityCSV values = new QuotedQualityCSV(); + QuotedQualityCSV values = null; for (HttpField f : this) + { if (f.getHeader()==header) + { + if (values==null) + values = new QuotedQualityCSV(); values.addValue(f.getValue()); - return values.getValues(); + } + } + + return values==null?Collections.emptyList():values.getValues(); } /** @@ -341,11 +454,17 @@ public class HttpFields implements Iterable */ public List getQualityCSV(String name) { - QuotedQualityCSV values = new QuotedQualityCSV(); + QuotedQualityCSV values = null; for (HttpField f : this) + { if (f.getName().equalsIgnoreCase(name)) + { + if (values==null) + values = new QuotedQualityCSV(); values.addValue(f.getValue()); - return values.getValues(); + } + } + return values==null?Collections.emptyList():values.getValues(); } /** diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java index f743379eb4b..b03133a96b4 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java @@ -18,7 +18,6 @@ package org.eclipse.jetty.http; -import java.io.EOFException; import java.io.IOException; import java.nio.BufferOverflowException; import java.nio.ByteBuffer; diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java index 73916c68a55..f3632923699 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java @@ -28,6 +28,8 @@ import org.eclipse.jetty.http.HttpTokens.EndOfContent; import org.eclipse.jetty.util.ArrayTernaryTrie; import org.eclipse.jetty.util.ArrayTrie; import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.HostPort; +import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.Trie; import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.Utf8StringBuilder; @@ -933,6 +935,7 @@ public class HttpParser break; default: break; + } if (add_to_connection_trie && !_connectionFields.isFull() && _header!=null && _valueString!=null) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSV.java b/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSV.java index fbeb153b917..46c9a098a6e 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSV.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSV.java @@ -22,6 +22,8 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import org.eclipse.jetty.util.QuotedStringTokenizer; + /* ------------------------------------------------------------ */ /** * Implements a quoted comma separated list of values @@ -52,6 +54,9 @@ public class QuotedCSV implements Iterable } /* ------------------------------------------------------------ */ + /** Add and parse a value string(s) + * @param value A value that may contain one or more Quoted CSV items. + */ public void addValue(String value) { StringBuffer buffer = new StringBuffer(); @@ -241,6 +246,15 @@ public class QuotedCSV implements Iterable { } + public int size() + { + return _values.size(); + } + + public boolean isEmpty() + { + return _values.isEmpty(); + } public List getValues() { @@ -252,7 +266,7 @@ public class QuotedCSV implements Iterable { return _values.iterator(); } - + public static String unquote(String s) { // handle trivial cases diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java b/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java index 43c3d1cd289..6c73d27b1fe 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java @@ -42,10 +42,9 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable private final List _quality = new ArrayList<>(); private boolean _sorted = false; - private final Function secondaryOrderingFunction; + private final Function _secondaryOrdering; /* ------------------------------------------------------------ */ - /** * Sorts values with equal quality according to the length of the value String. */ @@ -54,32 +53,35 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable this((s) -> s.length()); } + /* ------------------------------------------------------------ */ /** * Sorts values with equal quality according to given order. + * @param preferredOrder Array indicating the preferred order of known values */ - public QuotedQualityCSV(String[] serverPreferredValueOrder) + public QuotedQualityCSV(String[] preferredOrder) { this((s) -> { - for (int i=0;i secondaryOrderingFunction) + public QuotedQualityCSV(Function secondaryOrdering) { - this.secondaryOrderingFunction = secondaryOrderingFunction; + this._secondaryOrdering = secondaryOrdering; } - /* ------------------------------------------------------------ */ public void addValue(String value) { @@ -148,7 +150,7 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable Double q = _quality.get(i); int compare=last.compareTo(q); - if (compare>0 || (compare==0 && secondaryOrderingFunction.apply(v)0 || (compare==0 && _secondaryOrdering.apply(v) } last=q; - lastOrderIndex=secondaryOrderingFunction.apply(v); + lastOrderIndex=_secondaryOrdering.apply(v); } int last_element=_quality.size(); diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/GZIPContentDecoderTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/GZIPContentDecoderTest.java new file mode 100644 index 00000000000..2c2d7195baa --- /dev/null +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/GZIPContentDecoderTest.java @@ -0,0 +1,343 @@ +// +// ======================================================================== +// Copyright (c) 1995-2016 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.http; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +import org.eclipse.jetty.io.ArrayByteBufferPool; +import org.eclipse.jetty.toolchain.test.TestTracker; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + + +public class GZIPContentDecoderTest +{ + @Rule + public final TestTracker tracker = new TestTracker(); + + + ArrayByteBufferPool pool; + AtomicInteger buffers = new AtomicInteger(0); + + @Before + public void beforeClass() throws Exception + { + buffers.set(0); + pool = new ArrayByteBufferPool() + { + + @Override + public ByteBuffer acquire(int size, boolean direct) + { + buffers.incrementAndGet(); + return super.acquire(size,direct); + } + + @Override + public void release(ByteBuffer buffer) + { + buffers.decrementAndGet(); + super.release(buffer); + } + + }; + } + + @After + public void afterClass() throws Exception + { + assertEquals(0,buffers.get()); + } + + + @Test + public void testStreamNoBlocks() throws Exception + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + GZIPOutputStream output = new GZIPOutputStream(baos); + output.close(); + byte[] bytes = baos.toByteArray(); + + GZIPInputStream input = new GZIPInputStream(new ByteArrayInputStream(bytes), 1); + int read = input.read(); + assertEquals(-1, read); + } + + @Test + public void testStreamBigBlockOneByteAtATime() throws Exception + { + String data = "0123456789ABCDEF"; + for (int i = 0; i < 10; ++i) + data += data; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + GZIPOutputStream output = new GZIPOutputStream(baos); + output.write(data.getBytes(StandardCharsets.UTF_8)); + output.close(); + byte[] bytes = baos.toByteArray(); + + baos = new ByteArrayOutputStream(); + GZIPInputStream input = new GZIPInputStream(new ByteArrayInputStream(bytes), 1); + int read; + while ((read = input.read()) >= 0) + baos.write(read); + assertEquals(data, new String(baos.toByteArray(), StandardCharsets.UTF_8)); + } + + @Test + public void testNoBlocks() throws Exception + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + GZIPOutputStream output = new GZIPOutputStream(baos); + output.close(); + byte[] bytes = baos.toByteArray(); + + GZIPContentDecoder decoder = new GZIPContentDecoder(pool,2048); + ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes)); + assertEquals(0, decoded.remaining()); + } + + @Test + public void testSmallBlock() throws Exception + { + String data = "0"; + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + GZIPOutputStream output = new GZIPOutputStream(baos); + output.write(data.getBytes(StandardCharsets.UTF_8)); + output.close(); + byte[] bytes = baos.toByteArray(); + + GZIPContentDecoder decoder = new GZIPContentDecoder(pool,2048); + ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes)); + assertEquals(data, StandardCharsets.UTF_8.decode(decoded).toString()); + decoder.release(decoded); + } + + @Test + public void testSmallBlockWithGZIPChunkedAtBegin() throws Exception + { + String data = "0"; + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + GZIPOutputStream output = new GZIPOutputStream(baos); + output.write(data.getBytes(StandardCharsets.UTF_8)); + output.close(); + byte[] bytes = baos.toByteArray(); + + // The header is 10 bytes, chunk at 11 bytes + byte[] bytes1 = new byte[11]; + System.arraycopy(bytes, 0, bytes1, 0, bytes1.length); + byte[] bytes2 = new byte[bytes.length - bytes1.length]; + System.arraycopy(bytes, bytes1.length, bytes2, 0, bytes2.length); + + GZIPContentDecoder decoder = new GZIPContentDecoder(pool,2048); + ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes1)); + assertEquals(0, decoded.capacity()); + decoded = decoder.decode(ByteBuffer.wrap(bytes2)); + assertEquals(data, StandardCharsets.UTF_8.decode(decoded).toString()); + decoder.release(decoded); + } + + @Test + public void testSmallBlockWithGZIPChunkedAtEnd() throws Exception + { + String data = "0"; + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + GZIPOutputStream output = new GZIPOutputStream(baos); + output.write(data.getBytes(StandardCharsets.UTF_8)); + output.close(); + byte[] bytes = baos.toByteArray(); + + // The trailer is 8 bytes, chunk the last 9 bytes + byte[] bytes1 = new byte[bytes.length - 9]; + System.arraycopy(bytes, 0, bytes1, 0, bytes1.length); + byte[] bytes2 = new byte[bytes.length - bytes1.length]; + System.arraycopy(bytes, bytes1.length, bytes2, 0, bytes2.length); + + GZIPContentDecoder decoder = new GZIPContentDecoder(pool,2048); + ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes1)); + assertEquals(data, StandardCharsets.UTF_8.decode(decoded).toString()); + assertFalse(decoder.isFinished()); + decoder.release(decoded); + decoded = decoder.decode(ByteBuffer.wrap(bytes2)); + assertEquals(0, decoded.remaining()); + assertTrue(decoder.isFinished()); + decoder.release(decoded); + } + + @Test + public void testSmallBlockWithGZIPTrailerChunked() throws Exception + { + String data = "0"; + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + GZIPOutputStream output = new GZIPOutputStream(baos); + output.write(data.getBytes(StandardCharsets.UTF_8)); + output.close(); + byte[] bytes = baos.toByteArray(); + + // The trailer is 4+4 bytes, chunk the last 3 bytes + byte[] bytes1 = new byte[bytes.length - 3]; + System.arraycopy(bytes, 0, bytes1, 0, bytes1.length); + byte[] bytes2 = new byte[bytes.length - bytes1.length]; + System.arraycopy(bytes, bytes1.length, bytes2, 0, bytes2.length); + + GZIPContentDecoder decoder = new GZIPContentDecoder(pool,2048); + ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(bytes1)); + assertEquals(0, decoded.capacity()); + decoder.release(decoded); + decoded = decoder.decode(ByteBuffer.wrap(bytes2)); + assertEquals(data, StandardCharsets.UTF_8.decode(decoded).toString()); + decoder.release(decoded); + } + + @Test + public void testTwoSmallBlocks() throws Exception + { + String data1 = "0"; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + GZIPOutputStream output = new GZIPOutputStream(baos); + output.write(data1.getBytes(StandardCharsets.UTF_8)); + output.close(); + byte[] bytes1 = baos.toByteArray(); + + String data2 = "1"; + baos = new ByteArrayOutputStream(); + output = new GZIPOutputStream(baos); + output.write(data2.getBytes(StandardCharsets.UTF_8)); + output.close(); + byte[] bytes2 = baos.toByteArray(); + + byte[] bytes = new byte[bytes1.length + bytes2.length]; + System.arraycopy(bytes1, 0, bytes, 0, bytes1.length); + System.arraycopy(bytes2, 0, bytes, bytes1.length, bytes2.length); + + GZIPContentDecoder decoder = new GZIPContentDecoder(pool,2048); + ByteBuffer buffer = ByteBuffer.wrap(bytes); + ByteBuffer decoded = decoder.decode(buffer); + assertEquals(data1, StandardCharsets.UTF_8.decode(decoded).toString()); + assertTrue(decoder.isFinished()); + assertTrue(buffer.hasRemaining()); + decoder.release(decoded); + decoded = decoder.decode(buffer); + assertEquals(data2, StandardCharsets.UTF_8.decode(decoded).toString()); + assertTrue(decoder.isFinished()); + assertFalse(buffer.hasRemaining()); + decoder.release(decoded); + } + + @Test + public void testBigBlock() throws Exception + { + String data = "0123456789ABCDEF"; + for (int i = 0; i < 10; ++i) + data += data; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + GZIPOutputStream output = new GZIPOutputStream(baos); + output.write(data.getBytes(StandardCharsets.UTF_8)); + output.close(); + byte[] bytes = baos.toByteArray(); + + String result = ""; + GZIPContentDecoder decoder = new GZIPContentDecoder(pool,2048); + ByteBuffer buffer = ByteBuffer.wrap(bytes); + while (buffer.hasRemaining()) + { + ByteBuffer decoded = decoder.decode(buffer); + result += StandardCharsets.UTF_8.decode(decoded).toString(); + decoder.release(decoded); + } + assertEquals(data, result); + } + + @Test + public void testBigBlockOneByteAtATime() throws Exception + { + String data = "0123456789ABCDEF"; + for (int i = 0; i < 10; ++i) + data += data; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + GZIPOutputStream output = new GZIPOutputStream(baos); + output.write(data.getBytes(StandardCharsets.UTF_8)); + output.close(); + byte[] bytes = baos.toByteArray(); + + String result = ""; + GZIPContentDecoder decoder = new GZIPContentDecoder(64); + ByteBuffer buffer = ByteBuffer.wrap(bytes); + while (buffer.hasRemaining()) + { + ByteBuffer decoded = decoder.decode(ByteBuffer.wrap(new byte[]{buffer.get()})); + if (decoded.hasRemaining()) + result += StandardCharsets.UTF_8.decode(decoded).toString(); + decoder.release(decoded); + } + assertEquals(data, result); + assertTrue(decoder.isFinished()); + } + + @Test + public void testBigBlockWithExtraBytes() throws Exception + { + String data1 = "0123456789ABCDEF"; + for (int i = 0; i < 10; ++i) + data1 += data1; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + GZIPOutputStream output = new GZIPOutputStream(baos); + output.write(data1.getBytes(StandardCharsets.UTF_8)); + output.close(); + byte[] bytes1 = baos.toByteArray(); + + String data2 = "HELLO"; + byte[] bytes2 = data2.getBytes(StandardCharsets.UTF_8); + + byte[] bytes = new byte[bytes1.length + bytes2.length]; + System.arraycopy(bytes1, 0, bytes, 0, bytes1.length); + System.arraycopy(bytes2, 0, bytes, bytes1.length, bytes2.length); + + String result = ""; + GZIPContentDecoder decoder = new GZIPContentDecoder(64); + ByteBuffer buffer = ByteBuffer.wrap(bytes); + while (buffer.hasRemaining()) + { + ByteBuffer decoded = decoder.decode(buffer); + if (decoded.hasRemaining()) + result += StandardCharsets.UTF_8.decode(decoded).toString(); + decoder.release(decoded); + if (decoder.isFinished()) + break; + } + assertEquals(data1, result); + assertTrue(buffer.hasRemaining()); + assertEquals(data2, StandardCharsets.UTF_8.decode(buffer).toString()); + } +} diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java index 75ccc054302..b5bf00afa71 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpFieldsTest.java @@ -19,6 +19,7 @@ package org.eclipse.jetty.http; import java.nio.ByteBuffer; +import java.util.Collections; import java.util.Enumeration; import java.util.List; import java.util.Locale; @@ -340,7 +341,89 @@ public class HttpFieldsTest } @Test - public void testGetQualityValues() throws Exception + public void testGetCSV() throws Exception + { + HttpFields fields = new HttpFields(); + + fields.put("name0", "value0A,value0B"); + fields.add("name0", "value0C,value0D"); + fields.put("name1", "value1A, \"value\t, 1B\" "); + fields.add("name1", "\"value1C\",\tvalue1D"); + + Enumeration e = fields.getValues("name0"); + assertEquals(true, e.hasMoreElements()); + assertEquals(e.nextElement(), "value0A,value0B"); + assertEquals(true, e.hasMoreElements()); + assertEquals(e.nextElement(), "value0C,value0D"); + assertEquals(false, e.hasMoreElements()); + + e = Collections.enumeration(fields.getCSV("name0",false)); + assertEquals(true, e.hasMoreElements()); + assertEquals(e.nextElement(), "value0A"); + assertEquals(true, e.hasMoreElements()); + assertEquals(e.nextElement(), "value0B"); + assertEquals(true, e.hasMoreElements()); + assertEquals(e.nextElement(), "value0C"); + assertEquals(true, e.hasMoreElements()); + assertEquals(e.nextElement(), "value0D"); + assertEquals(false, e.hasMoreElements()); + + e = Collections.enumeration(fields.getCSV("name1",false)); + assertEquals(true, e.hasMoreElements()); + assertEquals(e.nextElement(), "value1A"); + assertEquals(true, e.hasMoreElements()); + assertEquals(e.nextElement(), "value\t, 1B"); + assertEquals(true, e.hasMoreElements()); + assertEquals(e.nextElement(), "value1C"); + assertEquals(true, e.hasMoreElements()); + assertEquals(e.nextElement(), "value1D"); + assertEquals(false, e.hasMoreElements()); + } + + @Test + public void testAddQuotedCSV() throws Exception + { + HttpFields fields = new HttpFields(); + + fields.put("some", "value"); + fields.add("name", "\"zero\""); + fields.add("name", "one, \"1 + 1\""); + fields.put("other", "value"); + fields.add("name", "three"); + fields.add("name", "four, I V"); + + List list = fields.getCSV("name",false); + assertEquals("zero",HttpFields.valueParameters(list.get(0),null)); + assertEquals("one",HttpFields.valueParameters(list.get(1),null)); + assertEquals("1 + 1",HttpFields.valueParameters(list.get(2),null)); + assertEquals("three",HttpFields.valueParameters(list.get(3),null)); + assertEquals("four",HttpFields.valueParameters(list.get(4),null)); + assertEquals("I V",HttpFields.valueParameters(list.get(5),null)); + + fields.addCSV("name","six"); + list = fields.getCSV("name",false); + assertEquals("zero",HttpFields.valueParameters(list.get(0),null)); + assertEquals("one",HttpFields.valueParameters(list.get(1),null)); + assertEquals("1 + 1",HttpFields.valueParameters(list.get(2),null)); + assertEquals("three",HttpFields.valueParameters(list.get(3),null)); + assertEquals("four",HttpFields.valueParameters(list.get(4),null)); + assertEquals("I V",HttpFields.valueParameters(list.get(5),null)); + assertEquals("six",HttpFields.valueParameters(list.get(6),null)); + + fields.addCSV("name","1 + 1","7","zero"); + list = fields.getCSV("name",false); + assertEquals("zero",HttpFields.valueParameters(list.get(0),null)); + assertEquals("one",HttpFields.valueParameters(list.get(1),null)); + assertEquals("1 + 1",HttpFields.valueParameters(list.get(2),null)); + assertEquals("three",HttpFields.valueParameters(list.get(3),null)); + assertEquals("four",HttpFields.valueParameters(list.get(4),null)); + assertEquals("I V",HttpFields.valueParameters(list.get(5),null)); + assertEquals("six",HttpFields.valueParameters(list.get(6),null)); + assertEquals("7",HttpFields.valueParameters(list.get(7),null)); + } + + @Test + public void testGetQualityCSV() throws Exception { HttpFields fields = new HttpFields(); @@ -351,7 +434,8 @@ public class HttpFieldsTest fields.add("name", "one;q=0.4"); fields.add("name", "three;x=y;q=0.2;a=b,two;q=0.3"); - List list = HttpFields.qualityList(fields.getValues("name",",")); + + List list = fields.getQualityCSV("name"); assertEquals("zero",HttpFields.valueParameters(list.get(0),null)); assertEquals("one",HttpFields.valueParameters(list.get(1),null)); assertEquals("two",HttpFields.valueParameters(list.get(2),null)); diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java index d0cb4555515..0e58a06093d 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java @@ -25,6 +25,7 @@ import java.util.List; import org.eclipse.jetty.http.HttpParser.State; import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.log.StacklessLogging; import org.hamcrest.Matchers; import org.junit.Assert; import org.junit.Before; @@ -1632,16 +1633,19 @@ public class HttpParserTest @Test public void testBadIPv6Host() throws Exception { - ByteBuffer buffer = BufferUtil.toBuffer( + try(StacklessLogging s = new StacklessLogging(HttpParser.class)) + { + ByteBuffer buffer = BufferUtil.toBuffer( "GET / HTTP/1.1\r\n" - + "Host: [::1\r\n" - + "Connection: close\r\n" - + "\r\n"); + + "Host: [::1\r\n" + + "Connection: close\r\n" + + "\r\n"); - HttpParser.RequestHandler handler = new Handler(); - HttpParser parser = new HttpParser(handler); - parser.parseNext(buffer); - Assert.assertThat(_bad, Matchers.containsString("Bad")); + HttpParser.RequestHandler handler = new Handler(); + HttpParser parser = new HttpParser(handler); + parser.parseNext(buffer); + Assert.assertThat(_bad, Matchers.containsString("Bad")); + } } @Test diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpTester.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpTester.java index 75dd55e84d9..caf242b5024 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpTester.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpTester.java @@ -320,7 +320,7 @@ public class HttpTester @Override public void parsedHeader(HttpField field) { - put(field.getName(),field.getValue()); + add(field.getName(),field.getValue()); } @Override diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java index 9afe932316d..bfa2421d52c 100644 --- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java @@ -39,7 +39,6 @@ import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.component.LifeCycle; -import org.eclipse.jetty.util.thread.ExecutionStrategy; import org.eclipse.jetty.util.thread.Scheduler; public class HTTP2ClientConnectionFactory implements ClientConnectionFactory @@ -88,6 +87,20 @@ public class HTTP2ClientConnectionFactory implements ClientConnectionFactory this.listener = listener; } + @Override + public long getMessagesIn() + { + HTTP2ClientSession session = (HTTP2ClientSession)getSession(); + return session.getStreamsOpened(); + } + + @Override + public long getMessagesOut() + { + HTTP2ClientSession session = (HTTP2ClientSession)getSession(); + return session.getStreamsClosed(); + } + @Override public void onOpen() { diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java index 0b57662d39a..295fdf56aaf 100644 --- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java +++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java @@ -18,6 +18,8 @@ package org.eclipse.jetty.http2.client; +import java.util.concurrent.atomic.AtomicLong; + import org.eclipse.jetty.http2.FlowControlStrategy; import org.eclipse.jetty.http2.HTTP2Session; import org.eclipse.jetty.http2.IStream; @@ -36,11 +38,38 @@ public class HTTP2ClientSession extends HTTP2Session { private static final Logger LOG = Log.getLogger(HTTP2ClientSession.class); + private final AtomicLong streamsOpened = new AtomicLong(); + private final AtomicLong streamsClosed = new AtomicLong(); + public HTTP2ClientSession(Scheduler scheduler, EndPoint endPoint, Generator generator, Session.Listener listener, FlowControlStrategy flowControl) { super(scheduler, endPoint, generator, listener, flowControl, 1); } + @Override + protected void onStreamOpened(IStream stream) + { + super.onStreamOpened(stream); + streamsOpened.incrementAndGet(); + } + + @Override + protected void onStreamClosed(IStream stream) + { + super.onStreamClosed(stream); + streamsClosed.incrementAndGet(); + } + + public long getStreamsOpened() + { + return streamsOpened.get(); + } + + public long getStreamsClosed() + { + return streamsClosed.get(); + } + @Override public void onHeaders(HeadersFrame frame) { diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/SessionFailureTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/SessionFailureTest.java index 1b6c60a9ce9..d6bc41c123f 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/SessionFailureTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/SessionFailureTest.java @@ -118,6 +118,14 @@ public class SessionFailureTest extends AbstractTest Assert.assertTrue(writeLatch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(serverFailureLatch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(clientFailureLatch.await(5, TimeUnit.SECONDS)); - Assert.assertFalse(((HTTP2Session)session).getEndPoint().isOpen()); + long start = System.nanoTime(); + long now = System.nanoTime(); + while (((HTTP2Session)session).getEndPoint().isOpen()) + { + if (TimeUnit.NANOSECONDS.toSeconds(now-start)>5) + Assert.fail(); + Thread.sleep(10); + now = System.nanoTime(); + } } } diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamCloseTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamCloseTest.java index ebe47c2fc23..233728e17c0 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamCloseTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamCloseTest.java @@ -23,6 +23,7 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpVersion; @@ -311,6 +312,7 @@ public class StreamCloseTest extends AbstractTest @Test public void testFailedSessionClosesIdleStream() throws Exception { + AtomicReference sessionRef = new AtomicReference<>(); final CountDownLatch latch = new CountDownLatch(1); final List streams = new ArrayList<>(); start(new ServerSessionListener.Adapter() @@ -332,9 +334,7 @@ public class StreamCloseTest extends AbstractTest @Override public void onFailure(Session session, Throwable failure) { - Assert.assertEquals(0, session.getStreams().size()); - for (Stream stream : streams) - Assert.assertTrue(stream.isClosed()); + sessionRef.set(session); latch.countDown(); } }); @@ -350,5 +350,13 @@ public class StreamCloseTest extends AbstractTest session.newStream(request2, new Promise.Adapter<>(), new Stream.Listener.Adapter()); Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); + Session serverSession = sessionRef.get(); + + // Wait for the server to finish the close activities. + Thread.sleep(1000); + + Assert.assertEquals(0, serverSession.getStreams().size()); + for (Stream stream : streams) + Assert.assertTrue(stream.isClosed()); } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java index 9e1186ff3d4..7e08f0f3070 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java @@ -20,8 +20,10 @@ package org.eclipse.jetty.http2; import java.io.IOException; import java.nio.ByteBuffer; +import java.util.ArrayDeque; import java.util.Queue; import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicLong; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.AbstractConnection; @@ -29,12 +31,10 @@ import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.ConcurrentArrayQueue; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.ExecutionStrategy; import org.eclipse.jetty.util.thread.Invocable; -import org.eclipse.jetty.util.thread.Invocable.InvocationType; import org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume; import org.eclipse.jetty.util.thread.strategy.ProduceExecuteConsume; @@ -42,12 +42,13 @@ public class HTTP2Connection extends AbstractConnection { protected static final Logger LOG = Log.getLogger(HTTP2Connection.class); - private final Queue tasks = new ConcurrentArrayQueue<>(); + private final Queue tasks = new ArrayDeque<>(); + private final HTTP2Producer producer = new HTTP2Producer(); + private final AtomicLong bytesIn = new AtomicLong(); private final ByteBufferPool byteBufferPool; private final Parser parser; private final ISession session; private final int bufferSize; - private final HTTP2Producer producer = new HTTP2Producer(); private final ExecutionStrategy blockingStrategy; private final ExecutionStrategy nonBlockingStrategy; @@ -62,12 +63,23 @@ public class HTTP2Connection extends AbstractConnection this.nonBlockingStrategy = new ProduceExecuteConsume(producer, executor); } + @Override + public long getBytesIn() + { + return bytesIn.get(); + } + + @Override + public long getBytesOut() + { + return session.getBytesWritten(); + } + public ISession getSession() { return session; } - protected Parser getParser() { return parser; @@ -95,20 +107,19 @@ public class HTTP2Connection extends AbstractConnection super.onClose(); } - @Override public void onFillable() { throw new UnsupportedOperationException(); } - + private void onFillableBlocking() { if (LOG.isDebugEnabled()) LOG.debug("HTTP2 onFillableBlocking {} ", this); blockingStrategy.produce(); } - + private void onFillableNonBlocking() { if (LOG.isDebugEnabled()) @@ -146,12 +157,12 @@ public class HTTP2Connection extends AbstractConnection protected void offerTask(Runnable task, boolean dispatch) { - tasks.offer(task); - + offerTask(task); + // Because producing calls parse and parse can call offerTask, we have to make sure // we use the same strategy otherwise produce can be reentrant and that messes with // the release mechanism. TODO is this test sufficient to protect from this? - ExecutionStrategy s = Invocable.isNonBlockingInvocation()?nonBlockingStrategy:blockingStrategy; + ExecutionStrategy s = Invocable.isNonBlockingInvocation() ? nonBlockingStrategy : blockingStrategy; if (dispatch) // TODO Why again is this necessary? s.dispatch(); @@ -167,6 +178,22 @@ public class HTTP2Connection extends AbstractConnection session.close(ErrorCode.NO_ERROR.code, "close", Callback.NOOP); } + private void offerTask(Runnable task) + { + synchronized (this) + { + tasks.offer(task); + } + } + + private Runnable pollTask() + { + synchronized (this) + { + return tasks.poll(); + } + } + protected class HTTP2Producer implements ExecutionStrategy.Producer { private final Callback fillableCallback = new FillableCallback(); @@ -174,8 +201,8 @@ public class HTTP2Connection extends AbstractConnection @Override public synchronized Runnable produce() - { - Runnable task = tasks.poll(); + { + Runnable task = pollTask(); if (LOG.isDebugEnabled()) LOG.debug("Dequeued task {}", task); if (task != null) @@ -194,7 +221,7 @@ public class HTTP2Connection extends AbstractConnection while (buffer.hasRemaining()) parser.parse(buffer); - task = tasks.poll(); + task = pollTask(); if (LOG.isDebugEnabled()) LOG.debug("Dequeued new task {}", task); if (task != null) @@ -220,6 +247,10 @@ public class HTTP2Connection extends AbstractConnection session.onShutdown(); return null; } + else + { + bytesIn.addAndGet(filled); + } looping = true; } @@ -237,12 +268,6 @@ public class HTTP2Connection extends AbstractConnection private class FillableCallback implements Callback { - @Override - public InvocationType getInvocationType() - { - return InvocationType.EITHER; - } - @Override public void succeeded() { @@ -257,5 +282,11 @@ public class HTTP2Connection extends AbstractConnection { onFillInterestedFailed(x); } + + @Override + public InvocationType getInvocationType() + { + return InvocationType.EITHER; + } } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 550fbeb4521..772b26962fd 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -31,6 +31,7 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import org.eclipse.jetty.http2.api.Session; @@ -75,6 +76,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio private final AtomicInteger sendWindow = new AtomicInteger(); private final AtomicInteger recvWindow = new AtomicInteger(); private final AtomicReference closed = new AtomicReference<>(CloseState.NOT_CLOSED); + private final AtomicLong bytesWritten = new AtomicLong(); private final Scheduler scheduler; private final EndPoint endPoint; private final Generator generator; @@ -197,6 +199,12 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio return generator; } + @Override + public long getBytesWritten() + { + return bytesWritten.get(); + } + @Override public void onData(final DataFrame frame) { @@ -460,8 +468,8 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio @Override public void onConnectionFailure(int error, String reason) { - close(error, reason, Callback.NOOP); notifyFailure(this, new IOException(String.format("%d/%s", error, reason))); + close(error, reason, Callback.NOOP); } @Override @@ -752,6 +760,8 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio else remoteStreamCount.decrementAndGet(); + onStreamClosed(stream); + flowControl.onStreamDestroyed(stream); if (LOG.isDebugEnabled()) @@ -940,6 +950,14 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio onConnectionFailure(ErrorCode.PROTOCOL_ERROR.code, "upgrade"); } + protected void onStreamOpened(IStream stream) + { + } + + protected void onStreamClosed(IStream stream) + { + } + public void disconnect() { if (LOG.isDebugEnabled()) @@ -979,8 +997,8 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio protected void abort(Throwable failure) { - terminate(); notifyFailure(this, failure); + terminate(); } public boolean isDisconnected() @@ -1096,6 +1114,8 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio private class ControlEntry extends HTTP2Flusher.Entry { + private int bytes; + private ControlEntry(Frame frame, IStream stream, Callback callback) { super(frame, stream, callback); @@ -1103,7 +1123,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio protected boolean generate(ByteBufferPool.Lease lease) { - generator.control(lease, frame); + bytes = generator.control(lease, frame); if (LOG.isDebugEnabled()) LOG.debug("Generated {}", frame); prepare(); @@ -1145,10 +1165,12 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio @Override public void succeeded() { + bytesWritten.addAndGet(bytes); switch (frame.getType()) { case HEADERS: { + onStreamOpened(stream); HeadersFrame headersFrame = (HeadersFrame)frame; if (stream.updateClose(headersFrame.isEndStream(), true)) removeStream(stream); @@ -1198,8 +1220,9 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio private class DataEntry extends HTTP2Flusher.Entry { - private int remaining; - private int generated; + private int bytes; + private int dataRemaining; + private int dataWritten; private DataEntry(DataFrame frame, IStream stream, Callback callback) { @@ -1209,35 +1232,37 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio // of data frames that cannot be completely written due to // the flow control window exhausting, since in that case // we would have to count the padding only once. - remaining = frame.remaining(); + dataRemaining = frame.remaining(); } @Override public int dataRemaining() { - return remaining; + return dataRemaining; } protected boolean generate(ByteBufferPool.Lease lease) { - int toWrite = dataRemaining(); + int dataRemaining = dataRemaining(); int sessionSendWindow = getSendWindow(); int streamSendWindow = stream.updateSendWindow(0); int window = Math.min(streamSendWindow, sessionSendWindow); - if (window <= 0 && toWrite > 0) + if (window <= 0 && dataRemaining > 0) return false; - int length = Math.min(toWrite, window); + int length = Math.min(dataRemaining, window); - int generated = generator.data(lease, (DataFrame)frame, length); + // Only one DATA frame is generated. + bytes = generator.data(lease, (DataFrame)frame, length); + int written = bytes - Frame.HEADER_LENGTH; if (LOG.isDebugEnabled()) - LOG.debug("Generated {}, length/window/data={}/{}/{}", frame, generated, window, toWrite); + LOG.debug("Generated {}, length/window/data={}/{}/{}", frame, written, window, dataRemaining); - this.generated += generated; - this.remaining -= generated; + this.dataWritten = written; + this.dataRemaining -= written; - flowControl.onDataSending(stream, generated); + flowControl.onDataSending(stream, written); return true; } @@ -1245,8 +1270,9 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio @Override public void succeeded() { - flowControl.onDataSent(stream, generated); - generated = 0; + bytesWritten.addAndGet(bytes); + flowControl.onDataSent(stream, dataWritten); + // Do we have more to send ? DataFrame dataFrame = (DataFrame)frame; if (dataRemaining() == 0) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java index 81eea91c008..f9c76c91628 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java @@ -127,4 +127,9 @@ public interface ISession extends Session * @param frame the synthetic frame to process */ public void onFrame(Frame frame); + + /** + * @return the number of bytes written by this session + */ + public long getBytesWritten(); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/ResetFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/ResetFrame.java index 3e142371c75..681e93f0865 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/ResetFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/ResetFrame.java @@ -24,6 +24,8 @@ import org.eclipse.jetty.http2.ErrorCode; public class ResetFrame extends Frame { + public static final int RESET_LENGTH = 4; + private final int streamId; private final int error; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java index 20013a8df26..89f39c2c1cb 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/frames/WindowUpdateFrame.java @@ -20,6 +20,8 @@ package org.eclipse.jetty.http2.frames; public class WindowUpdateFrame extends Frame { + public static final int WINDOW_UPDATE_LENGTH = 4; + private final int streamId; private final int windowDelta; diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java index 66bfcb75151..0c2bb8f7e07 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DataGenerator.java @@ -63,7 +63,7 @@ public class DataGenerator data.limit(limit); generateFrame(lease, streamId, slice, false); } - return length; + return Frame.HEADER_LENGTH + length; } private void generateFrame(ByteBufferPool.Lease lease, int streamId, ByteBuffer data, boolean last) @@ -75,10 +75,9 @@ public class DataGenerator flags |= Flags.END_STREAM; ByteBuffer header = headerGenerator.generate(lease, FrameType.DATA, Frame.HEADER_LENGTH + length, length, flags, streamId); - BufferUtil.flipToFlush(header, 0); lease.append(header, true); - + // Skip empty data buffers. if (data.remaining() > 0) lease.append(data, false); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DisconnectGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DisconnectGenerator.java index 03a9d095607..93037799d65 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DisconnectGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/DisconnectGenerator.java @@ -29,7 +29,8 @@ public class DisconnectGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame) + public int generate(ByteBufferPool.Lease lease, Frame frame) { + return 0; } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/FrameGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/FrameGenerator.java index 486f32fb05f..30f2c980e71 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/FrameGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/FrameGenerator.java @@ -33,7 +33,7 @@ public abstract class FrameGenerator this.headerGenerator = headerGenerator; } - public abstract void generate(ByteBufferPool.Lease lease, Frame frame); + public abstract int generate(ByteBufferPool.Lease lease, Frame frame); protected ByteBuffer generateHeader(ByteBufferPool.Lease lease, FrameType frameType, int length, int flags, int streamId) { diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java index 0c4c12063bf..bd873c47b5e 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java @@ -75,9 +75,9 @@ public class Generator headerGenerator.setMaxFrameSize(maxFrameSize); } - public void control(ByteBufferPool.Lease lease, Frame frame) + public int control(ByteBufferPool.Lease lease, Frame frame) { - generators[frame.getType().getType()].generate(lease, frame); + return generators[frame.getType().getType()].generate(lease, frame); } public int data(ByteBufferPool.Lease lease, DataFrame frame, int maxLength) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java index 34b3ddba4d7..697d158570e 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/GoAwayGenerator.java @@ -36,13 +36,13 @@ public class GoAwayGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame) + public int generate(ByteBufferPool.Lease lease, Frame frame) { GoAwayFrame goAwayFrame = (GoAwayFrame)frame; - generateGoAway(lease, goAwayFrame.getLastStreamId(), goAwayFrame.getError(), goAwayFrame.getPayload()); + return generateGoAway(lease, goAwayFrame.getLastStreamId(), goAwayFrame.getError(), goAwayFrame.getPayload()); } - public void generateGoAway(ByteBufferPool.Lease lease, int lastStreamId, int error, byte[] payload) + public int generateGoAway(ByteBufferPool.Lease lease, int lastStreamId, int error, byte[] payload) { if (lastStreamId < 0) throw new IllegalArgumentException("Invalid last stream id: " + lastStreamId); @@ -62,11 +62,11 @@ public class GoAwayGenerator extends FrameGenerator header.putInt(error); if (payload != null) - { header.put(payload); - } BufferUtil.flipToFlush(header, 0); lease.append(header, true); + + return Frame.HEADER_LENGTH + length; } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java index 7ceab1c17c9..2db5c5de601 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/HeadersGenerator.java @@ -50,13 +50,13 @@ public class HeadersGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame) + public int generate(ByteBufferPool.Lease lease, Frame frame) { HeadersFrame headersFrame = (HeadersFrame)frame; - generateHeaders(lease, headersFrame.getStreamId(), headersFrame.getMetaData(), headersFrame.getPriority(), headersFrame.isEndStream()); + return generateHeaders(lease, headersFrame.getStreamId(), headersFrame.getMetaData(), headersFrame.getPriority(), headersFrame.isEndStream()); } - public void generateHeaders(ByteBufferPool.Lease lease, int streamId, MetaData metaData, PriorityFrame priority, boolean endStream) + public int generateHeaders(ByteBufferPool.Lease lease, int streamId, MetaData metaData, PriorityFrame priority, boolean endStream) { if (streamId < 0) throw new IllegalArgumentException("Invalid stream id: " + streamId); @@ -87,10 +87,11 @@ public class HeadersGenerator extends FrameGenerator generatePriority(header, priority); BufferUtil.flipToFlush(header, 0); lease.append(header, true); - hpacked.limit(maxHeaderBlockFragment); lease.append(hpacked.slice(), false); + int totalLength = Frame.HEADER_LENGTH + length; + int position = maxHeaderBlockFragment; int limit = position + maxHeaderBlockFragment; while (limit < hpackedLength) @@ -102,6 +103,7 @@ public class HeadersGenerator extends FrameGenerator lease.append(hpacked.slice(), false); position += maxHeaderBlockFragment; limit += maxHeaderBlockFragment; + totalLength += Frame.HEADER_LENGTH + maxHeaderBlockFragment; } hpacked.position(position).limit(hpackedLength); @@ -109,6 +111,9 @@ public class HeadersGenerator extends FrameGenerator BufferUtil.flipToFlush(header, 0); lease.append(header, true); lease.append(hpacked, true); + totalLength += Frame.HEADER_LENGTH + hpacked.remaining(); + + return totalLength; } else { @@ -125,6 +130,8 @@ public class HeadersGenerator extends FrameGenerator BufferUtil.flipToFlush(header, 0); lease.append(header, true); lease.append(hpacked, true); + + return Frame.HEADER_LENGTH + length; } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java index 5058dd6ab03..8015bf11c01 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PingGenerator.java @@ -35,13 +35,13 @@ public class PingGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame) + public int generate(ByteBufferPool.Lease lease, Frame frame) { PingFrame pingFrame = (PingFrame)frame; - generatePing(lease, pingFrame.getPayload(), pingFrame.isReply()); + return generatePing(lease, pingFrame.getPayload(), pingFrame.isReply()); } - public void generatePing(ByteBufferPool.Lease lease, byte[] payload, boolean reply) + public int generatePing(ByteBufferPool.Lease lease, byte[] payload, boolean reply) { if (payload.length != PingFrame.PING_LENGTH) throw new IllegalArgumentException("Invalid payload length: " + payload.length); @@ -52,5 +52,7 @@ public class PingGenerator extends FrameGenerator BufferUtil.flipToFlush(header, 0); lease.append(header, true); + + return Frame.HEADER_LENGTH + PingFrame.PING_LENGTH; } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PrefaceGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PrefaceGenerator.java index 101c948d8cb..1e1490d202e 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PrefaceGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PrefaceGenerator.java @@ -32,8 +32,9 @@ public class PrefaceGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame) + public int generate(ByteBufferPool.Lease lease, Frame frame) { lease.append(ByteBuffer.wrap(PrefaceFrame.PREFACE_BYTES), false); + return PrefaceFrame.PREFACE_BYTES.length; } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PriorityGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PriorityGenerator.java index 2fc7c10e9de..e7a53eb538e 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PriorityGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PriorityGenerator.java @@ -35,18 +35,19 @@ public class PriorityGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame) + public int generate(ByteBufferPool.Lease lease, Frame frame) { PriorityFrame priorityFrame = (PriorityFrame)frame; - generatePriority(lease, priorityFrame.getStreamId(), priorityFrame.getParentStreamId(), priorityFrame.getWeight(), priorityFrame.isExclusive()); + return generatePriority(lease, priorityFrame.getStreamId(), priorityFrame.getParentStreamId(), priorityFrame.getWeight(), priorityFrame.isExclusive()); } - public void generatePriority(ByteBufferPool.Lease lease, int streamId, int parentStreamId, int weight, boolean exclusive) + public int generatePriority(ByteBufferPool.Lease lease, int streamId, int parentStreamId, int weight, boolean exclusive) { ByteBuffer header = generateHeader(lease, FrameType.PRIORITY, PriorityFrame.PRIORITY_LENGTH, Flags.NONE, streamId); generatePriorityBody(header, streamId, parentStreamId, weight, exclusive); BufferUtil.flipToFlush(header, 0); lease.append(header, true); + return Frame.HEADER_LENGTH + PriorityFrame.PRIORITY_LENGTH; } public void generatePriorityBody(ByteBuffer header, int streamId, int parentStreamId, int weight, boolean exclusive) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java index a6ebb259e5b..5566fdd5df0 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/PushPromiseGenerator.java @@ -40,13 +40,13 @@ public class PushPromiseGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame) + public int generate(ByteBufferPool.Lease lease, Frame frame) { PushPromiseFrame pushPromiseFrame = (PushPromiseFrame)frame; - generatePushPromise(lease, pushPromiseFrame.getStreamId(), pushPromiseFrame.getPromisedStreamId(), pushPromiseFrame.getMetaData()); + return generatePushPromise(lease, pushPromiseFrame.getStreamId(), pushPromiseFrame.getPromisedStreamId(), pushPromiseFrame.getMetaData()); } - public void generatePushPromise(ByteBufferPool.Lease lease, int streamId, int promisedStreamId, MetaData metaData) + public int generatePushPromise(ByteBufferPool.Lease lease, int streamId, int promisedStreamId, MetaData metaData) { if (streamId < 0) throw new IllegalArgumentException("Invalid stream id: " + streamId); @@ -73,5 +73,7 @@ public class PushPromiseGenerator extends FrameGenerator lease.append(header, true); lease.append(hpacked, true); + + return Frame.HEADER_LENGTH + length; } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/ResetGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/ResetGenerator.java index 87758feaa94..0fcb05e2494 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/ResetGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/ResetGenerator.java @@ -35,22 +35,22 @@ public class ResetGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame) + public int generate(ByteBufferPool.Lease lease, Frame frame) { ResetFrame resetFrame = (ResetFrame)frame; - generateReset(lease, resetFrame.getStreamId(), resetFrame.getError()); + return generateReset(lease, resetFrame.getStreamId(), resetFrame.getError()); } - public void generateReset(ByteBufferPool.Lease lease, int streamId, int error) + public int generateReset(ByteBufferPool.Lease lease, int streamId, int error) { if (streamId < 0) throw new IllegalArgumentException("Invalid stream id: " + streamId); - ByteBuffer header = generateHeader(lease, FrameType.RST_STREAM, 4, Flags.NONE, streamId); - + ByteBuffer header = generateHeader(lease, FrameType.RST_STREAM, ResetFrame.RESET_LENGTH, Flags.NONE, streamId); header.putInt(error); - BufferUtil.flipToFlush(header, 0); lease.append(header, true); + + return Frame.HEADER_LENGTH + ResetFrame.RESET_LENGTH; } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java index 363d2e1e1ed..4dcd3dff359 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/SettingsGenerator.java @@ -36,13 +36,13 @@ public class SettingsGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame) + public int generate(ByteBufferPool.Lease lease, Frame frame) { SettingsFrame settingsFrame = (SettingsFrame)frame; - generateSettings(lease, settingsFrame.getSettings(), settingsFrame.isReply()); + return generateSettings(lease, settingsFrame.getSettings(), settingsFrame.isReply()); } - public void generateSettings(ByteBufferPool.Lease lease, Map settings, boolean reply) + public int generateSettings(ByteBufferPool.Lease lease, Map settings, boolean reply) { // Two bytes for the identifier, four bytes for the value. int entryLength = 2 + 4; @@ -60,5 +60,7 @@ public class SettingsGenerator extends FrameGenerator BufferUtil.flipToFlush(header, 0); lease.append(header, true); + + return Frame.HEADER_LENGTH + length; } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/WindowUpdateGenerator.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/WindowUpdateGenerator.java index a047f64149f..f9acca0f994 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/WindowUpdateGenerator.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/WindowUpdateGenerator.java @@ -35,20 +35,22 @@ public class WindowUpdateGenerator extends FrameGenerator } @Override - public void generate(ByteBufferPool.Lease lease, Frame frame) + public int generate(ByteBufferPool.Lease lease, Frame frame) { WindowUpdateFrame windowUpdateFrame = (WindowUpdateFrame)frame; - generateWindowUpdate(lease, windowUpdateFrame.getStreamId(), windowUpdateFrame.getWindowDelta()); + return generateWindowUpdate(lease, windowUpdateFrame.getStreamId(), windowUpdateFrame.getWindowDelta()); } - public void generateWindowUpdate(ByteBufferPool.Lease lease, int streamId, int windowUpdate) + public int generateWindowUpdate(ByteBufferPool.Lease lease, int streamId, int windowUpdate) { if (windowUpdate < 0) throw new IllegalArgumentException("Invalid window update: " + windowUpdate); - ByteBuffer header = generateHeader(lease, FrameType.WINDOW_UPDATE, 4, Flags.NONE, streamId); + ByteBuffer header = generateHeader(lease, FrameType.WINDOW_UPDATE, WindowUpdateFrame.WINDOW_UPDATE_LENGTH, Flags.NONE, streamId); header.putInt(windowUpdate); BufferUtil.flipToFlush(header, 0); lease.append(header, true); + + return Frame.HEADER_LENGTH + WindowUpdateFrame.WINDOW_UPDATE_LENGTH; } } diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java index d730589a70a..0da6986cb86 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java @@ -108,6 +108,7 @@ public class DataGenerateParseTest while (true) { generated += generator.generateData(lease, 13, slice, true, slice.remaining()); + generated -= Frame.HEADER_LENGTH; if (generated == data.remaining()) break; } @@ -147,6 +148,7 @@ public class DataGenerateParseTest while (true) { generated += generator.generateData(lease, 13, slice, true, slice.remaining()); + generated -= Frame.HEADER_LENGTH; if (generated == data.remaining()) break; } diff --git a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpReceiverOverHTTP2.java b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpReceiverOverHTTP2.java index 5a3d01e867a..f95c09d429f 100644 --- a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpReceiverOverHTTP2.java +++ b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpReceiverOverHTTP2.java @@ -30,6 +30,7 @@ import org.eclipse.jetty.client.HttpReceiver; import org.eclipse.jetty.client.HttpResponse; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.ErrorCode; import org.eclipse.jetty.http2.api.Stream; @@ -79,7 +80,9 @@ public class HttpReceiverOverHTTP2 extends HttpReceiver implements Stream.Listen if (responseHeaders(exchange)) { - if (frame.isEndStream()) + int status = metaData.getStatus(); + boolean informational = HttpStatus.isInformational(status) && status != HttpStatus.SWITCHING_PROTOCOLS_101; + if (frame.isEndStream() || informational) responseSuccess(exchange); } } @@ -159,8 +162,14 @@ public class HttpReceiverOverHTTP2 extends HttpReceiver implements Stream.Listen { dataInfo = queue.poll(); } + if (dataInfo == null) + { + DataInfo prevDataInfo = this.dataInfo; + if (prevDataInfo != null && prevDataInfo.last) + return Action.SUCCEEDED; return Action.IDLE; + } this.dataInfo = dataInfo; responseContent(dataInfo.exchange, dataInfo.buffer, this); @@ -173,11 +182,15 @@ public class HttpReceiverOverHTTP2 extends HttpReceiver implements Stream.Listen ByteBufferPool byteBufferPool = getHttpDestination().getHttpClient().getByteBufferPool(); byteBufferPool.release(dataInfo.buffer); dataInfo.callback.succeeded(); - if (dataInfo.last) - responseSuccess(dataInfo.exchange); super.succeeded(); } + @Override + protected void onCompleteSuccess() + { + responseSuccess(dataInfo.exchange); + } + @Override protected void onCompleteFailure(Throwable failure) { diff --git a/jetty-http2/http2-server/src/main/config/etc/jetty-http2.xml b/jetty-http2/http2-server/src/main/config/etc/jetty-http2.xml index b23f25b41f7..226941d5e71 100644 --- a/jetty-http2/http2-server/src/main/config/etc/jetty-http2.xml +++ b/jetty-http2/http2-server/src/main/config/etc/jetty-http2.xml @@ -10,7 +10,7 @@ - + @@ -23,4 +23,3 @@ - diff --git a/jetty-http2/http2-server/src/main/config/etc/jetty-http2c.xml b/jetty-http2/http2-server/src/main/config/etc/jetty-http2c.xml index ccd3af14048..4e8610cc1ef 100644 --- a/jetty-http2/http2-server/src/main/config/etc/jetty-http2c.xml +++ b/jetty-http2/http2-server/src/main/config/etc/jetty-http2c.xml @@ -10,9 +10,8 @@ - + - diff --git a/jetty-http2/http2-server/src/main/config/modules/http2.mod b/jetty-http2/http2-server/src/main/config/modules/http2.mod index ece1e331b52..5927f571279 100644 --- a/jetty-http2/http2-server/src/main/config/modules/http2.mod +++ b/jetty-http2/http2-server/src/main/config/modules/http2.mod @@ -2,6 +2,12 @@ Enables HTTP2 protocol support on the TLS(SSL) Connector, using the ALPN extension to select which protocol to use. +[Tags] +connector +http2 +http +ssl + [depend] ssl alpn @@ -16,5 +22,5 @@ etc/jetty-http2.xml ## Max number of concurrent streams per connection # jetty.http2.maxConcurrentStreams=1024 -## Initial stream send (server to client) window -# jetty.http2.initialStreamSendWindow=65535 +## Initial stream receive window (client to server) +# jetty.http2.initialStreamRecvWindow=65535 diff --git a/jetty-http2/http2-server/src/main/config/modules/http2c.mod b/jetty-http2/http2-server/src/main/config/modules/http2c.mod index dfca925ee57..b0fee130af5 100644 --- a/jetty-http2/http2-server/src/main/config/modules/http2c.mod +++ b/jetty-http2/http2-server/src/main/config/modules/http2c.mod @@ -2,6 +2,11 @@ Enables the HTTP2C protocol on the HTTP Connector The connector will accept both HTTP/1 and HTTP/2 connections. +[Tags] +connector +http2 +http + [depend] http @@ -15,5 +20,5 @@ etc/jetty-http2c.xml ## Max number of concurrent streams per connection # jetty.http2c.maxConcurrentStreams=1024 -## Initial stream send (server to client) window -# jetty.http2c.initialStreamSendWindow=65535 +## Initial stream receive window (client to server) +# jetty.http2c.initialStreamRecvWindow=65535 diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java index 892ca2a9ab7..2055bdbf071 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java @@ -35,8 +35,6 @@ import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.Name; import org.eclipse.jetty.util.component.LifeCycle; -import org.eclipse.jetty.util.thread.ExecutionStrategy; -import org.eclipse.jetty.util.thread.strategy.ProduceExecuteConsume; @ManagedObject public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConnectionFactory @@ -49,7 +47,7 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne private int maxConcurrentStreams = 128; private int maxHeaderBlockFragment = 0; private FlowControlStrategy.Factory flowControlStrategyFactory = () -> new BufferingFlowControlStrategy(0.5F); - private ExecutionStrategy.Factory executionStrategyFactory = new ProduceExecuteConsume.Factory(); + private long streamIdleTimeout; public AbstractHTTP2ServerConnectionFactory(@Name("config") HttpConfiguration httpConfiguration) { @@ -99,26 +97,6 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne this.initialStreamRecvWindow = initialStreamRecvWindow; } - /** - * @deprecated use {@link #getInitialStreamRecvWindow()} instead, - * since "send" is meant on the client, but this is the server configuration - */ - @Deprecated - public int getInitialStreamSendWindow() - { - return getInitialStreamRecvWindow(); - } - - /** - * @deprecated use {@link #setInitialStreamRecvWindow(int)} instead, - * since "send" is meant on the client, but this is the server configuration - */ - @Deprecated - public void setInitialStreamSendWindow(int initialStreamSendWindow) - { - setInitialStreamRecvWindow(initialStreamSendWindow); - } - @ManagedAttribute("The max number of concurrent streams per session") public int getMaxConcurrentStreams() { @@ -150,6 +128,17 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne this.flowControlStrategyFactory = flowControlStrategyFactory; } + @ManagedAttribute("The stream idle timeout in milliseconds") + public long getStreamIdleTimeout() + { + return streamIdleTimeout; + } + + public void setStreamIdleTimeout(long streamIdleTimeout) + { + this.streamIdleTimeout = streamIdleTimeout; + } + public HttpConfiguration getHttpConfiguration() { return httpConfiguration; @@ -168,8 +157,11 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne // For a single stream in a connection, there will be a race between // the stream idle timeout and the connection idle timeout. However, // the typical case is that the connection will be busier and the - // stream idle timeout will expire earlier that the connection's. - session.setStreamIdleTimeout(endPoint.getIdleTimeout()); + // stream idle timeout will expire earlier than the connection's. + long streamIdleTimeout = getStreamIdleTimeout(); + if (streamIdleTimeout <= 0) + streamIdleTimeout = endPoint.getIdleTimeout(); + session.setStreamIdleTimeout(streamIdleTimeout); session.setInitialSessionRecvWindow(getInitialSessionRecvWindow()); ServerParser parser = newServerParser(connector, session); diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java index 65c95318bbb..f817501ed99 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java @@ -20,10 +20,12 @@ package org.eclipse.jetty.http2.server; import java.io.Closeable; import java.nio.ByteBuffer; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.List; import java.util.Queue; import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicLong; import org.eclipse.jetty.http.BadMessageException; import org.eclipse.jetty.http.HttpField; @@ -53,13 +55,10 @@ import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.util.B64Code; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.ConcurrentArrayQueue; import org.eclipse.jetty.util.TypeUtil; -import org.eclipse.jetty.util.thread.ExecutionStrategy; public class HTTP2ServerConnection extends HTTP2Connection implements Connection.UpgradeTo { - /** * @param protocol A HTTP2 protocol variant * @return True if the protocol version is supported @@ -84,10 +83,12 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection } } - private final Queue channels = new ConcurrentArrayQueue<>(); + private final Queue channels = new ArrayDeque<>(); + private final List upgradeFrames = new ArrayList<>(); + private final AtomicLong totalRequests = new AtomicLong(); + private final AtomicLong totalResponses = new AtomicLong(); private final ServerSessionListener listener; private final HttpConfiguration httpConfig; - private final List upgradeFrames = new ArrayList<>(); public HTTP2ServerConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, HttpConfiguration httpConfig, ServerParser parser, ISession session, int inputBufferSize, ServerSessionListener listener) { @@ -96,6 +97,18 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection this.httpConfig = httpConfig; } + @Override + public long getMessagesIn() + { + return totalRequests.get(); + } + + @Override + public long getMessagesOut() + { + return totalResponses.get(); + } + @Override protected ServerParser getParser() { @@ -154,9 +167,9 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection public boolean onStreamTimeout(IStream stream, Throwable failure) { HttpChannelOverHTTP2 channel = (HttpChannelOverHTTP2)stream.getAttribute(IStream.CHANNEL_ATTRIBUTE); - boolean result = !channel.isRequestHandled(); + boolean result = channel.onStreamTimeout(failure); if (LOG.isDebugEnabled()) - LOG.debug("{} idle timeout on {}: {}", result ? "Processing" : "Ignoring", stream, failure); + LOG.debug("{} idle timeout on {}: {}", result ? "Processed" : "Ignored", stream, failure); return result; } @@ -178,7 +191,7 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection result &= !channel.isRequestHandled(); } if (LOG.isDebugEnabled()) - LOG.debug("{} idle timeout on {}: {}", result ? "Processing" : "Ignoring", session, failure); + LOG.debug("{} idle timeout on {}: {}", result ? "Processed" : "Ignored", session, failure); return result; } @@ -203,7 +216,7 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection private HttpChannelOverHTTP2 provideHttpChannel(Connector connector, IStream stream) { - HttpChannelOverHTTP2 channel = channels.poll(); + HttpChannelOverHTTP2 channel = pollChannel(); if (channel != null) { channel.getHttpTransport().setStream(stream); @@ -222,6 +235,22 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection return channel; } + private void offerChannel(HttpChannelOverHTTP2 channel) + { + synchronized (this) + { + channels.offer(channel); + } + } + + private HttpChannelOverHTTP2 pollChannel() + { + synchronized (this) + { + return channels.poll(); + } + } + public boolean upgrade(Request request) { if (HttpMethod.PRI.is(request.getMethod())) @@ -264,21 +293,29 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection } @Override - public void recycle() + public Runnable onRequest(HeadersFrame frame) { - getStream().removeAttribute(IStream.CHANNEL_ATTRIBUTE); - super.recycle(); - channels.offer(this); + totalRequests.incrementAndGet(); + return super.onRequest(frame); } @Override public void onCompleted() { + totalResponses.incrementAndGet(); super.onCompleted(); if (!getStream().isReset()) recycle(); } + @Override + public void recycle() + { + getStream().removeAttribute(IStream.CHANNEL_ATTRIBUTE); + super.recycle(); + offerChannel(this); + } + @Override public void close() { diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java index 0af8f165e82..8295acc5c20 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java @@ -133,6 +133,12 @@ public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionF getConnection().onSessionFailure(new IOException("HTTP/2 " + error + reason)); } + @Override + public void onFailure(Session session, Throwable failure) + { + getConnection().onSessionFailure(failure); + } + @Override public void onHeaders(Stream stream, HeadersFrame frame) { diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java index c10ebddf8ab..cb5de81d6c2 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java @@ -89,6 +89,7 @@ public class HTTP2ServerSession extends HTTP2Session implements ServerParser.Lis IStream stream = createRemoteStream(frame.getStreamId()); if (stream != null) { + onStreamOpened(stream); stream.process(frame, Callback.NOOP); Stream.Listener listener = notifyNewStream(stream, frame); stream.setListener(listener); diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java index 7796b4833d4..7c3717fc3f0 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java @@ -44,7 +44,6 @@ import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.thread.Invocable.InvocationType; public class HttpChannelOverHTTP2 extends HttpChannel { @@ -72,6 +71,18 @@ public class HttpChannelOverHTTP2 extends HttpChannel return _expect100Continue; } + @Override + public void setIdleTimeout(long timeoutMs) + { + getStream().setIdleTimeout(timeoutMs); + } + + @Override + public long getIdleTimeout() + { + return getStream().getIdleTimeout(); + } + public Runnable onRequest(HeadersFrame frame) { try @@ -256,11 +267,11 @@ public class HttpChannelOverHTTP2 extends HttpChannel handle); } - boolean delayed = _delayedUntilContent; + boolean wasDelayed = _delayedUntilContent; _delayedUntilContent = false; - if (delayed) + if (wasDelayed) _handled = true; - return handle || delayed ? this : null; + return handle || wasDelayed ? this : null; } public boolean isRequestHandled() @@ -268,10 +279,27 @@ public class HttpChannelOverHTTP2 extends HttpChannel return _handled; } + public boolean onStreamTimeout(Throwable failure) + { + if (!_handled) + return true; + + HttpInput input = getRequest().getHttpInput(); + boolean readFailed = input.failed(failure); + if (readFailed) + handle(); + + boolean writeFailed = getHttpTransport().onStreamTimeout(failure); + + return readFailed || writeFailed; + } + public void onFailure(Throwable failure) { - onEarlyEOF(); - getState().asyncError(failure); + if (onEarlyEOF()) + handle(); + else + getState().asyncError(failure); } protected void consumeInput() diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java index c058801fd10..24b925c8b40 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.http2.server; import java.nio.ByteBuffer; import java.util.concurrent.atomic.AtomicBoolean; +import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.ErrorCode; @@ -37,13 +38,13 @@ import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.thread.Invocable.InvocationType; public class HttpTransportOverHTTP2 implements HttpTransport { private static final Logger LOG = Log.getLogger(HttpTransportOverHTTP2.class); private final AtomicBoolean commit = new AtomicBoolean(); + private final TransportCallback transportCallback = new TransportCallback(); private final Connector connector; private final HTTP2ServerConnection connection; private IStream stream; @@ -83,52 +84,36 @@ public class HttpTransportOverHTTP2 implements HttpTransport @Override public void send(MetaData.Response info, boolean isHeadRequest, ByteBuffer content, boolean lastContent, Callback callback) { - // info != null | content != 0 | last = true => commit + send/end - // info != null | content != 0 | last = false => commit + send - // info != null | content == 0 | last = true => commit/end - // info != null | content == 0 | last = false => commit - // info == null | content != 0 | last = true => send/end - // info == null | content != 0 | last = false => send - // info == null | content == 0 | last = true => send/end - // info == null | content == 0 | last = false => noop - boolean hasContent = BufferUtil.hasContent(content) && !isHeadRequest; if (info != null) { - if (commit.compareAndSet(false, true)) + int status = info.getStatus(); + boolean informational = HttpStatus.isInformational(status) && status != HttpStatus.SWITCHING_PROTOCOLS_101; + boolean committed = false; + if (!informational) + committed = commit.compareAndSet(false, true); + + if (committed || informational) { if (hasContent) { - commit(info, false, new Callback() + Callback commitCallback = new Callback.Nested(callback) { - @Override - public InvocationType getInvocationType() - { - // TODO is this dependent on the callback itself? - return InvocationType.NON_BLOCKING; - } - @Override public void succeeded() { - if (LOG.isDebugEnabled()) - LOG.debug("HTTP2 Response #{}/{} committed", stream.getId(), Integer.toHexString(stream.getSession().hashCode())); - send(content, lastContent, callback); + if (transportCallback.start(callback, false)) + send(content, lastContent, transportCallback); } - - @Override - public void failed(Throwable x) - { - if (LOG.isDebugEnabled()) - LOG.debug("HTTP2 Response #" + stream.getId() + "/" + Integer.toHexString(stream.getSession().hashCode()) + " failed to commit", x); - callback.failed(x); - } - }); + }; + if (transportCallback.start(commitCallback, true)) + commit(info, false, transportCallback); } else { - commit(info, lastContent, callback); + if (transportCallback.start(callback, false)) + commit(info, lastContent, transportCallback); } } else @@ -140,7 +125,8 @@ public class HttpTransportOverHTTP2 implements HttpTransport { if (hasContent || lastContent) { - send(content, lastContent, callback); + if (transportCallback.start(callback, false)) + send(content, lastContent, transportCallback); } else { @@ -211,6 +197,11 @@ public class HttpTransportOverHTTP2 implements HttpTransport stream.data(frame, callback); } + public boolean onStreamTimeout(Throwable failure) + { + return transportCallback.onIdleTimeout(failure); + } + @Override public void onCompleted() { @@ -239,4 +230,105 @@ public class HttpTransportOverHTTP2 implements HttpTransport if (stream != null) stream.reset(new ResetFrame(stream.getId(), ErrorCode.INTERNAL_ERROR.code), Callback.NOOP); } + + private class TransportCallback implements Callback + { + private State state = State.IDLE; + private Callback callback; + private boolean commit; + + public boolean start(Callback callback, boolean commit) + { + State state; + synchronized (this) + { + state = this.state; + if (state == State.IDLE) + { + this.state = State.WRITING; + this.callback = callback; + this.commit = commit; + return true; + } + } + callback.failed(new IllegalStateException("Invalid transport state: " + state)); + return false; + } + + @Override + public void succeeded() + { + boolean commit; + Callback callback = null; + synchronized (this) + { + commit = this.commit; + if (state != State.TIMEOUT) + { + callback = this.callback; + this.state = State.IDLE; + } + } + if (LOG.isDebugEnabled()) + LOG.debug("HTTP2 Response #{} {}", stream.getId(), commit ? "committed" : "flushed content"); + if (callback != null) + callback.succeeded(); + } + + @Override + public void failed(Throwable x) + { + boolean commit; + Callback callback = null; + synchronized (this) + { + commit = this.commit; + if (state != State.TIMEOUT) + { + callback = this.callback; + this.state = State.FAILED; + } + } + if (LOG.isDebugEnabled()) + LOG.debug("HTTP2 Response #" + stream.getId() + " failed to " + (commit ? "commit" : "flush"), x); + if (callback != null) + callback.failed(x); + } + + @Override + public InvocationType getInvocationType() + { + Callback callback; + synchronized (this) + { + callback = this.callback; + } + return callback.getInvocationType(); + } + + private boolean onIdleTimeout(Throwable failure) + { + boolean result; + Callback callback = null; + synchronized (this) + { + result = state == State.WRITING; + if (result) + { + callback = this.callback; + this.state = State.TIMEOUT; + } + } + if (LOG.isDebugEnabled()) + LOG.debug("HTTP2 Response #" + stream.getId() + " idle timeout", failure); + if (result) + callback.failed(failure); + return result; + } + } + + private enum State + { + IDLE, WRITING, FAILED, TIMEOUT + } } diff --git a/jetty-infinispan/src/main/config/etc/sessions/infinispan/default.xml b/jetty-infinispan/src/main/config/etc/sessions/infinispan/default.xml index 3bcc7940bad..20b844dd47a 100644 --- a/jetty-infinispan/src/main/config/etc/sessions/infinispan/default.xml +++ b/jetty-infinispan/src/main/config/etc/sessions/infinispan/default.xml @@ -20,7 +20,7 @@ - + diff --git a/jetty-infinispan/src/main/config/etc/sessions/infinispan/remote.xml b/jetty-infinispan/src/main/config/etc/sessions/infinispan/remote.xml index 6a533945817..f91df1d4b37 100644 --- a/jetty-infinispan/src/main/config/etc/sessions/infinispan/remote.xml +++ b/jetty-infinispan/src/main/config/etc/sessions/infinispan/remote.xml @@ -10,7 +10,7 @@ - + @@ -22,7 +22,7 @@ - + diff --git a/jetty-infinispan/src/main/config/modules/session-store-infinispan-embedded.mod b/jetty-infinispan/src/main/config/modules/session-store-infinispan-embedded.mod index 76441062683..bd0bb80ea10 100644 --- a/jetty-infinispan/src/main/config/modules/session-store-infinispan-embedded.mod +++ b/jetty-infinispan/src/main/config/modules/session-store-infinispan-embedded.mod @@ -1,6 +1,9 @@ [description] Enables session data store in a local Infinispan cache +[Tags] +session + [provides] session-store diff --git a/jetty-infinispan/src/main/config/modules/session-store-infinispan-remote.mod b/jetty-infinispan/src/main/config/modules/session-store-infinispan-remote.mod index 12ff46de108..70c62076d94 100644 --- a/jetty-infinispan/src/main/config/modules/session-store-infinispan-remote.mod +++ b/jetty-infinispan/src/main/config/modules/session-store-infinispan-remote.mod @@ -1,6 +1,9 @@ [description] Enables session data store in a remote Infinispan cache +[Tags] +session + [provides] session-store @@ -22,6 +25,6 @@ http://www.apache.org/licenses/LICENSE-2.0.html [ini-template] -#jetty.session.remoteInfinispanCache.name=sessions -#jetty.session.infinispanIdleTimeout.seconds=0 +#jetty.session.infinispan.remoteCacheName=sessions +#jetty.session.infinispan.idleTimeout.seconds=0 #jetty.session.gracePeriod.seconds=3600 diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java index eb1a72834d5..e0c97481d82 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java @@ -85,19 +85,15 @@ public abstract class AbstractConnection implements Connection protected void failedCallback(final Callback callback, final Throwable x) { - Runnable failCallback = new Runnable() + Runnable failCallback = () -> { - @Override - public void run() + try { - try - { - callback.failed(x); - } - catch (Exception e) - { - LOG.warn(e); - } + callback.failed(x); + } + catch (Exception e) + { + LOG.warn(e); } }; @@ -223,13 +219,13 @@ public abstract class AbstractConnection implements Connection } @Override - public int getMessagesIn() + public long getMessagesIn() { return -1; } @Override - public int getMessagesOut() + public long getMessagesOut() { return -1; } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java index bfb498ad124..8da443ebd9d 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java @@ -20,8 +20,6 @@ package org.eclipse.jetty.io; import java.nio.ByteBuffer; -import org.eclipse.jetty.util.BufferUtil; - public class ArrayByteBufferPool implements ByteBufferPool { private final int _min; @@ -63,8 +61,8 @@ public class ArrayByteBufferPool implements ByteBufferPool for (int i=0;i<_direct.length;i++) { size+=_inc; - _direct[i]=new ByteBufferPool.Bucket(size,_maxQueue); - _indirect[i]=new ByteBufferPool.Bucket(size,_maxQueue); + _direct[i]=new ByteBufferPool.Bucket(this,size,_maxQueue); + _indirect[i]=new ByteBufferPool.Bucket(this,size,_maxQueue); } } @@ -73,7 +71,7 @@ public class ArrayByteBufferPool implements ByteBufferPool { ByteBufferPool.Bucket bucket = bucketFor(size,direct); if (bucket==null) - return direct ? BufferUtil.allocateDirect(size) : BufferUtil.allocate(size); + return newByteBuffer(size,direct); return bucket.acquire(direct); diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java index 4944dac91c5..257862d1ea5 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteBufferPool.java @@ -19,13 +19,15 @@ package org.eclipse.jetty.io; import java.nio.ByteBuffer; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.List; import java.util.Queue; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.ConcurrentArrayQueue; /** *

A {@link ByteBuffer} pool.

@@ -56,6 +58,11 @@ public interface ByteBufferPool */ public void release(ByteBuffer buffer); + default ByteBuffer newByteBuffer(int capacity, boolean direct) + { + return direct ? BufferUtil.allocateDirect(capacity) : BufferUtil.allocate(capacity); + } + public static class Lease { private final ByteBufferPool byteBufferPool; @@ -121,68 +128,131 @@ public interface ByteBufferPool class Bucket { + private final Lock _lock = new ReentrantLock(); + private final Queue _queue = new ArrayDeque<>(); + private final ByteBufferPool _pool; private final int _capacity; private final AtomicInteger _space; - private final Queue _queue= new ConcurrentArrayQueue<>(); - public Bucket(int bufferSize,int maxSize) + public Bucket(ByteBufferPool pool, int bufferSize, int maxSize) { - _capacity=bufferSize; - _space=maxSize>0?new AtomicInteger(maxSize):null; + _pool = pool; + _capacity = bufferSize; + _space = maxSize > 0 ? new AtomicInteger(maxSize) : null; } - + + public ByteBuffer acquire(boolean direct) + { + ByteBuffer buffer = queuePoll(); + if (buffer == null) + return _pool.newByteBuffer(_capacity, direct); + if (_space != null) + _space.incrementAndGet(); + return buffer; + } + public void release(ByteBuffer buffer) { BufferUtil.clear(buffer); - if (_space==null) - _queue.offer(buffer); - else if (_space.decrementAndGet()>=0) - _queue.offer(buffer); + if (_space == null) + queueOffer(buffer); + else if (_space.decrementAndGet() >= 0) + queueOffer(buffer); else _space.incrementAndGet(); } - - public ByteBuffer acquire(boolean direct) - { - ByteBuffer buffer = _queue.poll(); - if (buffer == null) - return direct ? BufferUtil.allocateDirect(_capacity) : BufferUtil.allocate(_capacity); - if (_space!=null) - _space.incrementAndGet(); - return buffer; - } - + public void clear() { - if (_space==null) - _queue.clear(); + if (_space == null) + { + queueClear(); + } else { - int s=_space.getAndSet(0); - while(s-->0) + int s = _space.getAndSet(0); + while (s-- > 0) { - if (_queue.poll()==null) + if (queuePoll() == null) _space.incrementAndGet(); } } } - + + private void queueOffer(ByteBuffer buffer) + { + Lock lock = _lock; + lock.lock(); + try + { + _queue.offer(buffer); + } + finally + { + lock.unlock(); + } + } + + private ByteBuffer queuePoll() + { + Lock lock = _lock; + lock.lock(); + try + { + return _queue.poll(); + } + finally + { + lock.unlock(); + } + } + + private void queueClear() + { + Lock lock = _lock; + lock.lock(); + try + { + _queue.clear(); + } + finally + { + lock.unlock(); + } + } + boolean isEmpty() { - return _queue.isEmpty(); + Lock lock = _lock; + lock.lock(); + try + { + return _queue.isEmpty(); + } + finally + { + lock.unlock(); + } } - + int size() { - return _queue.size(); + Lock lock = _lock; + lock.lock(); + try + { + return _queue.size(); + } + finally + { + lock.unlock(); + } } - + @Override public String toString() { - return String.format("Bucket@%x{%d,%d}",hashCode(),_capacity,_queue.size()); + return String.format("Bucket@%x{%d/%d}", hashCode(), size(), _capacity); } } - - } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/Connection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/Connection.java index cf650243ad6..7761fdccb49 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/Connection.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/Connection.java @@ -60,7 +60,7 @@ public interface Connection extends Closeable public void onClose(); /** - * @return the {@link EndPoint} associated with this {@link Connection} + * @return the {@link EndPoint} associated with this Connection. */ public EndPoint getEndPoint(); @@ -86,8 +86,8 @@ public interface Connection extends Closeable */ public boolean onIdleExpired(); - public int getMessagesIn(); - public int getMessagesOut(); + public long getMessagesIn(); + public long getMessagesOut(); public long getBytesIn(); public long getBytesOut(); public long getCreatedTimeStamp(); diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ConnectionStatistics.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ConnectionStatistics.java new file mode 100644 index 00000000000..42d3fd0f50b --- /dev/null +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ConnectionStatistics.java @@ -0,0 +1,233 @@ +// +// ======================================================================== +// Copyright (c) 1995-2016 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.io; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.LongAdder; + +import org.eclipse.jetty.util.annotation.ManagedAttribute; +import org.eclipse.jetty.util.annotation.ManagedObject; +import org.eclipse.jetty.util.annotation.ManagedOperation; +import org.eclipse.jetty.util.component.AbstractLifeCycle; +import org.eclipse.jetty.util.component.ContainerLifeCycle; +import org.eclipse.jetty.util.component.Dumpable; +import org.eclipse.jetty.util.statistic.CounterStatistic; +import org.eclipse.jetty.util.statistic.SampleStatistic; + +/** + *

A {@link Connection.Listener} that tracks connection statistics.

+ *

Adding an instance of this class as a bean to a server Connector + * (for the server) or to HttpClient (for the client) will trigger the + * tracking of the connection statistics for all connections managed + * by the server Connector or by HttpClient.

+ */ +@ManagedObject("Tracks statistics on connections") +public class ConnectionStatistics extends AbstractLifeCycle implements Connection.Listener, Dumpable +{ + private final CounterStatistic _connections = new CounterStatistic(); + private final SampleStatistic _connectionsDuration = new SampleStatistic(); + private final LongAdder _rcvdBytes = new LongAdder(); + private final AtomicLong _bytesInStamp = new AtomicLong(); + private final LongAdder _sentBytes = new LongAdder(); + private final AtomicLong _bytesOutStamp = new AtomicLong(); + private final LongAdder _messagesIn = new LongAdder(); + private final AtomicLong _messagesInStamp = new AtomicLong(); + private final LongAdder _messagesOut = new LongAdder(); + private final AtomicLong _messagesOutStamp = new AtomicLong(); + + @ManagedOperation(value = "Resets the statistics", impact = "ACTION") + public void reset() + { + _connections.reset(); + _connectionsDuration.reset(); + _rcvdBytes.reset(); + _bytesInStamp.set(System.nanoTime()); + _sentBytes.reset(); + _bytesOutStamp.set(System.nanoTime()); + _messagesIn.reset(); + _messagesInStamp.set(System.nanoTime()); + _messagesOut.reset(); + _messagesOutStamp.set(System.nanoTime()); + } + + @Override + protected void doStart() throws Exception + { + reset(); + } + + @Override + public void onOpened(Connection connection) + { + if (!isStarted()) + return; + + _connections.increment(); + } + + @Override + public void onClosed(Connection connection) + { + if (!isStarted()) + return; + + _connections.decrement(); + + long elapsed = System.currentTimeMillis() - connection.getCreatedTimeStamp(); + _connectionsDuration.set(elapsed); + + long bytesIn = connection.getBytesIn(); + if (bytesIn > 0) + _rcvdBytes.add(bytesIn); + long bytesOut = connection.getBytesOut(); + if (bytesOut > 0) + _sentBytes.add(bytesOut); + + long messagesIn = connection.getMessagesIn(); + if (messagesIn > 0) + _messagesIn.add(messagesIn); + long messagesOut = connection.getMessagesOut(); + if (messagesOut > 0) + _messagesOut.add(messagesOut); + } + + @ManagedAttribute("Total number of bytes received by tracked connections") + public long getReceivedBytes() + { + return _rcvdBytes.sum(); + } + + @ManagedAttribute("Total number of bytes received per second since the last invocation of this method") + public long getReceivedBytesRate() + { + long now = System.nanoTime(); + long then = _bytesInStamp.getAndSet(now); + long elapsed = TimeUnit.NANOSECONDS.toMillis(now - then); + return elapsed == 0 ? 0 : getReceivedBytes() * 1000 / elapsed; + } + + @ManagedAttribute("Total number of bytes sent by tracked connections") + public long getSentBytes() + { + return _sentBytes.sum(); + } + + @ManagedAttribute("Total number of bytes sent per second since the last invocation of this method") + public long getSentBytesRate() + { + long now = System.nanoTime(); + long then = _bytesOutStamp.getAndSet(now); + long elapsed = TimeUnit.NANOSECONDS.toMillis(now - then); + return elapsed == 0 ? 0 : getSentBytes() * 1000 / elapsed; + } + + @ManagedAttribute("The max duration of a connection in ms") + public long getConnectionDurationMax() + { + return _connectionsDuration.getMax(); + } + + @ManagedAttribute("The mean duration of a connection in ms") + public double getConnectionDurationMean() + { + return _connectionsDuration.getMean(); + } + + @ManagedAttribute("The standard deviation of the duration of a connection") + public double getConnectionDurationStdDev() + { + return _connectionsDuration.getStdDev(); + } + + @ManagedAttribute("The total number of connections opened") + public long getConnectionsTotal() + { + return _connections.getTotal(); + } + + @ManagedAttribute("The current number of open connections") + public long getConnections() + { + return _connections.getCurrent(); + } + + @ManagedAttribute("The max number of open connections") + public long getConnectionsMax() + { + return _connections.getMax(); + } + + @ManagedAttribute("The total number of messages received") + public long getReceivedMessages() + { + return _messagesIn.sum(); + } + + @ManagedAttribute("Total number of messages received per second since the last invocation of this method") + public long getReceivedMessagesRate() + { + long now = System.nanoTime(); + long then = _messagesInStamp.getAndSet(now); + long elapsed = TimeUnit.NANOSECONDS.toMillis(now - then); + return elapsed == 0 ? 0 : getReceivedMessages() * 1000 / elapsed; + } + + @ManagedAttribute("The total number of messages sent") + public long getSentMessages() + { + return _messagesOut.sum(); + } + + @ManagedAttribute("Total number of messages sent per second since the last invocation of this method") + public long getSentMessagesRate() + { + long now = System.nanoTime(); + long then = _messagesOutStamp.getAndSet(now); + long elapsed = TimeUnit.NANOSECONDS.toMillis(now - then); + return elapsed == 0 ? 0 : getSentMessages() * 1000 / elapsed; + } + + @Override + public String dump() + { + return ContainerLifeCycle.dump(this); + } + + @Override + public void dump(Appendable out, String indent) throws IOException + { + ContainerLifeCycle.dumpObject(out, this); + List children = new ArrayList<>(); + children.add(String.format("connections=%s", _connections)); + children.add(String.format("durations=%s", _connectionsDuration)); + children.add(String.format("bytes in/out=%s/%s", getReceivedBytes(), getSentBytes())); + children.add(String.format("messages in/out=%s/%s", getReceivedMessages(), getSentMessages())); + ContainerLifeCycle.dump(out, indent, children); + } + + @Override + public String toString() + { + return String.format("%s@%x", getClass().getSimpleName(), hashCode()); + } +} diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/MappedByteBufferPool.java b/jetty-io/src/main/java/org/eclipse/jetty/io/MappedByteBufferPool.java index 335d6ccba7b..11af00c7273 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/MappedByteBufferPool.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/MappedByteBufferPool.java @@ -22,6 +22,7 @@ import java.nio.ByteBuffer; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Function; import org.eclipse.jetty.util.BufferUtil; @@ -31,6 +32,7 @@ public class MappedByteBufferPool implements ByteBufferPool private final ConcurrentMap heapBuffers = new ConcurrentHashMap<>(); private final int _factor; private final int _maxQueue; + private final Function _newBucket; public MappedByteBufferPool() { @@ -39,13 +41,19 @@ public class MappedByteBufferPool implements ByteBufferPool public MappedByteBufferPool(int factor) { - this(factor,-1); + this(factor,-1,null); } public MappedByteBufferPool(int factor,int maxQueue) + { + this(factor,maxQueue,null); + } + + public MappedByteBufferPool(int factor,int maxQueue,Function newBucket) { _factor = factor<=0?1024:factor; - _maxQueue=maxQueue; + _maxQueue = maxQueue; + _newBucket = newBucket!=null?newBucket:i->new Bucket(this,i*_factor,_maxQueue); } @Override @@ -60,12 +68,6 @@ public class MappedByteBufferPool implements ByteBufferPool return bucket.acquire(direct); } - protected ByteBuffer newByteBuffer(int capacity, boolean direct) - { - return direct ? BufferUtil.allocateDirect(capacity) - : BufferUtil.allocate(capacity); - } - @Override public void release(ByteBuffer buffer) { @@ -78,13 +80,15 @@ public class MappedByteBufferPool implements ByteBufferPool int b = bucketFor(buffer.capacity()); ConcurrentMap buckets = bucketsFor(buffer.isDirect()); - Bucket bucket = buckets.computeIfAbsent(b,bi->new Bucket(b*_factor,_maxQueue)); + Bucket bucket = buckets.computeIfAbsent(b,_newBucket); bucket.release(buffer); } public void clear() { + directBuffers.values().forEach(Bucket::clear); directBuffers.clear(); + heapBuffers.values().forEach(Bucket::clear); heapBuffers.clear(); } @@ -107,7 +111,7 @@ public class MappedByteBufferPool implements ByteBufferPool private final AtomicInteger tag = new AtomicInteger(); @Override - protected ByteBuffer newByteBuffer(int capacity, boolean direct) + public ByteBuffer newByteBuffer(int capacity, boolean direct) { ByteBuffer buffer = super.newByteBuffer(capacity + 4, direct); buffer.limit(buffer.capacity()); diff --git a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ConnectorServer.java b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ConnectorServer.java index 5320c063bb8..5955a7633e1 100644 --- a/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ConnectorServer.java +++ b/jetty-jmx/src/main/java/org/eclipse/jetty/jmx/ConnectorServer.java @@ -32,6 +32,7 @@ import javax.management.remote.JMXConnectorServer; import javax.management.remote.JMXConnectorServerFactory; import javax.management.remote.JMXServiceURL; +import org.eclipse.jetty.util.HostPort; import org.eclipse.jetty.util.component.AbstractLifeCycle; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -134,15 +135,10 @@ public class ConnectorServer extends AbstractLifeCycle */ private String startRegistry(String hostPath) throws Exception { - int rmiPort = 1099; // default RMI registry port - String rmiHost = hostPath; + HostPort hostPort = new HostPort(hostPath); - int idx = hostPath.indexOf(':'); - if (idx > 0) - { - rmiPort = Integer.parseInt(hostPath.substring(idx + 1)); - rmiHost = hostPath.substring(0,idx); - } + String rmiHost = hostPort.getHost(); + int rmiPort = hostPort.getPort(1099); // Verify that local registry is being used InetAddress hostAddress = InetAddress.getByName(rmiHost); @@ -171,7 +167,7 @@ public class ConnectorServer extends AbstractLifeCycle _registry = LocateRegistry.createRegistry(rmiPort); Thread.sleep(1000); - rmiHost = InetAddress.getLocalHost().getCanonicalHostName(); + rmiHost = HostPort.normalizeHost(InetAddress.getLocalHost().getCanonicalHostName()); return rmiHost + ':' + Integer.toString(rmiPort); } diff --git a/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/ConnectorServerTest.java b/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/ConnectorServerTest.java index 40eba9b987a..b71eb7f11df 100644 --- a/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/ConnectorServerTest.java +++ b/jetty-jmx/src/test/java/org/eclipse/jetty/jmx/ConnectorServerTest.java @@ -62,6 +62,7 @@ public class ConnectorServerTest } @Test + @Ignore // collides on ci server public void testConnServerWithRmiDefaultPort() throws Exception { // given diff --git a/jetty-memcached/jetty-memcached-sessions/src/main/config/modules/sessions/session-data-cache/xmemcached.mod b/jetty-memcached/jetty-memcached-sessions/src/main/config/modules/sessions/session-data-cache/xmemcached.mod index 76987983ddc..48c589ae00c 100644 --- a/jetty-memcached/jetty-memcached-sessions/src/main/config/modules/sessions/session-data-cache/xmemcached.mod +++ b/jetty-memcached/jetty-memcached-sessions/src/main/config/modules/sessions/session-data-cache/xmemcached.mod @@ -1,6 +1,9 @@ [description] Memcache cache for SessionData +[Tags] +session + [depends] session-store slf4j-api diff --git a/jetty-nosql/src/main/config/etc/sessions/mongo/session-store.xml b/jetty-nosql/src/main/config/etc/sessions/mongo/session-store.xml index 0b462c86013..528aff98aff 100644 --- a/jetty-nosql/src/main/config/etc/sessions/mongo/session-store.xml +++ b/jetty-nosql/src/main/config/etc/sessions/mongo/session-store.xml @@ -10,9 +10,11 @@ - - + + + + diff --git a/jetty-nosql/src/main/config/modules/session-store-mongo.mod b/jetty-nosql/src/main/config/modules/session-store-mongo.mod index 493aad48f2e..c1ffb5c755e 100644 --- a/jetty-nosql/src/main/config/modules/session-store-mongo.mod +++ b/jetty-nosql/src/main/config/modules/session-store-mongo.mod @@ -1,6 +1,9 @@ [description] Enables NoSql session management with a MongoDB driver. +[Tags] +session + [provides] session-store @@ -23,6 +26,9 @@ http://www.apache.org/licenses/LICENSE-2.0.html etc/sessions/mongo/session-store.xml [ini-template] -#jetty.session.dbName=HttpSessions -#jetty.session.collectionName=jettySessions +#jetty.session.mongo.dbName=HttpSessions +#jetty.session.mongo.collectionName=jettySessions +#jetty.session.mongo.host=localhost +#jetty.session.mongo.port=27017 #jetty.session.gracePeriod.seconds=3600 + diff --git a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStore.java b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStore.java index 004814d5a46..620ed915c62 100644 --- a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStore.java +++ b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStore.java @@ -63,6 +63,7 @@ import org.eclipse.jetty.util.log.Logger; * Each of the nested objects inside the "context" element contains: *
    *
  • unique_context_name : nested object containing name:value pairs of the session attributes for that context
  • + *
  • unique_context_name: vhost:contextpath, where no vhosts="0_0_0_0", root context = "", contextpath "/" replaced by "_" *
*

* One of the name:value attribute pairs will always be the special attribute "__metadata__". The value @@ -74,10 +75,10 @@ import org.eclipse.jetty.util.log.Logger; * { "_id" : ObjectId("52845534a40b66410f228f23"), * "accessed" : NumberLong("1384818548903"), * "maxIdle" : 1, - * "context" : { "::_contextA" : { "A" : "A", + * "context" : { "0_0_0_0:_testA" : { "A" : "A", * "__metadata__" : { "version" : NumberLong(2) } * }, - * "::_contextB" : { "B" : "B", + * "0_0_0_0:_testB" : { "B" : "B", * "__metadata__" : { "version" : NumberLong(1) } * } * }, @@ -91,7 +92,9 @@ import org.eclipse.jetty.util.log.Logger; * In MongoDB, the nesting level is indicated by "." separators for the key name. Thus to * interact with a session attribute, the key is composed of: * "context".unique_context_name.attribute_name - * Eg "context"."::/contextA"."A" + * Eg "context"."0_0_0_0:_testA"."A" + * + * */ public class MongoSessionDataStore extends NoSqlSessionDataStore { diff --git a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStoreFactory.java b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStoreFactory.java index 056fd6abdb6..b5f1bd38782 100644 --- a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStoreFactory.java +++ b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStoreFactory.java @@ -23,6 +23,7 @@ import java.net.UnknownHostException; import org.eclipse.jetty.server.session.AbstractSessionDataStoreFactory; import org.eclipse.jetty.server.session.SessionHandler; +import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.server.session.SessionDataStore; @@ -38,6 +39,43 @@ public class MongoSessionDataStoreFactory extends AbstractSessionDataStoreFactor { String _dbName; String _collectionName; + String _host; + int _port = -1; + + /** + * @return the host + */ + public String getHost() + { + return _host; + } + + /** + * @param host the host to set + */ + public void setHost(String host) + { + _host = host; + } + + /** + * @return the port + */ + public int getPort() + { + return _port; + } + + /** + * @param port the port to set + */ + public void setPort(int port) + { + _port = port; + } + + + /** @@ -83,7 +121,14 @@ public class MongoSessionDataStoreFactory extends AbstractSessionDataStoreFactor { MongoSessionDataStore store = new MongoSessionDataStore(); store.setGracePeriodSec(getGracePeriodSec()); - store.setDBCollection(new Mongo().getDB(getDbName()).getCollection(getCollectionName())); + Mongo mongo; + if (!StringUtil.isBlank(getHost()) && getPort() != -1) + mongo = new Mongo(getHost(), getPort()); + else if (!StringUtil.isBlank(getHost())) + mongo = new Mongo(getHost()); + else + mongo = new Mongo(); + store.setDBCollection(mongo.getDB(getDbName()).getCollection(getCollectionName())); return store; } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationConfiguration.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationConfiguration.java index d92ccd5f4d9..70f8669cad5 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationConfiguration.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationConfiguration.java @@ -18,11 +18,14 @@ package org.eclipse.jetty.osgi.annotations; +import java.io.IOException; +import java.net.MalformedURLException; import java.util.HashSet; import java.util.Set; +import javax.servlet.ServletContainerInitializer; + import org.eclipse.jetty.annotations.AnnotationParser.Handler; -import org.eclipse.jetty.annotations.ClassNameResolver; import org.eclipse.jetty.osgi.boot.OSGiWebInfConfiguration; import org.eclipse.jetty.osgi.boot.OSGiWebappConstants; import org.eclipse.jetty.util.log.Log; @@ -44,9 +47,9 @@ public class AnnotationConfiguration extends org.eclipse.jetty.annotations.Annot public class BundleParserTask extends ParserTask { - public BundleParserTask (AnnotationParser parser, Sethandlers, Resource resource, ClassNameResolver resolver) + public BundleParserTask (AnnotationParser parser, Sethandlers, Resource resource) { - super(parser, handlers, resource, resolver); + super(parser, handlers, resource); } public Void call() throws Exception @@ -57,7 +60,7 @@ public class AnnotationConfiguration extends org.eclipse.jetty.annotations.Annot Bundle bundle = osgiAnnotationParser.getBundle(_resource); if (_stat != null) _stat.start(); - osgiAnnotationParser.parse(_handlers, bundle, _resolver); + osgiAnnotationParser.parse(_handlers, bundle); if (_stat != null) _stat.end(); } @@ -79,6 +82,17 @@ public class AnnotationConfiguration extends org.eclipse.jetty.annotations.Annot return new AnnotationParser(); } + @Override + public Resource getJarFor(ServletContainerInitializer service) throws MalformedURLException, IOException + { + Resource resource = super.getJarFor(service); + // TODO This is not correct, but implemented like this to be bug for bug compatible + // with previous implementation that could only handle actual jars and not bundles. + if (resource!=null && !resource.toString().endsWith(".jar")) + return null; + return resource; + } + /** * Here is the order in which jars and osgi artifacts are scanned for discoverable annotations. *

    @@ -195,47 +209,13 @@ public class AnnotationConfiguration extends org.eclipse.jetty.annotations.Annot handlers.add(_classInheritanceHandler); handlers.addAll(_containerInitializerAnnotationHandlers); - ClassNameResolver classNameResolver = createClassNameResolver(context); if (_parserTasks != null) { - BundleParserTask task = new BundleParserTask(parser, handlers, bundleRes, classNameResolver); + BundleParserTask task = new BundleParserTask(parser, handlers, bundleRes); _parserTasks.add(task); if (LOG.isDebugEnabled()) task.setStatistic(new TimeStatistic()); } } - /** - * Returns the same classname resolver than for the webInfjar scanner - * @param context the web app context - * @return the class name resolver - */ - protected ClassNameResolver createClassNameResolver(final WebAppContext context) - { - return createClassNameResolver(context,true,false,false,false); - } - - protected ClassNameResolver createClassNameResolver(final WebAppContext context, - final boolean excludeSysClass, final boolean excludeServerClass, final boolean excludeEverythingElse, - final boolean overrideIsParenLoaderIsPriority) - { - return new ClassNameResolver () - { - public boolean isExcluded (String name) - { - if (context.isSystemClass(name)) return excludeSysClass; - if (context.isServerClass(name)) return excludeServerClass; - return excludeEverythingElse; - } - - public boolean shouldOverride (String name) - { - //looking at system classpath - if (context.isParentLoaderPriority()) - return overrideIsParenLoaderIsPriority; - return !overrideIsParenLoaderIsPriority; - } - }; - } - } diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationParser.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationParser.java index a22b4077113..d454e9be7cf 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationParser.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationParser.java @@ -29,7 +29,6 @@ import java.util.StringTokenizer; import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; -import org.eclipse.jetty.annotations.ClassNameResolver; import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelperFactory; import org.eclipse.jetty.util.ConcurrentHashSet; import org.eclipse.jetty.util.resource.Resource; @@ -85,7 +84,7 @@ public class AnnotationParser extends org.eclipse.jetty.annotations.AnnotationPa * */ @Override - public void parse (Set handlers, URI[] uris, ClassNameResolver resolver) + public void parse (Set handlers, URI[] uris) throws Exception { for (URI uri : uris) @@ -99,16 +98,16 @@ public class AnnotationParser extends org.eclipse.jetty.annotations.AnnotationPa } //a jar in WEB-INF/lib or the WEB-INF/classes //use the behavior of the super class for a standard jar. - super.parse(handlers, new URI[] {uri},resolver); + super.parse(handlers, new URI[] {uri}); } else { - parse(handlers, associatedBundle,resolver); + parse(handlers, associatedBundle); } } } - protected void parse(Set handlers, Bundle bundle, ClassNameResolver resolver) + protected void parse(Set handlers, Bundle bundle) throws Exception { URI uri = _bundleToUri.get(bundle); @@ -205,7 +204,7 @@ public class AnnotationParser extends org.eclipse.jetty.annotations.AnnotationPa } //transform into a classname to pass to the resolver String shortName = name.replace('/', '.').substring(0,name.length()-6); - if ((resolver == null) || (!resolver.isExcluded(shortName) && (!isParsed(shortName) || resolver.shouldOverride(shortName)))) + if (!isParsed(shortName)) { try (InputStream classInputStream = classUrl.openStream()) { diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractOSGiApp.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractOSGiApp.java index a04f37adfb5..02c0feb35dc 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractOSGiApp.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractOSGiApp.java @@ -47,18 +47,16 @@ public abstract class AbstractOSGiApp extends App private static final Logger LOG = Log.getLogger(AbstractOSGiApp.class); protected Bundle _bundle; - protected Dictionary _properties; + protected Dictionary _properties; protected ServiceRegistration _registration; /* ------------------------------------------------------------ */ public AbstractOSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, String originId) { - super(manager, provider, originId); - _properties = bundle.getHeaders(); - _bundle = bundle; + this (manager, provider, bundle, bundle.getHeaders(), originId); } /* ------------------------------------------------------------ */ - public AbstractOSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, Dictionary properties, String originId) + public AbstractOSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, Dictionary properties, String originId) { super(manager, provider, originId); _properties = properties; diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractWebAppProvider.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractWebAppProvider.java index 0386f013c7e..74d386cc837 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractWebAppProvider.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractWebAppProvider.java @@ -38,6 +38,7 @@ import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.resource.JarResource; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.webapp.Configuration; +import org.eclipse.jetty.webapp.WebAppClassLoader; import org.eclipse.jetty.webapp.WebAppContext; import org.eclipse.jetty.xml.XmlConfiguration; import org.osgi.framework.Bundle; @@ -436,18 +437,23 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement } } } - if (contextXmlUrl == null) return; + if (contextXmlUrl == null) + return; // Apply it just as the standard jetty ContextProvider would do LOG.info("Applying " + contextXmlUrl + " to " + _webApp); XmlConfiguration xmlConfiguration = new XmlConfiguration(contextXmlUrl); - HashMap properties = new HashMap(); - properties.put("Server", getDeploymentManager().getServer()); - properties.put(OSGiWebappConstants.JETTY_BUNDLE_ROOT, rootResource.toString()); - properties.put(OSGiServerConstants.JETTY_HOME, getDeploymentManager().getServer().getAttribute(OSGiServerConstants.JETTY_HOME)); - xmlConfiguration.getProperties().putAll(properties); - xmlConfiguration.configure(_webApp); + WebAppClassLoader.runWithServerClassAccess(()-> + { + HashMap properties = new HashMap<>(); + xmlConfiguration.getIdMap().put("Server",getDeploymentManager().getServer()); + properties.put(OSGiWebappConstants.JETTY_BUNDLE_ROOT, rootResource.toString()); + properties.put(OSGiServerConstants.JETTY_HOME, (String)getDeploymentManager().getServer().getAttribute(OSGiServerConstants.JETTY_HOME)); + xmlConfiguration.getProperties().putAll(properties); + xmlConfiguration.configure(_webApp); + return null; + }); } finally { diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleWebAppProvider.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleWebAppProvider.java index 43bf2c4733c..395c621139f 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleWebAppProvider.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleWebAppProvider.java @@ -175,7 +175,7 @@ public class BundleWebAppProvider extends AbstractWebAppProvider implements Bund String contextPath = null; try { - Dictionary headers = bundle.getHeaders(); + Dictionary headers = bundle.getHeaders(); //does the bundle have a OSGiWebappConstants.JETTY_WAR_FOLDER_PATH String resourcePath = Util.getManifestHeaderValue(OSGiWebappConstants.JETTY_WAR_FOLDER_PATH, OSGiWebappConstants.JETTY_WAR_RESOURCE_PATH, headers); @@ -217,7 +217,7 @@ public class BundleWebAppProvider extends AbstractWebAppProvider implements Bund { //Could be a static webapp with no web.xml String base = "."; - contextPath = (String)headers.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH); + contextPath = headers.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH); String originId = getOriginId(bundle,base); OSGiApp app = new OSGiApp(getDeploymentManager(), this, bundle, originId); diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/OSGiWebappClassLoader.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/OSGiWebappClassLoader.java index 8c77b130d76..8ba7377e9c9 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/OSGiWebappClassLoader.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/OSGiWebappClassLoader.java @@ -78,8 +78,6 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe private Bundle _contributor; - private boolean _lookInOsgiFirst = true; - /* ------------------------------------------------------------ */ /** * @param parent The parent classloader. @@ -96,11 +94,26 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe } - + + /* ------------------------------------------------------------ */ @Override public Class loadClass(String name) throws ClassNotFoundException { - return super.loadClass(name); + try + { + return _osgiBundleClassLoader.loadClass(name); + } + catch (ClassNotFoundException cne) + { + try + { + return super.loadClass(name); + } + catch (ClassNotFoundException cne2) + { + throw cne; + } + } } /* ------------------------------------------------------------ */ @@ -121,36 +134,18 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe { Enumeration osgiUrls = _osgiBundleClassLoader.getResources(name); Enumeration urls = super.getResources(name); - if (_lookInOsgiFirst) - { - return Collections.enumeration(toList(osgiUrls, urls)); - } - else - { - return Collections.enumeration(toList(urls, osgiUrls)); - } + List resources = toList(osgiUrls, urls); + return Collections.enumeration(resources); } - - /* ------------------------------------------------------------ */ @Override public URL getResource(String name) { - if (_lookInOsgiFirst) - { - URL url = _osgiBundleClassLoader.getResource(name); - return url != null ? url : super.getResource(name); - } - else - { - URL url = super.getResource(name); - return url != null ? url : _osgiBundleClassLoader.getResource(name); - } + URL url = _osgiBundleClassLoader.getResource(name); + return url != null ? url : super.getResource(name); } - - /* ------------------------------------------------------------ */ private List toList(Enumeration e, Enumeration e2) { @@ -160,30 +155,7 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe while (e2 != null && e2.hasMoreElements()) list.add(e2.nextElement()); return list; - } - - - /* ------------------------------------------------------------ */ - protected Class findClass(String name) throws ClassNotFoundException - { - try - { - return _lookInOsgiFirst ? _osgiBundleClassLoader.loadClass(name) : super.findClass(name); - } - catch (ClassNotFoundException cne) - { - try - { - return _lookInOsgiFirst ? super.findClass(name) : _osgiBundleClassLoader.loadClass(name); - } - catch (ClassNotFoundException cne2) - { - throw cne; - } - } - } - - + } /* ------------------------------------------------------------ */ /** diff --git a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AbstractProxyServlet.java b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AbstractProxyServlet.java index 8350febd4c3..2fc62333bdc 100644 --- a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AbstractProxyServlet.java +++ b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AbstractProxyServlet.java @@ -40,7 +40,9 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.client.ContinueProtocolHandler; import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.ProtocolHandlers; import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.http.HttpField; @@ -80,6 +82,7 @@ import org.eclipse.jetty.util.thread.QueuedThreadPool; */ public abstract class AbstractProxyServlet extends HttpServlet { + protected static final String CLIENT_REQUEST_ATTRIBUTE = "org.eclipse.jetty.proxy.clientRequest"; protected static final Set HOP_HEADERS; static { @@ -324,8 +327,10 @@ public abstract class AbstractProxyServlet extends HttpServlet // Content must not be decoded, otherwise the client gets confused. client.getContentDecoderFactories().clear(); - // No protocol handlers, pass everything to the client. - client.getProtocolHandlers().clear(); + // Pass traffic to the client, only intercept what's necessary. + ProtocolHandlers protocolHandlers = client.getProtocolHandlers(); + protocolHandlers.clear(); + protocolHandlers.put(new ProxyContinueProtocolHandler()); return client; } @@ -427,6 +432,11 @@ public abstract class AbstractProxyServlet extends HttpServlet clientRequest.getHeader(HttpHeader.TRANSFER_ENCODING.asString()) != null; } + protected boolean expects100Continue(HttpServletRequest request) + { + return HttpHeaderValue.CONTINUE.asString().equals(request.getHeader(HttpHeader.EXPECT.asString())); + } + protected void copyRequestHeaders(HttpServletRequest clientRequest, Request proxyRequest) { // First clear possibly existing headers, as we are going to copy those from the client request. @@ -638,6 +648,9 @@ public abstract class AbstractProxyServlet extends HttpServlet int status = failure instanceof TimeoutException ? HttpStatus.GATEWAY_TIMEOUT_504 : HttpStatus.BAD_GATEWAY_502; + int serverStatus = serverResponse == null ? status : serverResponse.getStatus(); + if (expects100Continue(clientRequest) && serverStatus >= HttpStatus.OK_200) + status = serverStatus; sendProxyResponseError(clientRequest, proxyResponse, status); } } @@ -655,6 +668,12 @@ public abstract class AbstractProxyServlet extends HttpServlet clientRequest.getAsyncContext().complete(); } + protected void onContinue(HttpServletRequest clientRequest, Request proxyRequest) + { + if (_log.isDebugEnabled()) + _log.debug("{} handling 100 Continue", getRequestId(clientRequest)); + } + /** *

    Utility class that implement transparent proxy functionalities.

    *

    Configuration parameters:

    @@ -733,4 +752,14 @@ public abstract class AbstractProxyServlet extends HttpServlet return rewrittenURI.toString(); } } + + class ProxyContinueProtocolHandler extends ContinueProtocolHandler + { + @Override + protected void onContinue(Request request) + { + HttpServletRequest clientRequest = (HttpServletRequest)request.getAttributes().get(CLIENT_REQUEST_ATTRIBUTE); + AbstractProxyServlet.this.onContinue(clientRequest, request); + } + } } diff --git a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AsyncMiddleManServlet.java b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AsyncMiddleManServlet.java index 491258acdc5..03ca4943d89 100644 --- a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AsyncMiddleManServlet.java +++ b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AsyncMiddleManServlet.java @@ -41,7 +41,6 @@ import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.client.ContentDecoder; import org.eclipse.jetty.client.GZIPContentDecoder; -import org.eclipse.jetty.client.api.ContentProvider; import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.api.Result; @@ -66,9 +65,10 @@ import org.eclipse.jetty.util.component.Destroyable; */ public class AsyncMiddleManServlet extends AbstractProxyServlet { - private static final String PROXY_REQUEST_COMMITTED = AsyncMiddleManServlet.class.getName() + ".proxyRequestCommitted"; - private static final String CLIENT_TRANSFORMER = AsyncMiddleManServlet.class.getName() + ".clientTransformer"; - private static final String SERVER_TRANSFORMER = AsyncMiddleManServlet.class.getName() + ".serverTransformer"; + private static final String PROXY_REQUEST_CONTENT_COMMITTED_ATTRIBUTE = AsyncMiddleManServlet.class.getName() + ".proxyRequestContentCommitted"; + private static final String CLIENT_TRANSFORMER_ATTRIBUTE = AsyncMiddleManServlet.class.getName() + ".clientTransformer"; + private static final String SERVER_TRANSFORMER_ATTRIBUTE = AsyncMiddleManServlet.class.getName() + ".serverTransformer"; + private static final String CONTINUE_ACTION_ATTRIBUTE = AsyncMiddleManServlet.class.getName() + ".continueAction"; @Override protected void service(HttpServletRequest clientRequest, HttpServletResponse proxyResponse) throws ServletException, IOException @@ -91,8 +91,6 @@ public class AsyncMiddleManServlet extends AbstractProxyServlet .method(clientRequest.getMethod()) .version(HttpVersion.fromString(clientRequest.getProtocol())); - boolean hasContent = hasContent(clientRequest); - copyRequestHeaders(clientRequest, proxyRequest); addProxyHeaders(clientRequest, proxyRequest); @@ -105,16 +103,43 @@ public class AsyncMiddleManServlet extends AbstractProxyServlet // If there is content, the send of the proxy request // is delayed and performed when the content arrives, // to allow optimization of the Content-Length header. - if (hasContent) - proxyRequest.content(newProxyContentProvider(clientRequest, proxyResponse, proxyRequest)); + if (hasContent(clientRequest)) + { + DeferredContentProvider provider = newProxyContentProvider(clientRequest, proxyResponse, proxyRequest); + proxyRequest.content(provider); + + if (expects100Continue(clientRequest)) + { + proxyRequest.attribute(CLIENT_REQUEST_ATTRIBUTE, clientRequest); + proxyRequest.attribute(CONTINUE_ACTION_ATTRIBUTE, (Runnable)() -> + { + try + { + ServletInputStream input = clientRequest.getInputStream(); + input.setReadListener(newProxyReadListener(clientRequest, proxyResponse, proxyRequest, provider)); + } + catch (Throwable failure) + { + onClientRequestFailure(clientRequest, proxyRequest, proxyResponse, failure); + } + }); + sendProxyRequest(clientRequest, proxyResponse, proxyRequest); + } + else + { + ServletInputStream input = clientRequest.getInputStream(); + input.setReadListener(newProxyReadListener(clientRequest, proxyResponse, proxyRequest, provider)); + } + } else + { sendProxyRequest(clientRequest, proxyResponse, proxyRequest); + } } - protected ContentProvider newProxyContentProvider(final HttpServletRequest clientRequest, HttpServletResponse proxyResponse, Request proxyRequest) throws IOException + protected DeferredContentProvider newProxyContentProvider(final HttpServletRequest clientRequest, HttpServletResponse proxyResponse, Request proxyRequest) throws IOException { - ServletInputStream input = clientRequest.getInputStream(); - DeferredContentProvider provider = new DeferredContentProvider() + return new DeferredContentProvider() { @Override public boolean offer(ByteBuffer buffer, Callback callback) @@ -124,8 +149,6 @@ public class AsyncMiddleManServlet extends AbstractProxyServlet return super.offer(buffer, callback); } }; - input.setReadListener(newProxyReadListener(clientRequest, proxyResponse, proxyRequest, provider)); - return provider; } protected ReadListener newProxyReadListener(HttpServletRequest clientRequest, HttpServletResponse proxyResponse, Request proxyRequest, DeferredContentProvider provider) @@ -154,6 +177,14 @@ public class AsyncMiddleManServlet extends AbstractProxyServlet return ContentTransformer.IDENTITY; } + @Override + protected void onContinue(HttpServletRequest clientRequest, Request proxyRequest) + { + super.onContinue(clientRequest, proxyRequest); + Runnable action = (Runnable)proxyRequest.getAttributes().get(CONTINUE_ACTION_ATTRIBUTE); + action.run(); + } + private void transform(ContentTransformer transformer, ByteBuffer input, boolean finished, List output) throws IOException { try @@ -197,10 +228,10 @@ public class AsyncMiddleManServlet extends AbstractProxyServlet private void cleanup(HttpServletRequest clientRequest) { - ContentTransformer clientTransformer = (ContentTransformer)clientRequest.getAttribute(CLIENT_TRANSFORMER); + ContentTransformer clientTransformer = (ContentTransformer)clientRequest.getAttribute(CLIENT_TRANSFORMER_ATTRIBUTE); if (clientTransformer instanceof Destroyable) ((Destroyable)clientTransformer).destroy(); - ContentTransformer serverTransformer = (ContentTransformer)clientRequest.getAttribute(SERVER_TRANSFORMER); + ContentTransformer serverTransformer = (ContentTransformer)clientRequest.getAttribute(SERVER_TRANSFORMER_ATTRIBUTE); if (serverTransformer instanceof Destroyable) ((Destroyable)serverTransformer).destroy(); } @@ -237,6 +268,7 @@ public class AsyncMiddleManServlet extends AbstractProxyServlet private final Request proxyRequest; private final DeferredContentProvider provider; private final int contentLength; + private final boolean expects100Continue; private int length; protected ProxyReader(HttpServletRequest clientRequest, HttpServletResponse proxyResponse, Request proxyRequest, DeferredContentProvider provider) @@ -246,6 +278,7 @@ public class AsyncMiddleManServlet extends AbstractProxyServlet this.proxyRequest = proxyRequest; this.provider = provider; this.contentLength = clientRequest.getContentLength(); + this.expects100Continue = expects100Continue(clientRequest); } @Override @@ -321,15 +354,13 @@ public class AsyncMiddleManServlet extends AbstractProxyServlet private void process(ByteBuffer content, Callback callback, boolean finished) throws IOException { - ContentTransformer transformer = (ContentTransformer)clientRequest.getAttribute(CLIENT_TRANSFORMER); + ContentTransformer transformer = (ContentTransformer)clientRequest.getAttribute(CLIENT_TRANSFORMER_ATTRIBUTE); if (transformer == null) { transformer = newClientRequestContentTransformer(clientRequest, proxyRequest); - clientRequest.setAttribute(CLIENT_TRANSFORMER, transformer); + clientRequest.setAttribute(CLIENT_TRANSFORMER_ATTRIBUTE, transformer); } - boolean committed = clientRequest.getAttribute(PROXY_REQUEST_COMMITTED) != null; - int contentBytes = content.remaining(); // Skip transformation for empty non-last buffers. @@ -361,11 +392,15 @@ public class AsyncMiddleManServlet extends AbstractProxyServlet if (_log.isDebugEnabled()) _log.debug("{} upstream content transformation {} -> {} bytes", getRequestId(clientRequest), contentBytes, newContentBytes); - if (!committed && (size > 0 || finished)) + boolean contentCommitted = clientRequest.getAttribute(PROXY_REQUEST_CONTENT_COMMITTED_ATTRIBUTE) != null; + if (!contentCommitted && (size > 0 || finished)) { - proxyRequest.header(HttpHeader.CONTENT_LENGTH, null); - clientRequest.setAttribute(PROXY_REQUEST_COMMITTED, true); - sendProxyRequest(clientRequest, proxyResponse, proxyRequest); + clientRequest.setAttribute(PROXY_REQUEST_CONTENT_COMMITTED_ATTRIBUTE, true); + if (!expects100Continue) + { + proxyRequest.header(HttpHeader.CONTENT_LENGTH, null); + sendProxyRequest(clientRequest, proxyResponse, proxyRequest); + } } if (size == 0) @@ -401,6 +436,7 @@ public class AsyncMiddleManServlet extends AbstractProxyServlet @Override public void onBegin(Response serverResponse) { + response = serverResponse; proxyResponse.setStatus(serverResponse.getStatus()); } @@ -430,11 +466,11 @@ public class AsyncMiddleManServlet extends AbstractProxyServlet clientRequest.setAttribute(WRITE_LISTENER_ATTRIBUTE, proxyWriter); } - ContentTransformer transformer = (ContentTransformer)clientRequest.getAttribute(SERVER_TRANSFORMER); + ContentTransformer transformer = (ContentTransformer)clientRequest.getAttribute(SERVER_TRANSFORMER_ATTRIBUTE); if (transformer == null) { transformer = newServerResponseContentTransformer(clientRequest, proxyResponse, serverResponse); - clientRequest.setAttribute(SERVER_TRANSFORMER, transformer); + clientRequest.setAttribute(SERVER_TRANSFORMER_ATTRIBUTE, transformer); } length += contentBytes; @@ -502,7 +538,7 @@ public class AsyncMiddleManServlet extends AbstractProxyServlet if (contentLength < 0) { ProxyWriter proxyWriter = (ProxyWriter)clientRequest.getAttribute(WRITE_LISTENER_ATTRIBUTE); - ContentTransformer transformer = (ContentTransformer)clientRequest.getAttribute(SERVER_TRANSFORMER); + ContentTransformer transformer = (ContentTransformer)clientRequest.getAttribute(SERVER_TRANSFORMER_ATTRIBUTE); transform(transformer, BufferUtil.EMPTY_BUFFER, true, buffers); @@ -544,7 +580,6 @@ public class AsyncMiddleManServlet extends AbstractProxyServlet @Override public void onComplete(Result result) { - response = result.getResponse(); if (result.isSucceeded()) complete.succeeded(); else diff --git a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ConnectHandler.java b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ConnectHandler.java index 44daa67ae9b..127d5d8c553 100644 --- a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ConnectHandler.java +++ b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ConnectHandler.java @@ -54,6 +54,7 @@ import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.HandlerWrapper; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.HostPort; import org.eclipse.jetty.util.Promise; import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; @@ -224,14 +225,9 @@ public class ConnectHandler extends HandlerWrapper return; } - String host = serverAddress; - int port = 80; - int colon = serverAddress.indexOf(':'); - if (colon > 0) - { - host = serverAddress.substring(0, colon); - port = Integer.parseInt(serverAddress.substring(colon + 1)); - } + HostPort hostPort = new HostPort(serverAddress); + String host = hostPort.getHost(); + int port = hostPort.getPort(80); if (!validateDestination(host, port)) { diff --git a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ProxyServlet.java b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ProxyServlet.java index d636ad89ec2..a0af592f4c6 100644 --- a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ProxyServlet.java +++ b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ProxyServlet.java @@ -18,9 +18,12 @@ package org.eclipse.jetty.proxy; +import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; +import java.util.Iterator; +import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import javax.servlet.AsyncContext; @@ -29,13 +32,16 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.client.AsyncContentProvider; import org.eclipse.jetty.client.api.ContentProvider; import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.api.Result; +import org.eclipse.jetty.client.util.DeferredContentProvider; import org.eclipse.jetty.client.util.InputStreamContentProvider; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.IteratingCallback; /** *

    Servlet 3.0 asynchronous proxy servlet.

    @@ -47,6 +53,8 @@ import org.eclipse.jetty.util.Callback; */ public class ProxyServlet extends AbstractProxyServlet { + private static final String CONTINUE_ACTION_ATTRIBUTE = ProxyServlet.class.getName() + ".continueAction"; + @Override protected void service(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException { @@ -83,7 +91,30 @@ public class ProxyServlet extends AbstractProxyServlet proxyRequest.timeout(getTimeout(), TimeUnit.MILLISECONDS); if (hasContent(request)) - proxyRequest.content(proxyRequestContent(request, response, proxyRequest)); + { + if (expects100Continue(request)) + { + DeferredContentProvider deferred = new DeferredContentProvider(); + proxyRequest.content(deferred); + proxyRequest.attribute(CLIENT_REQUEST_ATTRIBUTE, request); + proxyRequest.attribute(CONTINUE_ACTION_ATTRIBUTE, (Runnable)() -> + { + try + { + ContentProvider provider = proxyRequestContent(request, response, proxyRequest); + new DelegatingContentProvider(request, proxyRequest, response, provider, deferred).iterate(); + } + catch (Throwable failure) + { + onClientRequestFailure(request, proxyRequest, response, failure); + } + }); + } + else + { + proxyRequest.content(proxyRequestContent(request, response, proxyRequest)); + } + } sendProxyRequest(request, response, proxyRequest); } @@ -114,6 +145,15 @@ public class ProxyServlet extends AbstractProxyServlet } } + @Override + protected void onContinue(HttpServletRequest clientRequest, Request proxyRequest) + { + super.onContinue(clientRequest, proxyRequest); + Runnable action = (Runnable)proxyRequest.getAttributes().get(CONTINUE_ACTION_ATTRIBUTE); + Executor executor = getHttpClient().getExecutor(); + executor.execute(action); + } + /** *

    Convenience extension of {@link ProxyServlet} that offers transparent proxy functionalities.

    * @@ -240,4 +280,81 @@ public class ProxyServlet extends AbstractProxyServlet onClientRequestFailure(request, proxyRequest, response, failure); } } + + private class DelegatingContentProvider extends IteratingCallback implements AsyncContentProvider.Listener + { + private final HttpServletRequest clientRequest; + private final Request proxyRequest; + private final HttpServletResponse proxyResponse; + private final Iterator iterator; + private final DeferredContentProvider deferred; + + private DelegatingContentProvider(HttpServletRequest clientRequest, Request proxyRequest, HttpServletResponse proxyResponse, ContentProvider provider, DeferredContentProvider deferred) + { + this.clientRequest = clientRequest; + this.proxyRequest = proxyRequest; + this.proxyResponse = proxyResponse; + this.iterator = provider.iterator(); + this.deferred = deferred; + if (provider instanceof AsyncContentProvider) + ((AsyncContentProvider)provider).setListener(this); + } + + @Override + protected Action process() throws Exception + { + if (!iterator.hasNext()) + return Action.SUCCEEDED; + + ByteBuffer buffer = iterator.next(); + if (buffer == null) + return Action.IDLE; + + deferred.offer(buffer, this); + return Action.SCHEDULED; + } + + @Override + public void succeeded() + { + if (iterator instanceof Callback) + ((Callback)iterator).succeeded(); + super.succeeded(); + } + + @Override + protected void onCompleteSuccess() + { + try + { + if (iterator instanceof Closeable) + ((Closeable)iterator).close(); + deferred.close(); + } + catch (Throwable x) + { + _log.ignore(x); + } + } + + @Override + protected void onCompleteFailure(Throwable failure) + { + if (iterator instanceof Callback) + ((Callback)iterator).failed(failure); + onClientRequestFailure(clientRequest, proxyRequest, proxyResponse, failure); + } + + @Override + public InvocationType getInvocationType() + { + return InvocationType.NON_BLOCKING; + } + + @Override + public void onContent() + { + iterate(); + } + } } diff --git a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ConnectHandlerTest.java b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ConnectHandlerTest.java index 3ae5a5b3d7a..89bbf56f733 100644 --- a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ConnectHandlerTest.java +++ b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ConnectHandlerTest.java @@ -18,9 +18,11 @@ package org.eclipse.jetty.proxy; +import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; @@ -65,7 +67,7 @@ public class ConnectHandlerTest extends AbstractConnectHandlerTest @Test public void testCONNECT() throws Exception - { + { String hostPort = "localhost:" + serverConnector.getLocalPort(); String request = "" + "CONNECT " + hostPort + " HTTP/1.1\r\n" + @@ -84,6 +86,27 @@ public class ConnectHandlerTest extends AbstractConnectHandlerTest } } + @Test + public void testCONNECTwithIPv6() throws Exception + { + String hostPort = "[::1]:" + serverConnector.getLocalPort(); + String request = "" + + "CONNECT " + hostPort + " HTTP/1.1\r\n" + + "Host: " + hostPort + "\r\n" + + "\r\n"; + try (Socket socket = newSocket()) + { + OutputStream output = socket.getOutputStream(); + + output.write(request.getBytes(StandardCharsets.UTF_8)); + output.flush(); + + // Expect 200 OK from the CONNECT request + HttpTester.Response response = readResponse(socket.getInputStream()); + Assert.assertEquals(HttpStatus.OK_200, response.getStatus()); + } + } + @Test public void testCONNECTAndGET() throws Exception { diff --git a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletTest.java b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletTest.java index f3add4ba420..3415c883d71 100644 --- a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletTest.java +++ b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletTest.java @@ -53,6 +53,7 @@ import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; +import javax.servlet.ServletInputStream; import javax.servlet.ServletOutputStream; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; @@ -72,9 +73,12 @@ import org.eclipse.jetty.client.api.Result; import org.eclipse.jetty.client.http.HttpDestinationOverHTTP; import org.eclipse.jetty.client.util.BufferingResponseListener; import org.eclipse.jetty.client.util.BytesContentProvider; +import org.eclipse.jetty.client.util.DeferredContentProvider; import org.eclipse.jetty.client.util.InputStreamResponseListener; import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.http.HttpHeaderValue; import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.Server; @@ -187,9 +191,12 @@ public class ProxyServletTest @After public void dispose() throws Exception { - client.stop(); - proxy.stop(); - server.stop(); + if (client != null) + client.stop(); + if (proxy != null) + proxy.stop(); + if (server != null) + server.stop(); } @Test @@ -1233,5 +1240,227 @@ public class ProxyServletTest Assert.assertEquals(200, response.getStatus()); } - // TODO: test proxy authentication + @Test + public void testExpect100ContinueRespond100Continue() throws Exception + { + CountDownLatch serverLatch1 = new CountDownLatch(1); + CountDownLatch serverLatch2 = new CountDownLatch(1); + startServer(new HttpServlet() + { + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + serverLatch1.countDown(); + + try + { + serverLatch2.await(5, TimeUnit.SECONDS); + } + catch (Throwable x) + { + throw new InterruptedIOException(); + } + + // Send the 100 Continue. + ServletInputStream input = request.getInputStream(); + + // Echo the content. + IO.copy(input, response.getOutputStream()); + } + }); + startProxy(); + startClient(); + + byte[] content = new byte[1024]; + CountDownLatch contentLatch = new CountDownLatch(1); + CountDownLatch clientLatch = new CountDownLatch(1); + client.newRequest("localhost", serverConnector.getLocalPort()) + .header(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString()) + .content(new BytesContentProvider(content)) + .onRequestContent((request, buffer) -> contentLatch.countDown()) + .send(new BufferingResponseListener() + { + @Override + public void onComplete(Result result) + { + if (result.isSucceeded()) + { + if (result.getResponse().getStatus() == HttpStatus.OK_200) + { + if (Arrays.equals(content, getContent())) + clientLatch.countDown(); + } + } + } + }); + + // Wait until we arrive on the server. + Assert.assertTrue(serverLatch1.await(5, TimeUnit.SECONDS)); + // The client should not send the content yet. + Assert.assertFalse(contentLatch.await(1, TimeUnit.SECONDS)); + + // Make the server send the 100 Continue. + serverLatch2.countDown(); + + // The client has sent the content. + Assert.assertTrue(contentLatch.await(5, TimeUnit.SECONDS)); + Assert.assertTrue(clientLatch.await(5, TimeUnit.SECONDS)); + } + + @Test + public void testExpect100ContinueRespond100ContinueDelayedRequestContent() throws Exception + { + startServer(new HttpServlet() + { + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + // Send the 100 Continue. + ServletInputStream input = request.getInputStream(); + // Echo the content. + IO.copy(input, response.getOutputStream()); + } + }); + startProxy(); + startClient(); + + byte[] content = new byte[1024]; + new Random().nextBytes(content); + int chunk1 = content.length / 2; + DeferredContentProvider contentProvider = new DeferredContentProvider(); + contentProvider.offer(ByteBuffer.wrap(content, 0, chunk1)); + CountDownLatch clientLatch = new CountDownLatch(1); + client.newRequest("localhost", serverConnector.getLocalPort()) + .header(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString()) + .content(contentProvider) + .send(new BufferingResponseListener() + { + @Override + public void onComplete(Result result) + { + if (result.isSucceeded()) + { + if (result.getResponse().getStatus() == HttpStatus.OK_200) + { + if (Arrays.equals(content, getContent())) + clientLatch.countDown(); + } + } + } + }); + + // Wait a while and then offer more content. + Thread.sleep(1000); + contentProvider.offer(ByteBuffer.wrap(content, chunk1, content.length - chunk1)); + contentProvider.close(); + + Assert.assertTrue(clientLatch.await(5, TimeUnit.SECONDS)); + } + + @Test + public void testExpect100ContinueRespond100ContinueSomeRequestContentThenFailure() throws Exception + { + CountDownLatch serverLatch = new CountDownLatch(1); + startServer(new HttpServlet() + { + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + // Send the 100 Continue. + ServletInputStream input = request.getInputStream(); + try + { + // Echo the content. + IO.copy(input, response.getOutputStream()); + } + catch (IOException x) + { + serverLatch.countDown(); + } + } + }); + startProxy(); + startClient(); + + long idleTimeout = 1000; + client.setIdleTimeout(idleTimeout); + + byte[] content = new byte[1024]; + new Random().nextBytes(content); + int chunk1 = content.length / 2; + DeferredContentProvider contentProvider = new DeferredContentProvider(); + contentProvider.offer(ByteBuffer.wrap(content, 0, chunk1)); + CountDownLatch clientLatch = new CountDownLatch(1); + client.newRequest("localhost", serverConnector.getLocalPort()) + .header(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString()) + .content(contentProvider) + .send(result -> + { + if (result.isFailed()) + clientLatch.countDown(); + }); + + // Wait more than the idle timeout to break the connection. + Thread.sleep(2 * idleTimeout); + + Assert.assertTrue(serverLatch.await(555, TimeUnit.SECONDS)); + Assert.assertTrue(clientLatch.await(555, TimeUnit.SECONDS)); + } + + @Test + public void testExpect100ContinueRespond417ExpectationFailed() throws Exception + { + CountDownLatch serverLatch1 = new CountDownLatch(1); + CountDownLatch serverLatch2 = new CountDownLatch(1); + startServer(new HttpServlet() + { + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + serverLatch1.countDown(); + + try + { + serverLatch2.await(5, TimeUnit.SECONDS); + } + catch (Throwable x) + { + throw new InterruptedIOException(); + } + + // Send the 417 Expectation Failed. + response.setStatus(HttpStatus.EXPECTATION_FAILED_417); + } + }); + startProxy(); + startClient(); + + byte[] content = new byte[1024]; + CountDownLatch contentLatch = new CountDownLatch(1); + CountDownLatch clientLatch = new CountDownLatch(1); + client.newRequest("localhost", serverConnector.getLocalPort()) + .header(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString()) + .content(new BytesContentProvider(content)) + .onRequestContent((request, buffer) -> contentLatch.countDown()) + .send(result -> + { + if (result.isFailed()) + { + if (result.getResponse().getStatus() == HttpStatus.EXPECTATION_FAILED_417) + clientLatch.countDown(); + } + }); + + // Wait until we arrive on the server. + Assert.assertTrue(serverLatch1.await(5, TimeUnit.SECONDS)); + // The client should not send the content yet. + Assert.assertFalse(contentLatch.await(1, TimeUnit.SECONDS)); + + // Make the server send the 417 Expectation Failed. + serverLatch2.countDown(); + + // The client should not send the content. + Assert.assertFalse(contentLatch.await(1, TimeUnit.SECONDS)); + Assert.assertTrue(clientLatch.await(5, TimeUnit.SECONDS)); + } } diff --git a/jetty-runner/src/main/java/org/eclipse/jetty/runner/Runner.java b/jetty-runner/src/main/java/org/eclipse/jetty/runner/Runner.java index 8929ede8134..bd2aadb4aa1 100644 --- a/jetty-runner/src/main/java/org/eclipse/jetty/runner/Runner.java +++ b/jetty-runner/src/main/java/org/eclipse/jetty/runner/Runner.java @@ -27,13 +27,13 @@ import java.util.Collections; import java.util.List; import java.util.Locale; +import org.eclipse.jetty.io.ConnectionStatistics; import org.eclipse.jetty.security.ConstraintMapping; import org.eclipse.jetty.security.ConstraintSecurityHandler; import org.eclipse.jetty.security.HashLoginService; import org.eclipse.jetty.security.authentication.BasicAuthenticator; import org.eclipse.jetty.server.AbstractConnector; import org.eclipse.jetty.server.Connector; -import org.eclipse.jetty.server.ConnectorStatistics; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.NCSARequestLog; import org.eclipse.jetty.server.Server; @@ -395,15 +395,15 @@ public class Runner connector.setHost(host); _server.addConnector(connector); if (_enableStats) - connector.addBean(new ConnectorStatistics()); + connector.addBean(new ConnectionStatistics()); } else { if (_enableStats) { - for (Connector connector : connectors) + for (Connector connector : connectors) { - ((AbstractConnector) connector).addBean(new ConnectorStatistics()); + ((AbstractConnector) connector).addBean(new ConnectionStatistics()); } } } diff --git a/jetty-server/src/main/config/etc/jetty-gzip.xml b/jetty-server/src/main/config/etc/jetty-gzip.xml index 93b41fd6396..6e5573449e7 100644 --- a/jetty-server/src/main/config/etc/jetty-gzip.xml +++ b/jetty-server/src/main/config/etc/jetty-gzip.xml @@ -15,6 +15,8 @@ + diff --git a/jetty-server/src/main/config/etc/jetty-stats.xml b/jetty-server/src/main/config/etc/jetty-stats.xml index 445ae6a8a43..954acd761df 100644 --- a/jetty-server/src/main/config/etc/jetty-stats.xml +++ b/jetty-server/src/main/config/etc/jetty-stats.xml @@ -12,7 +12,7 @@ - + diff --git a/jetty-server/src/main/config/etc/jetty-threadlimit.xml b/jetty-server/src/main/config/etc/jetty-threadlimit.xml new file mode 100644 index 00000000000..20faf163287 --- /dev/null +++ b/jetty-server/src/main/config/etc/jetty-threadlimit.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/jetty-server/src/main/config/etc/sessions/file/session-store.xml b/jetty-server/src/main/config/etc/sessions/file/session-store.xml index 356c9ff1dd3..3112cc91285 100644 --- a/jetty-server/src/main/config/etc/sessions/file/session-store.xml +++ b/jetty-server/src/main/config/etc/sessions/file/session-store.xml @@ -10,8 +10,8 @@ - - + + diff --git a/jetty-server/src/main/config/etc/sessions/id-manager.xml b/jetty-server/src/main/config/etc/sessions/id-manager.xml index b31f690ae67..945d5076275 100644 --- a/jetty-server/src/main/config/etc/sessions/id-manager.xml +++ b/jetty-server/src/main/config/etc/sessions/id-manager.xml @@ -12,7 +12,18 @@ - node + + + node + + + 0 + + + + + + diff --git a/jetty-server/src/main/config/etc/sessions/jdbc/datasource.xml b/jetty-server/src/main/config/etc/sessions/jdbc/datasource.xml index 5bdbec19e80..dad8ecd7058 100644 --- a/jetty-server/src/main/config/etc/sessions/jdbc/datasource.xml +++ b/jetty-server/src/main/config/etc/sessions/jdbc/datasource.xml @@ -5,7 +5,7 @@ - + - \ No newline at end of file + diff --git a/jetty-server/src/main/config/etc/sessions/jdbc/driver.xml b/jetty-server/src/main/config/etc/sessions/jdbc/driver.xml index ab6465d54de..2b225a5d94f 100644 --- a/jetty-server/src/main/config/etc/sessions/jdbc/driver.xml +++ b/jetty-server/src/main/config/etc/sessions/jdbc/driver.xml @@ -5,9 +5,9 @@ - - + + - \ No newline at end of file + diff --git a/jetty-server/src/main/config/etc/sessions/jdbc/session-store.xml b/jetty-server/src/main/config/etc/sessions/jdbc/session-store.xml index 30fde60af63..8f0d1c1b858 100644 --- a/jetty-server/src/main/config/etc/sessions/jdbc/session-store.xml +++ b/jetty-server/src/main/config/etc/sessions/jdbc/session-store.xml @@ -18,43 +18,43 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/jetty-server/src/main/config/etc/sessions/hash-session-cache.xml b/jetty-server/src/main/config/etc/sessions/session-cache-hash.xml similarity index 90% rename from jetty-server/src/main/config/etc/sessions/hash-session-cache.xml rename to jetty-server/src/main/config/etc/sessions/session-cache-hash.xml index 07a62f84e2d..9909e774915 100644 --- a/jetty-server/src/main/config/etc/sessions/hash-session-cache.xml +++ b/jetty-server/src/main/config/etc/sessions/session-cache-hash.xml @@ -12,6 +12,7 @@ + diff --git a/jetty-server/src/main/config/etc/sessions/session-cache-null.xml b/jetty-server/src/main/config/etc/sessions/session-cache-null.xml new file mode 100644 index 00000000000..b65c224cc46 --- /dev/null +++ b/jetty-server/src/main/config/etc/sessions/session-cache-null.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/jetty-server/src/main/config/modules/debug.mod b/jetty-server/src/main/config/modules/debug.mod index 7b75ecc0e79..9e0ae040b9f 100644 --- a/jetty-server/src/main/config/modules/debug.mod +++ b/jetty-server/src/main/config/modules/debug.mod @@ -3,6 +3,9 @@ Enables the DebugListener to generate additional logging regarding detailed request handling events. Renames threads to include request URI. +[Tags] +debug + [depend] deploy diff --git a/jetty-server/src/main/config/modules/debuglog.mod b/jetty-server/src/main/config/modules/debuglog.mod index a76f728a5b4..81db4894c71 100644 --- a/jetty-server/src/main/config/modules/debuglog.mod +++ b/jetty-server/src/main/config/modules/debuglog.mod @@ -2,6 +2,9 @@ Deprecated Debug Log using the DebugHandle. Replaced with the debug module. +[Tags] +debug + [depend] server diff --git a/jetty-server/src/main/config/modules/ext.mod b/jetty-server/src/main/config/modules/ext.mod index 4171f8dfc21..63081e550dd 100644 --- a/jetty-server/src/main/config/modules/ext.mod +++ b/jetty-server/src/main/config/modules/ext.mod @@ -2,6 +2,9 @@ Adds all jar files discovered in $JETTY_HOME/lib/ext and $JETTY_BASE/lib/ext to the servers classpath. +[Tags] +classpath + [lib] lib/ext/**.jar diff --git a/jetty-server/src/main/config/modules/gzip.mod b/jetty-server/src/main/config/modules/gzip.mod index 65663a16066..50db40b156e 100644 --- a/jetty-server/src/main/config/modules/gzip.mod +++ b/jetty-server/src/main/config/modules/gzip.mod @@ -2,6 +2,9 @@ Enable GzipHandler for dynamic gzip compression for the entire server. +[Tags] +handler + [depend] server @@ -20,3 +23,6 @@ etc/jetty-gzip.xml ## User agents for which gzip is disabled # jetty.gzip.excludedUserAgent=.*MSIE.6\.0.* + +## Inflate request buffer size, or 0 for no request inflation +# jetty.gzip.inflateBufferSize=0 diff --git a/jetty-server/src/main/config/modules/http-forwarded.mod b/jetty-server/src/main/config/modules/http-forwarded.mod index 6508a2b9a3f..2797bc29d3b 100644 --- a/jetty-server/src/main/config/modules/http-forwarded.mod +++ b/jetty-server/src/main/config/modules/http-forwarded.mod @@ -2,6 +2,9 @@ Adds a forwarded request customizer to the HTTP Connector to process forwarded-for style headers from a proxy. +[Tags] +connector + [depend] http diff --git a/jetty-server/src/main/config/modules/http.mod b/jetty-server/src/main/config/modules/http.mod index 3f2766f0e45..caf104cb9b4 100644 --- a/jetty-server/src/main/config/modules/http.mod +++ b/jetty-server/src/main/config/modules/http.mod @@ -3,6 +3,10 @@ Enables a HTTP connector on the server. By default HTTP/1 is support, but HTTP2C can be added to the connector with the http2c module. +[Tags] +connector +http + [depend] server diff --git a/jetty-server/src/main/config/modules/https.mod b/jetty-server/src/main/config/modules/https.mod index 6ffbd69d0cc..9ff301e58d5 100644 --- a/jetty-server/src/main/config/modules/https.mod +++ b/jetty-server/src/main/config/modules/https.mod @@ -1,6 +1,12 @@ [description] Adds HTTPS protocol support to the TLS(SSL) Connector +[Tags] +connector +https +http +ssl + [depend] ssl diff --git a/jetty-server/src/main/config/modules/ipaccess.mod b/jetty-server/src/main/config/modules/ipaccess.mod index 68f04dfc576..5afd05e0a11 100644 --- a/jetty-server/src/main/config/modules/ipaccess.mod +++ b/jetty-server/src/main/config/modules/ipaccess.mod @@ -2,6 +2,9 @@ Enable the ipaccess handler to apply a white/black list control of the remote IP of requests. +[Tags] +handler + [depend] server diff --git a/jetty-server/src/main/config/modules/jvm.mod b/jetty-server/src/main/config/modules/jvm.mod index 173a6d11ba1..30b0d966b96 100644 --- a/jetty-server/src/main/config/modules/jvm.mod +++ b/jetty-server/src/main/config/modules/jvm.mod @@ -1,6 +1,7 @@ [description] A noop module that creates an ini template useful for setting JVM arguments (eg -Xmx ) + [ini-template] ## JVM Configuration ## If JVM args are include in an ini file then --exec is needed @@ -16,7 +17,7 @@ setting JVM arguments (eg -Xmx ) # -XX:+CMSClassUnloadingEnabled # -XX:+UseCMSCompactAtFullCollection # -XX:CMSInitiatingOccupancyFraction=80 -# -verbose:gc +# -internal:gc # -XX:+PrintGCDateStamps # -XX:+PrintGCTimeStamps # -XX:+PrintGCDetails diff --git a/jetty-server/src/main/config/modules/logback-access.mod b/jetty-server/src/main/config/modules/logback-access.mod index b1275ba49b9..0cb8bd0de45 100644 --- a/jetty-server/src/main/config/modules/logback-access.mod +++ b/jetty-server/src/main/config/modules/logback-access.mod @@ -1,6 +1,11 @@ [description] Enables logback request log. +[Tags] +requestlog +logging +logback + [depend] server logback-core diff --git a/jetty-server/src/main/config/modules/proxy-protocol-ssl.mod b/jetty-server/src/main/config/modules/proxy-protocol-ssl.mod index 374763d0b5b..4b41e935bb6 100644 --- a/jetty-server/src/main/config/modules/proxy-protocol-ssl.mod +++ b/jetty-server/src/main/config/modules/proxy-protocol-ssl.mod @@ -5,6 +5,10 @@ This allows a Proxy operating in TCP mode to transport details of the proxied connection to the server. Both V1 and V2 versions of the protocol are supported. +[Tags] +connector +ssl + [depend] ssl diff --git a/jetty-server/src/main/config/modules/requestlog.mod b/jetty-server/src/main/config/modules/requestlog.mod index 628f759e088..0bf60edcdc0 100644 --- a/jetty-server/src/main/config/modules/requestlog.mod +++ b/jetty-server/src/main/config/modules/requestlog.mod @@ -1,6 +1,9 @@ [description] Enables a NCSA style request log. +[Tags] +requestlog + [depend] server @@ -36,4 +39,4 @@ logs/ # jetty.requestlog.timezone=GMT ## Whether to log LogLatency -# jetty.requestlog.loglatency=false \ No newline at end of file +# jetty.requestlog.loglatency=false diff --git a/jetty-server/src/main/config/modules/resources.mod b/jetty-server/src/main/config/modules/resources.mod index 56489486408..4e0bd35b43a 100644 --- a/jetty-server/src/main/config/modules/resources.mod +++ b/jetty-server/src/main/config/modules/resources.mod @@ -3,6 +3,9 @@ Adds the $JETTY_HOME/resources and/or $JETTY_BASE/resources directory to the server classpath. Useful for configuration property files (eg jetty-logging.properties) +[Tags] +classpath + [lib] resources/ diff --git a/jetty-server/src/main/config/modules/session-cache-hash.mod b/jetty-server/src/main/config/modules/session-cache-hash.mod index 4930104c8ff..1f257867b25 100644 --- a/jetty-server/src/main/config/modules/session-cache-hash.mod +++ b/jetty-server/src/main/config/modules/session-cache-hash.mod @@ -4,6 +4,9 @@ If not enabled, sessions will use a HashSessionCache by default, so enabling via this module is only needed if the configuration properties need to be changed. +[Tags] +session + [provides] session-cache @@ -11,9 +14,10 @@ session-cache sessions [xml] -etc/sessions/hash-session-cache.xml +etc/sessions/session-cache-hash.xml [ini-template] #jetty.session.evictionPolicy=-1 #jetty.session.saveOnInactiveEvict=false +#jetty.session.saveOnCreate=false #jetty.session.removeUnloadableSessions=false diff --git a/jetty-server/src/main/config/modules/session-cache-null.mod b/jetty-server/src/main/config/modules/session-cache-null.mod new file mode 100644 index 00000000000..70c9e97fa37 --- /dev/null +++ b/jetty-server/src/main/config/modules/session-cache-null.mod @@ -0,0 +1,18 @@ +[description] +A trivial SessionCache that does not actually cache sessions. + +[Tags] +session + +[provides] +session-cache + +[depends] +sessions + +[xml] +etc/sessions/session-cache-null.xml + +[ini-template] +#jetty.session.saveOnCreate=false +#jetty.session.removeUnloadableSessions=false diff --git a/jetty-server/src/main/config/modules/session-store-cache.mod b/jetty-server/src/main/config/modules/session-store-cache.mod index e9a170b823e..cac19d1207d 100644 --- a/jetty-server/src/main/config/modules/session-store-cache.mod +++ b/jetty-server/src/main/config/modules/session-store-cache.mod @@ -1,6 +1,9 @@ [description] Enables caching of SessionData in front of a SessionDataStore. +[Tags] +session + [depend] session-store diff --git a/jetty-server/src/main/config/modules/session-store-file.mod b/jetty-server/src/main/config/modules/session-store-file.mod index 61ab04fd82d..d644f67dddd 100644 --- a/jetty-server/src/main/config/modules/session-store-file.mod +++ b/jetty-server/src/main/config/modules/session-store-file.mod @@ -1,6 +1,9 @@ [description] Enables session persistent storage in files. +[Tags] +session + [provides] session-store @@ -14,6 +17,6 @@ etc/sessions/file/session-store.xml sessions/ [ini-template] -jetty.session.storeDir=${jetty.base}/sessions -#jetty.session.deleteUnrestorableFiles=false +jetty.session.file.storeDir=${jetty.base}/sessions +#jetty.session.file.deleteUnrestorableFiles=false diff --git a/jetty-server/src/main/config/modules/session-store-jdbc.mod b/jetty-server/src/main/config/modules/session-store-jdbc.mod index 6e790b01d22..69bf3125bd0 100644 --- a/jetty-server/src/main/config/modules/session-store-jdbc.mod +++ b/jetty-server/src/main/config/modules/session-store-jdbc.mod @@ -1,6 +1,9 @@ [description] Enables JDBC peristent/distributed session storage. +[Tags] +session + [provides] session-store @@ -23,27 +26,27 @@ db-connection-type=datasource ## Connection type:Datasource db-connection-type=datasource -#jetty.session.datasourceName=/jdbc/sessions +#jetty.session.jdbc.datasourceName=/jdbc/sessions ## Connection type:driver #db-connection-type=driver -#jetty.session.driverClass= -#jetty.session.driverUrl= +#jetty.session.jdbc.driverClass= +#jetty.session.jdbc.driverUrl= ## Session table schema -#jetty.sessionTableSchema.accessTimeColumn=accessTime -#jetty.sessionTableSchema.contextPathColumn=contextPath -#jetty.sessionTableSchema.cookieTimeColumn=cookieTime -#jetty.sessionTableSchema.createTimeColumn=createTime -#jetty.sessionTableSchema.expiryTimeColumn=expiryTime -#jetty.sessionTableSchema.lastAccessTimeColumn=lastAccessTime -#jetty.sessionTableSchema.lastSavedTimeColumn=lastSavedTime -#jetty.sessionTableSchema.idColumn=sessionId -#jetty.sessionTableSchema.lastNodeColumn=lastNode -#jetty.sessionTableSchema.virtualHostColumn=virtualHost -#jetty.sessionTableSchema.maxIntervalColumn=maxInterval -#jetty.sessionTableSchema.mapColumn=map -#jetty.sessionTableSchema.table=JettySessions +#jetty.session.jdbc.schema.accessTimeColumn=accessTime +#jetty.session.jdbc.schema.contextPathColumn=contextPath +#jetty.session.jdbc.schema.cookieTimeColumn=cookieTime +#jetty.session.jdbc.schema.createTimeColumn=createTime +#jetty.session.jdbc.schema.expiryTimeColumn=expiryTime +#jetty.session.jdbc.schema.lastAccessTimeColumn=lastAccessTime +#jetty.session.jdbc.schema.lastSavedTimeColumn=lastSavedTime +#jetty.session.jdbc.schema.idColumn=sessionId +#jetty.session.jdbc.schema.lastNodeColumn=lastNode +#jetty.session.jdbc.schema.virtualHostColumn=virtualHost +#jetty.session.jdbc.schema.maxIntervalColumn=maxInterval +#jetty.session.jdbc.schema.mapColumn=map +#jetty.session.jdbc.schema.table=JettySessions diff --git a/jetty-server/src/main/config/modules/sessions.mod b/jetty-server/src/main/config/modules/sessions.mod index 2b9a69285cf..4ce1cde856e 100644 --- a/jetty-server/src/main/config/modules/sessions.mod +++ b/jetty-server/src/main/config/modules/sessions.mod @@ -5,6 +5,9 @@ created or by enabling other session-cache or session-store modules. Without this module enabled, the server may still use sessions, but their management cannot be configured. +[Tags] +session + [depends] server @@ -16,4 +19,4 @@ etc/sessions/id-manager.xml #jetty.sessionIdManager.workerName=node1 ## Period between runs of the session scavenger (in seconds) -#jetty.sessionScavengeInterval.seconds=60 +#jetty.sessionScavengeInterval.seconds=600 diff --git a/jetty-server/src/main/config/modules/ssl.mod b/jetty-server/src/main/config/modules/ssl.mod index 43c29143bde..db92f255bb2 100644 --- a/jetty-server/src/main/config/modules/ssl.mod +++ b/jetty-server/src/main/config/modules/ssl.mod @@ -3,6 +3,10 @@ Enables a TLS(SSL) Connector on the server. This may be used for HTTPS and/or HTTP2 by enabling the associated support modules. +[Tags] +connector +ssl + [depend] server diff --git a/jetty-server/src/main/config/modules/stats.mod b/jetty-server/src/main/config/modules/stats.mod index 838d54a904d..2b4d3d32f8b 100644 --- a/jetty-server/src/main/config/modules/stats.mod +++ b/jetty-server/src/main/config/modules/stats.mod @@ -2,6 +2,9 @@ Enable detailed statistics collection for the server, available via JMX. +[Tags] +handler + [depend] server diff --git a/jetty-server/src/main/config/modules/threadlimit.mod b/jetty-server/src/main/config/modules/threadlimit.mod new file mode 100644 index 00000000000..b6d41dc1480 --- /dev/null +++ b/jetty-server/src/main/config/modules/threadlimit.mod @@ -0,0 +1,28 @@ +# +# Thread Limit module +# Applies ThreadLimiteHandler to entire server +# + +[Tags] +handler + +[depend] +server + +[xml] +etc/jetty-threadlimit.xml + +[ini-template] +## Select style of proxy forwarded header +#jetty.threadlimit.forwardedHeader=X-Forwarded-For +#jetty.threadlimit.forwardedHeader=Forwarded + +## Enabled by default? +#jetty.threadlimit.enabled=true + +## MS to block for waiting for available thread +#jetty.threadlimit.blockForMs=0 + +## Thread limit per remote IP +#jetty.threadlimit.threadLimit=10 + diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextEvent.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextEvent.java index 4d5caf206fd..4a6ad3db3ea 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextEvent.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextEvent.java @@ -27,6 +27,7 @@ import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import org.eclipse.jetty.server.handler.ContextHandler.Context; +import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.thread.Scheduler; public class AsyncContextEvent extends AsyncEvent implements Runnable @@ -94,7 +95,7 @@ public class AsyncContextEvent extends AsyncEvent implements Runnable } /** - * @return The path in the context + * @return The path in the context (encoded with possible query string) */ public String getPath() { @@ -131,6 +132,9 @@ public class AsyncContextEvent extends AsyncEvent implements Runnable _dispatchContext=context; } + /** + * @param path encoded URI + */ public void setDispatchPath(String path) { _dispatchPath=path; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ConnectorStatistics.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ConnectorStatistics.java index e73cdc6da2d..218d23f9a9e 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ConnectorStatistics.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ConnectorStatistics.java @@ -43,7 +43,10 @@ import org.eclipse.jetty.util.statistic.SampleStatistic; /** A Connector.Listener that gathers Connector and Connections Statistics. * Adding an instance of this class as with {@link AbstractConnector#addBean(Object)} * will register the listener with all connections accepted by that connector. + * + * @deprecated use {@link ServerConnectionStatistics} instead. */ +@Deprecated @ManagedObject("Connector Statistics") public class ConnectorStatistics extends AbstractLifeCycle implements Dumpable, Connection.Listener { @@ -75,8 +78,8 @@ public class ConnectorStatistics extends AbstractLifeCycle implements Dumpable, { if (isStarted()) { - int msgsIn=connection.getMessagesIn(); - int msgsOut=connection.getMessagesOut(); + long msgsIn=connection.getMessagesIn(); + long msgsOut=connection.getMessagesOut(); _messagesIn.set(msgsIn); _messagesOut.set(msgsOut); _connectionStats.decrement(); @@ -302,7 +305,7 @@ public class ConnectorStatistics extends AbstractLifeCycle implements Dumpable, _messagesOut=connection.getMessagesOut(); } - final int _messagesIn; - final int _messagesOut; + final long _messagesIn; + final long _messagesOut; } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java index 48289da495c..31ec5e5e842 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java @@ -38,12 +38,12 @@ import org.eclipse.jetty.util.StringUtil; * This customizer looks at at HTTP request for headers that indicate * it has been forwarded by one or more proxies. Specifically handled are *
      - *
    • Forwarded, as defined by rfc7239 - *
    • X-Forwarded-Host
    • - *
    • X-Forwarded-Server
    • - *
    • X-Forwarded-For
    • - *
    • X-Forwarded-Proto
    • - *
    • X-Proxied-Https
    • + *
    • {@code Forwarded}, as defined by rfc7239 + *
    • {@code X-Forwarded-Host}
    • + *
    • {@code X-Forwarded-Server}
    • + *
    • {@code X-Forwarded-For}
    • + *
    • {@code X-Forwarded-Proto}
    • + *
    • {@code X-Proxied-Https}
    • *
    *

    If these headers are present, then the {@link Request} object is updated * so that the proxy is not seen as the other end point of the connection on which @@ -68,7 +68,7 @@ public class ForwardedRequestCustomizer implements Customizer /** * @return true if the proxy address obtained via - * X-Forwarded-Server or RFC7239 "by" is used as + * {@code X-Forwarded-Server} or RFC7239 "by" is used as * the request authority. Default false */ public boolean getProxyAsAuthority() @@ -78,7 +78,7 @@ public class ForwardedRequestCustomizer implements Customizer /** * @param proxyAsAuthority if true, use the proxy address obtained via - * X-Forwarded-Server or RFC7239 "by" as the request authority. + * {@code X-Forwarded-Server} or RFC7239 "by" as the request authority. */ public void setProxyAsAuthority(boolean proxyAsAuthority) { @@ -87,7 +87,7 @@ public class ForwardedRequestCustomizer implements Customizer /** * Configure to only support the RFC7239 Forwarded header and to - * not support any X-Forwarded- headers. This convenience method + * not support any {@code X-Forwarded-} headers. This convenience method * clears all the non RFC headers if passed true and sets them to * the default values (if not already set) if passed false. */ @@ -159,7 +159,7 @@ public class ForwardedRequestCustomizer implements Customizer /** * @param forwardedHostHeader - * The header name for forwarded hosts (default x-forwarded-host) + * The header name for forwarded hosts (default {@code X-Forwarded-Host}) */ public void setForwardedHostHeader(String forwardedHostHeader) { @@ -176,7 +176,7 @@ public class ForwardedRequestCustomizer implements Customizer /** * @param forwardedServerHeader - * The header name for forwarded server (default x-forwarded-server) + * The header name for forwarded server (default {@code X-Forwarded-Server}) */ public void setForwardedServerHeader(String forwardedServerHeader) { @@ -193,7 +193,7 @@ public class ForwardedRequestCustomizer implements Customizer /** * @param forwardedRemoteAddressHeader - * The header name for forwarded for (default x-forwarded-for) + * The header name for forwarded for (default {@code X-Forwarded-For}) */ public void setForwardedForHeader(String forwardedRemoteAddressHeader) { @@ -203,7 +203,7 @@ public class ForwardedRequestCustomizer implements Customizer /** * Get the forwardedProtoHeader. * - * @return the forwardedProtoHeader (default X-Forwarded-For) + * @return the forwardedProtoHeader (default {@code X-Forwarded-Proto}) */ public String getForwardedProtoHeader() { @@ -214,7 +214,7 @@ public class ForwardedRequestCustomizer implements Customizer * Set the forwardedProtoHeader. * * @param forwardedProtoHeader - * the forwardedProtoHeader to set (default X-Forwarded-For) + * the forwardedProtoHeader to set (default {@code X-Forwarded-Proto}) */ public void setForwardedProtoHeader(String forwardedProtoHeader) { @@ -222,7 +222,7 @@ public class ForwardedRequestCustomizer implements Customizer } /** - * @return The header name holding a forwarded cipher suite (default Proxy-auth-cert) + * @return The header name holding a forwarded cipher suite (default {@code Proxy-auth-cert}) */ public String getForwardedCipherSuiteHeader() { @@ -231,7 +231,7 @@ public class ForwardedRequestCustomizer implements Customizer /** * @param forwardedCipherSuite - * The header name holding a forwarded cipher suite (default Proxy-auth-cert) + * The header name holding a forwarded cipher suite (default {@code Proxy-auth-cert}) */ public void setForwardedCipherSuiteHeader(String forwardedCipherSuite) { @@ -239,7 +239,7 @@ public class ForwardedRequestCustomizer implements Customizer } /** - * @return The header name holding a forwarded SSL Session ID (default Proxy-ssl-id) + * @return The header name holding a forwarded SSL Session ID (default {@code Proxy-ssl-id}) */ public String getForwardedSslSessionIdHeader() { @@ -248,7 +248,7 @@ public class ForwardedRequestCustomizer implements Customizer /** * @param forwardedSslSessionId - * The header name holding a forwarded SSL Session ID (default Proxy-ssl-id) + * The header name holding a forwarded SSL Session ID (default {@code Proxy-ssl-id}) */ public void setForwardedSslSessionIdHeader(String forwardedSslSessionId) { @@ -256,7 +256,7 @@ public class ForwardedRequestCustomizer implements Customizer } /** - * @return The header name holding a forwarded Https (on|off true|false) value + * @return The header name holding a forwarded Https status indicator (on|off true|false) (default {@code X-Proxied-Https}) */ public String getForwardedHttpsHeader() { @@ -264,7 +264,7 @@ public class ForwardedRequestCustomizer implements Customizer } /** - * @param forwardedHttpsHeader + * @param forwardedHttpsHeader the header name holding a forwarded Https status indicator(default {@code X-Proxied-Https}) */ public void setForwardedHttpsHeader(String forwardedHttpsHeader) { @@ -294,7 +294,7 @@ public class ForwardedRequestCustomizer implements Customizer { HttpFields httpFields = request.getHttpFields(); - RFC7239 rfc7230 = null; + RFC7239 rfc7239 = null; String forwardedHost = null; String forwardedServer = null; String forwardedFor = null; @@ -343,9 +343,9 @@ public class ForwardedRequestCustomizer implements Customizer if (_forwardedHeader!=null && _forwardedHeader.equalsIgnoreCase(name)) { - if (rfc7230==null) - rfc7230= new RFC7239(); - rfc7230.addValue(field.getValue()); + if (rfc7239==null) + rfc7239= new RFC7239(); + rfc7239.addValue(field.getValue()); } } @@ -356,9 +356,9 @@ public class ForwardedRequestCustomizer implements Customizer httpFields.put(_forcedHost); request.setAuthority(_forcedHost.getHost(),_forcedHost.getPort()); } - else if (rfc7230!=null && rfc7230._host!=null) + else if (rfc7239!=null && rfc7239._host!=null) { - HostPortHttpField auth = rfc7230._host; + HostPortHttpField auth = rfc7239._host; httpFields.put(auth); request.setAuthority(auth.getHost(),auth.getPort()); } @@ -370,9 +370,9 @@ public class ForwardedRequestCustomizer implements Customizer } else if (_proxyAsAuthority) { - if (rfc7230!=null && rfc7230._by!=null) + if (rfc7239!=null && rfc7239._by!=null) { - HostPortHttpField auth = rfc7230._by; + HostPortHttpField auth = rfc7239._by; httpFields.put(auth); request.setAuthority(auth.getHost(),auth.getPort()); } @@ -383,9 +383,9 @@ public class ForwardedRequestCustomizer implements Customizer } // handle remote end identifier - if (rfc7230!=null && rfc7230._for!=null) + if (rfc7239!=null && rfc7239._for!=null) { - request.setRemoteAddr(InetSocketAddress.createUnresolved(rfc7230._for.getHost(),rfc7230._for.getPort())); + request.setRemoteAddr(InetSocketAddress.createUnresolved(rfc7239._for.getHost(),rfc7239._for.getPort())); } else if (forwardedFor != null) { @@ -393,10 +393,10 @@ public class ForwardedRequestCustomizer implements Customizer } // handle protocol identifier - if (rfc7230!=null && rfc7230._proto!=null) + if (rfc7239!=null && rfc7239._proto!=null) { - request.setScheme(rfc7230._proto); - if (rfc7230._proto.equals(config.getSecureScheme())) + request.setScheme(rfc7239._proto); + if (rfc7239._proto.equals(config.getSecureScheme())) request.setSecure(true); } else if (forwardedProto != null) @@ -455,9 +455,6 @@ public class ForwardedRequestCustomizer implements Customizer _forcedHost = new HostPortHttpField(hostHeader); } - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ private final class RFC7239 extends QuotedCSV { HostPortHttpField _by; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index 58a725ebb3d..eaa0bfe93f5 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -24,8 +24,7 @@ import java.nio.ByteBuffer; import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.atomic.AtomicLong; import javax.servlet.DispatcherType; @@ -68,7 +67,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor { private static final Logger LOG = Log.getLogger(HttpChannel.class); private final AtomicBoolean _committed = new AtomicBoolean(); - private final AtomicInteger _requests = new AtomicInteger(); + private final AtomicLong _requests = new AtomicLong(); private final Connector _connector; private final Executor _executor; private final HttpConfiguration _configuration; @@ -79,6 +78,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor private final Response _response; private MetaData.Response _committedMetaData; private RequestLog _requestLog; + private long _oldIdleTimeout; /** Bytes written after interception (eg after compression) */ private long _written; @@ -124,7 +124,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor /** * @return the number of requests handled by this connection */ - public int getRequests() + public long getRequests() { return _requests.get(); } @@ -265,8 +265,6 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor handle(); } - AtomicReference caller = new AtomicReference<>(); - /** * @return True if the channel is ready to continue handling (ie it is not suspended) */ @@ -354,7 +352,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor { _response.reset(); Integer icode = (Integer)_request.getAttribute(ERROR_STATUS_CODE); - int code = icode!=null?icode.intValue():HttpStatus.INTERNAL_SERVER_ERROR_500; + int code = icode != null ? icode : HttpStatus.INTERNAL_SERVER_ERROR_500; _response.setStatus(code); _request.setAttribute(ERROR_STATUS_CODE,code); if (icode==null) @@ -478,9 +476,9 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor else if (failure instanceof BadMessageException) { if (LOG.isDebugEnabled()) - LOG.warn(_request.getRequestURI(), failure); + LOG.debug(_request.getRequestURI(), failure); else - LOG.warn("{} {}",_request.getRequestURI(), failure.getMessage()); + LOG.warn("{} {}",_request.getRequestURI(), failure); } else { @@ -507,7 +505,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor // Minimal response Integer code=(Integer)_request.getAttribute(ERROR_STATUS_CODE); _response.reset(); - _response.setStatus(code==null?500:code.intValue()); + _response.setStatus(code == null ? 500 : code); _response.flushBuffer(); } } @@ -550,6 +548,11 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor if (_configuration.getSendDateHeader() && !fields.contains(HttpHeader.DATE)) fields.put(_connector.getServer().getDateField()); + long idleTO=_configuration.getIdleTimeout(); + _oldIdleTimeout=getIdleTimeout(); + if (idleTO>=0 && _oldIdleTimeout!=idleTO) + setIdleTimeout(idleTO); + _request.setMetaData(request); if (LOG.isDebugEnabled()) @@ -581,6 +584,10 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor if (_requestLog!=null ) _requestLog.log(_request, _response); + long idleTO=_configuration.getIdleTimeout(); + if (idleTO>=0 && getIdleTimeout()!=_oldIdleTimeout) + setIdleTimeout(_oldIdleTimeout); + _transport.onCompleted(); } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java index c5b348e60cf..6668678874c 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java @@ -222,8 +222,8 @@ public class HttpChannelOverHttp extends HttpChannel implements HttpParser.Reque // If we have no request yet, just close if (_metadata.getMethod() == null) _httpConnection.close(); - else - onEarlyEOF(); + else if (onEarlyEOF()) + handle(); } @Override diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java index cce294b4bc4..5a819b8ef8d 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java @@ -367,6 +367,8 @@ public class HttpChannelState protected Action unhandle() { Action action; + boolean read_interested=false; + try(Locker.Lock lock= _locker.lock()) { if(DEBUG) @@ -424,8 +426,8 @@ public class HttpChannelState _state=State.ASYNC_WAIT; action=Action.WAIT; if (_asyncReadUnready) - _channel.asyncReadFillInterested(); - Scheduler scheduler = _channel.getScheduler(); + read_interested=true; + Scheduler scheduler=_channel.getScheduler(); if (scheduler!=null && _timeoutMs>0) _event.setTimeoutTask(scheduler.schedule(_event,_timeoutMs,TimeUnit.MILLISECONDS)); } @@ -463,6 +465,9 @@ public class HttpChannelState } } + if (read_interested) + _channel.asyncReadFillInterested(); + return action; } @@ -537,7 +542,7 @@ public class HttpChannelState } - final AtomicReference error=new AtomicReference(); + final AtomicReference error=new AtomicReference<>(); if (listeners!=null) { Runnable task=new Runnable() diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java index d2ec7bd0398..5e6fb8a8ddb 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java @@ -56,6 +56,7 @@ public class HttpConfiguration private int _responseHeaderSize=8*1024; private int _headerCacheSize=512; private int _securePort; + private long _idleTimeout=-1; private long _blockingTimeout=-1; private String _secureScheme = HttpScheme.HTTPS.asString(); private boolean _sendServerVersion = true; @@ -64,6 +65,7 @@ public class HttpConfiguration private boolean _delayDispatchUntilContent = true; private boolean _persistentConnectionsEnabled = true; private int _maxErrorDispatches = 10; + private long _minRequestDataRate; /* ------------------------------------------------------------ */ /** @@ -113,6 +115,7 @@ public class HttpConfiguration _headerCacheSize=config._headerCacheSize; _secureScheme=config._secureScheme; _securePort=config._securePort; + _idleTimeout=config._idleTimeout; _blockingTimeout=config._blockingTimeout; _sendDateHeader=config._sendDateHeader; _sendServerVersion=config._sendServerVersion; @@ -120,6 +123,7 @@ public class HttpConfiguration _delayDispatchUntilContent=config._delayDispatchUntilContent; _persistentConnectionsEnabled=config._persistentConnectionsEnabled; _maxErrorDispatches=config._maxErrorDispatches; + _minRequestDataRate=config._minRequestDataRate; } /* ------------------------------------------------------------ */ @@ -200,12 +204,37 @@ public class HttpConfiguration } /* ------------------------------------------------------------ */ - @ManagedAttribute("True if HTTP/1 persistent connection are enabled") + @ManagedAttribute("Whether persistent connections are enabled") public boolean isPersistentConnectionsEnabled() { return _persistentConnectionsEnabled; } + /* ------------------------------------------------------------ */ + /** Get the max idle time in ms. + *

    The max idle time is applied to a HTTP request for IO operations and + * delayed dispatch. + * @return the max idle time in ms or if == 0 implies an infinite timeout, <0 + * implies no HTTP channel timeout and the connection timeout is used instead. + */ + @ManagedAttribute("The idle timeout in ms for I/O operations during the handling of a HTTP request") + public long getIdleTimeout() + { + return _idleTimeout; + } + + /* ------------------------------------------------------------ */ + /** Set the max idle time in ms. + *

    The max idle time is applied to a HTTP request for IO operations and + * delayed dispatch. + * @param timeoutMs the max idle time in ms or if == 0 implies an infinite timeout, <0 + * implies no HTTP channel timeout and the connection timeout is used instead. + */ + public void setIdleTimeout(long timeoutMs) + { + _idleTimeout=timeoutMs; + } + /* ------------------------------------------------------------ */ /** Get the timeout applied to blocking operations. *

    This timeout is in addition to the {@link Connector#getIdleTimeout()}, and applies @@ -214,7 +243,7 @@ public class HttpConfiguration * @return -1, for no blocking timeout (default), 0 for a blocking timeout equal to the * idle timeout; >0 for a timeout in ms applied to the total blocking operation. */ - @ManagedAttribute("Timeout in MS for blocking operations.") + @ManagedAttribute("Total timeout in ms for blocking I/O operations.") public long getBlockingTimeout() { return _blockingTimeout; @@ -246,7 +275,7 @@ public class HttpConfiguration } /* ------------------------------------------------------------ */ - @ManagedAttribute("if true, send the Server header in responses") + @ManagedAttribute("Whether to send the Server header in responses") public boolean getSendServerVersion() { return _sendServerVersion; @@ -272,7 +301,7 @@ public class HttpConfiguration } /* ------------------------------------------------------------ */ - @ManagedAttribute("if true, send the X-Powered-By header in responses") + @ManagedAttribute("Whether to send the X-Powered-By header in responses") public boolean getSendXPoweredBy() { return _sendXPoweredBy; @@ -285,7 +314,7 @@ public class HttpConfiguration } /* ------------------------------------------------------------ */ - @ManagedAttribute("if true, include the date in HTTP headers") + @ManagedAttribute("Whether to send the Date header in responses") public boolean getSendDateHeader() { return _sendDateHeader; @@ -301,7 +330,7 @@ public class HttpConfiguration } /* ------------------------------------------------------------ */ - @ManagedAttribute("if true, delay the application dispatch until content is available") + @ManagedAttribute("Whether to delay the application dispatch until content is available") public boolean isDelayDispatchUntilContent() { return _delayDispatchUntilContent; @@ -479,4 +508,23 @@ public class HttpConfiguration { _maxErrorDispatches=max; } + + /* ------------------------------------------------------------ */ + /** + * @return The minimum request data rate in bytes per second; or <=0 for no limit + */ + @ManagedAttribute("The minimum request content data rate in bytes per second") + public long getMinRequestDataRate() + { + return _minRequestDataRate; + } + + /* ------------------------------------------------------------ */ + /** + * @param bytesPerSecond The minimum request data rate in bytes per second; or <=0 for no limit + */ + public void setMinRequestDataRate(long bytesPerSecond) + { + _minRequestDataRate=bytesPerSecond; + } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java index 4ca95a61a19..af6a11163a2 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java @@ -44,7 +44,6 @@ import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.IteratingCallback; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.thread.Invocable.InvocationType; /** *

    A {@link Connection} that handles the HTTP protocol.

    @@ -125,9 +124,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http protected HttpChannelOverHttp newHttpChannel() { - HttpChannelOverHttp httpChannel = new HttpChannelOverHttp(this, _connector, _config, getEndPoint(), this); - - return httpChannel; + return new HttpChannelOverHttp(this, _connector, _config, getEndPoint(), this); } protected HttpParser newHttpParser(HttpCompliance compliance) @@ -172,13 +169,13 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http } @Override - public int getMessagesIn() + public long getMessagesIn() { return getHttpChannel().getRequests(); } @Override - public int getMessagesOut() + public long getMessagesOut() { return getHttpChannel().getRequests(); } @@ -286,9 +283,8 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http while (_parser.inContentState()) { int filled = fillRequestBuffer(); - boolean handle = parseRequestBuffer(); - handled|=handle; - if (handle || filled<=0 || _channel.getRequest().getHttpInput().hasContent()) + handled = parseRequestBuffer(); + if (handled || filled<=0 || _channel.getRequest().getHttpInput().hasContent()) break; } return handled; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java index cfcbb8b6c78..52604608e28 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java @@ -25,46 +25,119 @@ import java.util.ArrayDeque; import java.util.Deque; import java.util.Objects; import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; +import org.eclipse.jetty.http.BadMessageException; +import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.io.EofException; import org.eclipse.jetty.io.RuntimeIOException; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.component.Destroyable; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.thread.Invocable.InvocationType; /** * {@link HttpInput} provides an implementation of {@link ServletInputStream} for {@link HttpChannel}. *

    - * Content may arrive in patterns such as [content(), content(), messageComplete()] so that this class - * maintains two states: the content state that tells whether there is content to consume and the EOF - * state that tells whether an EOF has arrived. - * Only once the content has been consumed the content state is moved to the EOF state. + * Content may arrive in patterns such as [content(), content(), messageComplete()] so that this class maintains two states: the content state that tells + * whether there is content to consume and the EOF state that tells whether an EOF has arrived. Only once the content has been consumed the content state is + * moved to the EOF state. */ public class HttpInput extends ServletInputStream implements Runnable { + /** + * An interceptor for HTTP Request input. + *

    + * Unlike inputstream wrappers that can be applied by filters, an interceptor + * is entirely transparent and works with async IO APIs. + *

    + * An Interceptor may consume data from the passed content and the interceptor + * will continue to be called for the same content until the interceptor returns + * null or an empty content. Thus even if the passed content is completely consumed + * the interceptor will be called with the same content until it can no longer + * produce more content. + * @see HttpInput#setInterceptor(Interceptor) + * @see HttpInput#addInterceptor(Interceptor) + */ + public interface Interceptor + { + /** + * @param content The content to be intercepted (may be empty or a {@link SentinelContent}. + * The content will be modified with any data the interceptor consumes, but there is no requirement + * that all the data is consumed by the interceptor. + * @return The intercepted content or null if interception is completed for that content. + */ + Content readFrom(Content content); + } + + /** + * An {@link Interceptor} that chains two other {@link Interceptor}s together. + * The {@link #readFrom(Content)} calls the previous {@link Interceptor}'s + * {@link #readFrom(Content)} and then passes any {@link Content} returned + * to the next {@link Interceptor}. + */ + public static class ChainedInterceptor implements Interceptor, Destroyable + { + private final Interceptor _prev; + private final Interceptor _next; + + public ChainedInterceptor(Interceptor prev, Interceptor next) + { + _prev = prev; + _next = next; + } + + public Interceptor getPrev() + { + return _prev; + } + + public Interceptor getNext() + { + return _next; + } + + @Override + public Content readFrom(Content content) + { + return getNext().readFrom(getPrev().readFrom(content)); + } + + @Override + public void destroy() + { + if (_prev instanceof Destroyable) + ((Destroyable)_prev).destroy(); + if (_next instanceof Destroyable) + ((Destroyable)_next).destroy(); + } + } + private final static Logger LOG = Log.getLogger(HttpInput.class); private final static Content EOF_CONTENT = new EofContent("EOF"); private final static Content EARLY_EOF_CONTENT = new EofContent("EARLY_EOF"); private final byte[] _oneByteBuffer = new byte[1]; + private Content _content; + private Content _intercepted; private final Deque _inputQ = new ArrayDeque<>(); private final HttpChannelState _channelState; private ReadListener _listener; private State _state = STREAM; + private long _firstByteTimeStamp = -1; + private long _contentArrived; private long _contentConsumed; - private long _blockingTimeoutAt = -1; + private long _blockUntil; + private Interceptor _interceptor; public HttpInput(HttpChannelState state) { - _channelState=state; - if (_channelState.getHttpChannel().getHttpConfiguration().getBlockingTimeout()>0) - _blockingTimeoutAt=0; + _channelState = state; } protected HttpChannelState getHttpChannelState() @@ -76,6 +149,9 @@ public class HttpInput extends ServletInputStream implements Runnable { synchronized (_inputQ) { + if (_content!=null) + _content.failed(null); + _content = null; Content item = _inputQ.poll(); while (item != null) { @@ -84,33 +160,71 @@ public class HttpInput extends ServletInputStream implements Runnable } _listener = null; _state = STREAM; + _contentArrived = 0; _contentConsumed = 0; + _firstByteTimeStamp = -1; + _blockUntil = 0; + if (_interceptor instanceof Destroyable) + ((Destroyable)_interceptor).destroy(); + _interceptor = null; } } + /** + * @return The current Interceptor, or null if none set + */ + public Interceptor getInterceptor() + { + return _interceptor; + } + + /** + * Set the interceptor. + * @param interceptor The interceptor to use. + */ + public void setInterceptor(Interceptor interceptor) + { + _interceptor = interceptor; + } + + /** + * Set the {@link Interceptor}, using a {@link ChainedInterceptor} if + * an {@link Interceptor} is already set. + * @param interceptor the next {@link Interceptor} in a chain + */ + public void addInterceptor(Interceptor interceptor) + { + if (_interceptor == null) + _interceptor = interceptor; + else + _interceptor = new ChainedInterceptor(_interceptor,interceptor); + } + @Override public int available() { - int available=0; - boolean woken=false; + int available = 0; + boolean woken = false; synchronized (_inputQ) { - Content content = _inputQ.peek(); - if (content==null) + if (_content == null) + _content = _inputQ.poll(); + if (_content == null) { try { produceContent(); } - catch(IOException e) + catch (IOException e) { - woken=failed(e); + woken = failed(e); } - content = _inputQ.peek(); + if (_content == null) + _content = _inputQ.poll(); } - if (content!=null) - available= remaining(content); + if (_content != null) + available = _content.remaining(); } if (woken) @@ -125,14 +239,18 @@ public class HttpInput extends ServletInputStream implements Runnable executor.execute(channel); } + private long getBlockingTimeout() + { + return getHttpChannelState().getHttpChannel().getHttpConfiguration().getBlockingTimeout(); + } @Override public int read() throws IOException { - int read = read(_oneByteBuffer, 0, 1); - if (read==0) + int read = read(_oneByteBuffer,0,1); + if (read == 0) throw new IllegalStateException("unready read=0"); - return read < 0 ? -1 : _oneByteBuffer[0] & 0xFF; + return read < 0?-1:_oneByteBuffer[0] & 0xFF; } @Override @@ -140,19 +258,39 @@ public class HttpInput extends ServletInputStream implements Runnable { synchronized (_inputQ) { - if (_blockingTimeoutAt>=0 && !isAsync()) - _blockingTimeoutAt=System.currentTimeMillis()+getHttpChannelState().getHttpChannel().getHttpConfiguration().getBlockingTimeout(); + if (!isAsync()) + { + if (_blockUntil == 0) + { + long blockingTimeout = getBlockingTimeout(); + if (blockingTimeout > 0) + _blockUntil = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(blockingTimeout); + } + } - while(true) + long minRequestDataRate = _channelState.getHttpChannel().getHttpConfiguration().getMinRequestDataRate(); + if (minRequestDataRate > 0 && _firstByteTimeStamp != -1) + { + long period = System.nanoTime() - _firstByteTimeStamp; + if (period > 0) + { + long minimum_data = minRequestDataRate * TimeUnit.NANOSECONDS.toMillis(period) / TimeUnit.SECONDS.toMillis(1); + if (_contentArrived < minimum_data) + throw new BadMessageException(HttpStatus.REQUEST_TIMEOUT_408,String.format("Request data rate < %d B/s",minRequestDataRate)); + } + } + + while (true) { Content item = nextContent(); - if (item!=null) + if (item != null) { - int l = get(item, b, off, len); + int l = get(item,b,off,len); if (LOG.isDebugEnabled()) LOG.debug("{} read {} from {}",this,l,item); - consumeNonContent(); + // Consume any following poison pills + pollReadableContent(); return l; } @@ -164,208 +302,232 @@ public class HttpInput extends ServletInputStream implements Runnable } /** - * Called when derived implementations should attempt to - * produce more Content and add it via {@link #addContent(Content)}. - * For protocols that are constantly producing (eg HTTP2) this can - * be left as a noop; - * @throws IOException if unable to produce content + * Called when derived implementations should attempt to produce more Content and add it via {@link #addContent(Content)}. For protocols that are constantly + * producing (eg HTTP2) this can be left as a noop; + * + * @throws IOException + * if unable to produce content */ protected void produceContent() throws IOException { } /** - * Get the next content from the inputQ, calling {@link #produceContent()} - * if need be. EOF is processed and state changed. + * Get the next content from the inputQ, calling {@link #produceContent()} if need be. EOF is processed and state changed. * * @return the content or null if none available. - * @throws IOException if retrieving the content fails + * @throws IOException + * if retrieving the content fails */ protected Content nextContent() throws IOException { - Content content = pollContent(); - if (content==null && !isFinished()) + Content content = pollNonEmptyContent(); + if (content == null && !isFinished()) { produceContent(); - content = pollContent(); + content = pollNonEmptyContent(); } return content; } - /** Poll the inputQ for Content. - * Consumed buffers and {@link PoisonPillContent}s are removed and - * EOF state updated if need be. + /** + * Poll the inputQ for Content. Consumed buffers and {@link SentinelContent}s are removed and EOF state updated if need be. + * * @return Content or null */ - protected Content pollContent() + protected Content pollNonEmptyContent() { - // Items are removed only when they are fully consumed. - Content content = _inputQ.peek(); - // Skip consumed items at the head of the queue. - while (content != null && remaining(content) == 0) - { - _inputQ.poll(); - content.succeeded(); - if (LOG.isDebugEnabled()) - LOG.debug("{} consumed {}", this, content); - - if (content==EOF_CONTENT) + while (true) + { + // Get the next content (or EOF) + Content content = pollReadableContent(); + + // If it is EOF, consume it here + if (content instanceof SentinelContent) { - if (_listener==null) - _state=EOF; - else + if (content == EARLY_EOF_CONTENT) + _state = EARLY_EOF; + else if (content instanceof EofContent) { - _state=AEOF; - boolean woken = _channelState.onReadReady(); // force callback? - if (woken) - wake(); + if (_listener == null) + _state = EOF; + else + { + _state = AEOF; + boolean woken = _channelState.onReadReady(); // force callback? + if (woken) + wake(); + } } + + // Consume the EOF content, either if it was original content + // or if it was produced by interception + content.succeeded(); + if (_content==content) + _content = null; + else if (_intercepted==content) + _intercepted = null; + continue; } - else if (content==EARLY_EOF_CONTENT) - _state=EARLY_EOF; - content = _inputQ.peek(); + return content; } - - return content; + } /** + * Poll the inputQ for Content or EOF. Consumed buffers and non EOF {@link SentinelContent}s are removed. EOF state is not updated. + * Interception is done within this method. + * @return Content with remaining, a {@link SentinelContent}, or null */ - protected void consumeNonContent() + protected Content pollReadableContent() { - // Items are removed only when they are fully consumed. - Content content = _inputQ.peek(); - // Skip consumed items at the head of the queue. - while (content != null && remaining(content) == 0) + // If we have a chunk produced by interception + if (_intercepted!=null) { - // Defer EOF until read - if (content instanceof EofContent) - break; - - // Consume all other empty content - _inputQ.poll(); - content.succeeded(); - if (LOG.isDebugEnabled()) - LOG.debug("{} consumed {}", this, content); - content = _inputQ.peek(); + // Use it if it has any remaining content + if (_intercepted.hasContent()) + return _intercepted; + + // succeed the chunk + _intercepted.succeeded(); + _intercepted=null; } + + // If we don't have a Content under consideration, get + // the next one off the input Q. + if (_content == null) + _content = _inputQ.poll(); + + // While we have content to consider. + while (_content!=null) + { + // Are we intercepting? + if (_interceptor!=null) + { + // Intercept the current content (may be called several + // times for the same content + _intercepted = _interceptor.readFrom(_content); + + // If interception produced new content + if (_intercepted!=null && _intercepted!=_content) + { + // if it is not empty use it + if (_intercepted.hasContent()) + return _intercepted; + _intercepted.succeeded(); + } + + // intercepted content consumed + _intercepted=null; + + // fall through so that the unintercepted _content is + // considered for any remaining content, for EOF and to + // succeed it if it is entirely consumed. + } + + // If the content has content or is an EOF marker, use it + if (_content.hasContent() || _content instanceof SentinelContent) + return _content; + + // The content is consumed, so get the next one. Note that EOF + // content is never consumed here, but in #pollContent + _content.succeeded(); + _content = _inputQ.poll(); + } + + return null; + } + /** - * Get the next readable from the inputQ, calling {@link #produceContent()} - * if need be. EOF is NOT processed and state is not changed. + * Get the next readable from the inputQ, calling {@link #produceContent()} if need be. EOF is NOT processed and state is not changed. * * @return the content or EOF or null if none available. - * @throws IOException if retrieving the content fails + * @throws IOException + * if retrieving the content fails */ protected Content nextReadable() throws IOException { - Content content = pollReadable(); - if (content==null && !isFinished()) + Content content = pollReadableContent(); + if (content == null && !isFinished()) { produceContent(); - content = pollReadable(); + content = pollReadableContent(); } return content; } - /** Poll the inputQ for Content or EOF. - * Consumed buffers and non EOF {@link PoisonPillContent}s are removed. - * EOF state is not updated. - * @return Content, EOF or null - */ - protected Content pollReadable() - { - // Items are removed only when they are fully consumed. - Content content = _inputQ.peek(); - - // Skip consumed items at the head of the queue except EOF - while (content != null) - { - if (content==EOF_CONTENT || content==EARLY_EOF_CONTENT || remaining(content)>0) - return content; - - _inputQ.poll(); - content.succeeded(); - if (LOG.isDebugEnabled()) - LOG.debug("{} consumed {}", this, content); - content = _inputQ.peek(); - } - - return null; - } - - /** - * @param item the content - * @return how many bytes remain in the given content - */ - protected int remaining(Content item) - { - return item.remaining(); - } /** * Copies the given content into the given byte buffer. * - * @param content the content to copy from - * @param buffer the buffer to copy into - * @param offset the buffer offset to start copying from - * @param length the space available in the buffer + * @param content + * the content to copy from + * @param buffer + * the buffer to copy into + * @param offset + * the buffer offset to start copying from + * @param length + * the space available in the buffer * @return the number of bytes actually copied */ protected int get(Content content, byte[] buffer, int offset, int length) { - int l = Math.min(content.remaining(), length); - content.getContent().get(buffer, offset, l); - _contentConsumed+=l; + int l = content.get(buffer,offset,length); + _contentConsumed += l; return l; } /** - * Consumes the given content. - * Calls the content succeeded if all content consumed. + * Consumes the given content. Calls the content succeeded if all content consumed. * - * @param content the content to consume - * @param length the number of bytes to consume + * @param content + * the content to consume + * @param length + * the number of bytes to consume */ protected void skip(Content content, int length) { - int l = Math.min(content.remaining(), length); - ByteBuffer buffer = content.getContent(); - buffer.position(buffer.position()+l); - _contentConsumed+=l; - if (l>0 && !content.hasContent()) - pollContent(); // hungry succeed + int l = content.skip(length); + + _contentConsumed += l; + if (l > 0 && content.isEmpty()) + pollNonEmptyContent(); // hungry succeed } /** * Blocks until some content or some end-of-file event arrives. * - * @throws IOException if the wait is interrupted + * @throws IOException + * if the wait is interrupted */ protected void blockForContent() throws IOException { try { - long timeout=0; - if (_blockingTimeoutAt>=0) + long timeout = 0; + if (_blockUntil != 0) { - timeout=_blockingTimeoutAt-System.currentTimeMillis(); - if (timeout<=0) + timeout = TimeUnit.NANOSECONDS.toMillis(_blockUntil - System.nanoTime()); + if (timeout <= 0) throw new TimeoutException(); } if (LOG.isDebugEnabled()) - LOG.debug("{} blocking for content timeout={}", this,timeout); - if (timeout>0) + LOG.debug("{} blocking for content timeout={}",this,timeout); + if (timeout > 0) _inputQ.wait(timeout); else _inputQ.wait(); - if (_blockingTimeoutAt>0 && System.currentTimeMillis()>=_blockingTimeoutAt) - throw new TimeoutException(); + // TODO: cannot return unless there is content or timeout, + // TODO: so spurious wakeups are not handled correctly. + + if (_blockUntil != 0 && TimeUnit.NANOSECONDS.toMillis(_blockUntil - System.nanoTime()) <= 0) + throw new TimeoutException(String.format("Blocking timeout %d ms",getBlockingTimeout())); } catch (Throwable e) { @@ -375,52 +537,67 @@ public class HttpInput extends ServletInputStream implements Runnable /** * Adds some content to the start of this input stream. - *

    Typically used to push back content that has - * been read, perhaps mutated. The bytes prepended are - * deducted for the contentConsumed total

    - * @param item the content to add + *

    + * Typically used to push back content that has been read, perhaps mutated. The bytes prepended are deducted for the contentConsumed total + *

    + * + * @param item + * the content to add * @return true if content channel woken for read */ public boolean prependContent(Content item) { - boolean woken=false; + boolean woken = false; synchronized (_inputQ) { - _inputQ.push(item); - _contentConsumed-=item.remaining(); + if (_content != null) + _inputQ.push(_content); + _content = item; + _contentConsumed -= item.remaining(); if (LOG.isDebugEnabled()) - LOG.debug("{} prependContent {}", this, item); + LOG.debug("{} prependContent {}",this,item); - if (_listener==null) + if (_listener == null) _inputQ.notify(); else - woken=_channelState.onReadPossible(); + woken = _channelState.onReadPossible(); } - return woken; } /** * Adds some content to this input stream. * - * @param item the content to add + * @param content + * the content to add * @return true if content channel woken for read */ - public boolean addContent(Content item) + public boolean addContent(Content content) { - boolean woken=false; + boolean woken = false; synchronized (_inputQ) { - _inputQ.offer(item); - if (LOG.isDebugEnabled()) - LOG.debug("{} addContent {}", this, item); + if (_firstByteTimeStamp == -1) + _firstByteTimeStamp = System.nanoTime(); - if (_listener==null) - _inputQ.notify(); + _contentArrived += content.remaining(); + + if (_content==null && _inputQ.isEmpty()) + _content=content; else - woken=_channelState.onReadPossible(); - } + _inputQ.offer(content); + + if (LOG.isDebugEnabled()) + LOG.debug("{} addContent {}",this,content); + if (pollReadableContent()!=null) + { + if (_listener == null) + _inputQ.notify(); + else + woken = _channelState.onReadPossible(); + } + } return woken; } @@ -428,7 +605,7 @@ public class HttpInput extends ServletInputStream implements Runnable { synchronized (_inputQ) { - return _inputQ.size()>0; + return _content!=null || _inputQ.size() > 0; } } @@ -449,11 +626,10 @@ public class HttpInput extends ServletInputStream implements Runnable } /** - * This method should be called to signal that an EOF has been - * detected before all the expected content arrived. + * This method should be called to signal that an EOF has been detected before all the expected content arrived. *

    - * Typically this will result in an EOFException being thrown - * from a subsequent read rather than a -1 return. + * Typically this will result in an EOFException being thrown from a subsequent read rather than a -1 return. + * * @return true if content channel woken for read */ public boolean earlyEOF() @@ -462,13 +638,13 @@ public class HttpInput extends ServletInputStream implements Runnable } /** - * This method should be called to signal that all the expected - * content arrived. + * This method should be called to signal that all the expected content arrived. + * * @return true if content channel woken for read */ public boolean eof() { - return addContent(EOF_CONTENT); + return addContent(EOF_CONTENT); } public boolean consumeAll() @@ -483,7 +659,7 @@ public class HttpInput extends ServletInputStream implements Runnable if (item == null) break; // Let's not bother blocking - skip(item, remaining(item)); + skip(item,item.remaining()); } return isFinished() && !isError(); } @@ -507,7 +683,7 @@ public class HttpInput extends ServletInputStream implements Runnable { synchronized (_inputQ) { - return _state==ASYNC; + return _state == ASYNC; } } @@ -520,7 +696,6 @@ public class HttpInput extends ServletInputStream implements Runnable } } - @Override public boolean isReady() { @@ -528,18 +703,18 @@ public class HttpInput extends ServletInputStream implements Runnable { synchronized (_inputQ) { - if (_listener == null ) + if (_listener == null) return true; if (_state instanceof EOFState) return true; - if (nextReadable()!=null) + if (nextReadable() != null) return true; _channelState.onReadUnready(); } return false; } - catch(IOException e) + catch (IOException e) { LOG.ignore(e); return true; @@ -550,7 +725,7 @@ public class HttpInput extends ServletInputStream implements Runnable public void setReadListener(ReadListener readListener) { readListener = Objects.requireNonNull(readListener); - boolean woken=false; + boolean woken = false; try { synchronized (_inputQ) @@ -558,11 +733,11 @@ public class HttpInput extends ServletInputStream implements Runnable if (_listener != null) throw new IllegalStateException("ReadListener already set"); if (_state != STREAM) - throw new IllegalStateException("State "+STREAM+" != " + _state); + throw new IllegalStateException("State " + STREAM + " != " + _state); _state = ASYNC; _listener = readListener; - boolean content=nextContent()!=null; + boolean content = nextContent() != null; if (content) woken = _channelState.onReadReady(); @@ -570,7 +745,7 @@ public class HttpInput extends ServletInputStream implements Runnable _channelState.onReadUnready(); } } - catch(IOException e) + catch (IOException e) { throw new RuntimeIOException(e); } @@ -581,7 +756,7 @@ public class HttpInput extends ServletInputStream implements Runnable public boolean failed(Throwable x) { - boolean woken=false; + boolean woken = false; synchronized (_inputQ) { if (_state instanceof ErrorState) @@ -589,39 +764,35 @@ public class HttpInput extends ServletInputStream implements Runnable else _state = new ErrorState(x); - if (_listener==null) + if (_listener == null) _inputQ.notify(); else - woken=_channelState.onReadPossible(); + woken = _channelState.onReadPossible(); } return woken; } - /* ------------------------------------------------------------ */ /* - *

    - * While this class is-a Runnable, it should never be dispatched in it's own thread. It is a - * runnable only so that the calling thread can use {@link ContextHandler#handle(Runnable)} - * to setup classloaders etc. - *

    + *

    While this class is-a Runnable, it should never be dispatched in it's own thread. It is a runnable only so that the calling thread can use {@link + * ContextHandler#handle(Runnable)} to setup classloaders etc.

    */ @Override public void run() { final Throwable error; final ReadListener listener; - boolean aeof=false; + boolean aeof = false; synchronized (_inputQ) { - if (_state==EOF) + if (_state == EOF) return; - if (_state==AEOF) + if (_state == AEOF) { - _state=EOF; - aeof=true; + _state = EOF; + aeof = true; } listener = _listener; @@ -630,7 +801,7 @@ public class HttpInput extends ServletInputStream implements Runnable try { - if (error!=null) + if (error != null) { _channelState.getHttpChannel().getResponse().getHttpFields().add(HttpConnection.CONNECTION_CLOSE); listener.onError(error); @@ -650,7 +821,7 @@ public class HttpInput extends ServletInputStream implements Runnable LOG.debug(e); try { - if (aeof || error==null) + if (aeof || error == null) { _channelState.getHttpChannel().getResponse().getHttpFields().add(HttpConnection.CONNECTION_CLOSE); listener.onError(e); @@ -674,27 +845,33 @@ public class HttpInput extends ServletInputStream implements Runnable Content content; synchronized (_inputQ) { - state=_state; - consumed=_contentConsumed; - q=_inputQ.size(); - content=_inputQ.peekFirst(); + state = _state; + consumed = _contentConsumed; + q = _inputQ.size(); + content = _inputQ.peekFirst(); } return String.format("%s@%x[c=%d,q=%d,[0]=%s,s=%s]", - getClass().getSimpleName(), - hashCode(), - consumed, - q, - content, - state); + getClass().getSimpleName(), + hashCode(), + consumed, + q, + content, + state); } - public static class PoisonPillContent extends Content + /** + * A Sentinel Content, which has zero length content but + * indicates some other event in the input stream (eg EOF) + * + */ + public static class SentinelContent extends Content { private final String _name; - public PoisonPillContent(String name) + + public SentinelContent(String name) { super(BufferUtil.EMPTY_BUFFER); - _name=name; + _name = name; } @Override @@ -704,7 +881,7 @@ public class HttpInput extends ServletInputStream implements Runnable } } - public static class EofContent extends PoisonPillContent + public static class EofContent extends SentinelContent { EofContent(String name) { @@ -714,22 +891,36 @@ public class HttpInput extends ServletInputStream implements Runnable public static class Content implements Callback { - private final ByteBuffer _content; + protected final ByteBuffer _content; public Content(ByteBuffer content) { - _content=content; + _content = content; } + public ByteBuffer getByteBuffer() + { + return _content; + } + @Override public InvocationType getInvocationType() { return InvocationType.NON_BLOCKING; } - public ByteBuffer getContent() + public int get(byte[] buffer, int offset, int length) { - return _content; + length = Math.min(_content.remaining(),length); + _content.get(buffer,offset,length); + return length; + } + + public int skip(int length) + { + length = Math.min(_content.remaining(),length); + _content.position(_content.position() + length); + return length; } public boolean hasContent() @@ -741,6 +932,11 @@ public class HttpInput extends ServletInputStream implements Runnable { return _content.remaining(); } + + public boolean isEmpty() + { + return !_content.hasRemaining(); + } @Override public String toString() @@ -749,7 +945,6 @@ public class HttpInput extends ServletInputStream implements Runnable } } - protected static abstract class State { public boolean blockForContent(HttpInput in) throws IOException @@ -770,9 +965,10 @@ public class HttpInput extends ServletInputStream implements Runnable protected class ErrorState extends EOFState { final Throwable _error; + ErrorState(Throwable error) { - _error=error; + _error = error; } public Throwable getError() @@ -791,7 +987,7 @@ public class HttpInput extends ServletInputStream implements Runnable @Override public String toString() { - return "ERROR:"+_error; + return "ERROR:" + _error; } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java index 695c43d3db7..9d1ec89924b 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java @@ -54,75 +54,78 @@ import org.eclipse.jetty.util.log.Logger; * close the stream, to be reopened after the inclusion ends.

    */ public class HttpOutput extends ServletOutputStream implements Runnable -{ - +{ /** - * The HttpOutput.Inteceptor is a single intercept point for all - * output written to the HttpOutput: via writer; via output stream; + * The HttpOutput.Interceptor is a single intercept point for all + * output written to the HttpOutput: via writer; via output stream; * asynchronously; or blocking. *

    - * The Interceptor can be used to implement translations (eg Gzip) or - * additional buffering that acts on all output. Interceptors are + * The Interceptor can be used to implement translations (eg Gzip) or + * additional buffering that acts on all output. Interceptors are * created in a chain, so that multiple concerns may intercept. *

    - * The {@link HttpChannel} is an {@link Interceptor} and is always the + * The {@link HttpChannel} is an {@link Interceptor} and is always the * last link in any Interceptor chain. *

    - * Responses are committed by the first call to + * Responses are committed by the first call to * {@link #write(ByteBuffer, boolean, Callback)} - * and closed by a call to {@link #write(ByteBuffer, boolean, Callback)} - * with the last boolean set true. If no content is available to commit + * and closed by a call to {@link #write(ByteBuffer, boolean, Callback)} + * with the last boolean set true. If no content is available to commit * or close, then a null buffer is passed. */ public interface Interceptor { - /** + /** * Write content. * The response is committed by the first call to write and is closed by - * a call with last == true. Empty content buffers may be passed to + * a call with last == true. Empty content buffers may be passed to * force a commit or close. - * @param content The content to be written or an empty buffer. - * @param last True if this is the last call to write - * @param callback The callback to use to indicate {@link Callback#succeeded()} - * or {@link Callback#failed(Throwable)}. + * + * @param content The content to be written or an empty buffer. + * @param last True if this is the last call to write + * @param callback The callback to use to indicate {@link Callback#succeeded()} + * or {@link Callback#failed(Throwable)}. */ void write(ByteBuffer content, boolean last, Callback callback); - + /** - * @return The next Interceptor in the chain or null if this is the + * @return The next Interceptor in the chain or null if this is the * last Interceptor in the chain. */ Interceptor getNextInterceptor(); - + /** - * @return True if the Interceptor is optimized to receive direct + * @return True if the Interceptor is optimized to receive direct * {@link ByteBuffer}s in the {@link #write(ByteBuffer, boolean, Callback)} - * method. If false is returned, then passing direct buffers may cause + * method. If false is returned, then passing direct buffers may cause * inefficiencies. */ boolean isOptimizedForDirectBuffers(); - + /** * Reset the buffers. *

    If the Interceptor contains buffers then reset them. - * @throws IllegalStateException Thrown if the response has been - * committed and buffers and/or headers cannot be reset. + * + * @throws IllegalStateException Thrown if the response has been + * committed and buffers and/or headers cannot be reset. */ default void resetBuffer() throws IllegalStateException { Interceptor next = getNextInterceptor(); - if (next!=null) + if (next != null) next.resetBuffer(); - }; + } } private static Logger LOG = Log.getLogger(HttpOutput.class); private final HttpChannel _channel; - private final SharedBlockingCallback _writeBlock; + private final SharedBlockingCallback _writeBlocker; private Interceptor _interceptor; - /** Bytes written via the write API (excludes bytes written via sendContent). Used to autocommit once content length is written. */ + /** + * Bytes written via the write API (excludes bytes written via sendContent). Used to autocommit once content length is written. + */ private long _written; private ByteBuffer _aggregate; @@ -140,33 +143,25 @@ public class HttpOutput extends ServletOutputStream implements Runnable isReady() OPEN:true READY:true READY:true UNREADY:false UNREADY:false CLOSED:true write completed - - - ASYNC READY->owp - */ - private enum OutputState { OPEN, ASYNC, READY, PENDING, UNREADY, ERROR, CLOSED } - private final AtomicReference _state=new AtomicReference<>(OutputState.OPEN); + private enum OutputState + { + OPEN, ASYNC, READY, PENDING, UNREADY, ERROR, CLOSED + } + + private final AtomicReference _state = new AtomicReference<>(OutputState.OPEN); public HttpOutput(HttpChannel channel) { _channel = channel; _interceptor = channel; - _writeBlock = new SharedBlockingCallback() - { - @Override - protected long getIdleTimeout() - { - long bto = getHttpChannel().getHttpConfiguration().getBlockingTimeout(); - if (bto>0) - return bto; - if (bto<0) - return -1; - return _channel.getIdleTimeout(); - } - }; + _writeBlocker = new WriteBlocker(channel); HttpConfiguration config = channel.getHttpConfiguration(); _bufferSize = config.getOutputBufferSize(); _commitSize = config.getOutputAggregationSize(); - if (_commitSize>_bufferSize) + if (_commitSize > _bufferSize) { - LOG.warn("OutputAggregationSize {} exceeds bufferSize {}",_commitSize,_bufferSize); - _commitSize=_bufferSize; + LOG.warn("OutputAggregationSize {} exceeds bufferSize {}", _commitSize, _bufferSize); + _commitSize = _bufferSize; } } @@ -180,9 +175,9 @@ public class HttpOutput extends ServletOutputStream implements Runnable return _interceptor; } - public void setInterceptor(Interceptor filter) + public void setInterceptor(Interceptor interceptor) { - _interceptor=filter; + _interceptor = interceptor; } public boolean isWritten() @@ -202,7 +197,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable private boolean isLastContentToWrite(int len) { - _written+=len; + _written += len; return _channel.getResponse().isAllContentWritten(_written); } @@ -213,12 +208,12 @@ public class HttpOutput extends ServletOutputStream implements Runnable protected Blocker acquireWriteBlockingCallback() throws IOException { - return _writeBlock.acquire(); + return _writeBlocker.acquire(); } private void write(ByteBuffer content, boolean complete) throws IOException { - try (Blocker blocker = _writeBlock.acquire()) + try (Blocker blocker = _writeBlocker.acquire()) { write(content, complete, blocker); blocker.block(); @@ -250,14 +245,13 @@ public class HttpOutput extends ServletOutputStream implements Runnable { while(true) { - OutputState state=_state.get(); + OutputState state = _state.get(); switch (state) { case CLOSED: { return; } - case ASYNC: { // A close call implies a write operation, thus in asynchronous mode @@ -269,7 +263,6 @@ public class HttpOutput extends ServletOutputStream implements Runnable continue; break; } - case UNREADY: case PENDING: { @@ -279,7 +272,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable // complete is called. Because the prior write has not yet completed // and/or isReady has not been called, this close is allowed, but will // abort the response. - if (!_state.compareAndSet(state,OutputState.CLOSED)) + if (!_state.compareAndSet(state, OutputState.CLOSED)) continue; IOException ex = new IOException("Closed while Pending/Unready"); LOG.warn(ex.toString()); @@ -287,17 +280,16 @@ public class HttpOutput extends ServletOutputStream implements Runnable _channel.abort(ex); return; } - default: { - if (!_state.compareAndSet(state,OutputState.CLOSED)) + if (!_state.compareAndSet(state, OutputState.CLOSED)) continue; // Do a normal close by writing the aggregate buffer or an empty buffer. If we are // not including, then indicate this is the last write. try { - write(BufferUtil.hasContent(_aggregate)?_aggregate:BufferUtil.EMPTY_BUFFER, !_channel.getResponse().isIncluding()); + write(BufferUtil.hasContent(_aggregate) ? _aggregate : BufferUtil.EMPTY_BUFFER, !_channel.getResponse().isIncluding()); } catch (IOException x) { @@ -320,9 +312,9 @@ public class HttpOutput extends ServletOutputStream implements Runnable */ void closed() { - while(true) + while (true) { - OutputState state=_state.get(); + OutputState state = _state.get(); switch (state) { case CLOSED: @@ -331,8 +323,8 @@ public class HttpOutput extends ServletOutputStream implements Runnable } case UNREADY: { - if (_state.compareAndSet(state,OutputState.ERROR)) - _writeListener.onError(_onError==null?new EofException("Async closed"):_onError); + if (_state.compareAndSet(state, OutputState.ERROR)) + _writeListener.onError(_onError == null ? new EofException("Async closed") : _onError); break; } default: @@ -372,12 +364,12 @@ public class HttpOutput extends ServletOutputStream implements Runnable public boolean isClosed() { - return _state.get()==OutputState.CLOSED; - } + return _state.get() == OutputState.CLOSED; + } public boolean isAsync() { - switch(_state.get()) + switch (_state.get()) { case ASYNC: case READY: @@ -388,16 +380,16 @@ public class HttpOutput extends ServletOutputStream implements Runnable return false; } } - + @Override public void flush() throws IOException { - while(true) + while (true) { - switch(_state.get()) + switch (_state.get()) { case OPEN: - write(BufferUtil.hasContent(_aggregate)?_aggregate:BufferUtil.EMPTY_BUFFER, false); + write(BufferUtil.hasContent(_aggregate) ? _aggregate : BufferUtil.EMPTY_BUFFER, false); return; case ASYNC: @@ -431,9 +423,9 @@ public class HttpOutput extends ServletOutputStream implements Runnable public void write(byte[] b, int off, int len) throws IOException { // Async or Blocking ? - while(true) + while (true) { - switch(_state.get()) + switch (_state.get()) { case OPEN: // process blocking below @@ -448,7 +440,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable // Should we aggregate? boolean last = isLastContentToWrite(len); - if (!last && len<=_commitSize) + if (!last && len <= _commitSize) { if (_aggregate == null) _aggregate = _channel.getByteBufferPool().acquire(getBufferSize(), _interceptor.isOptimizedForDirectBuffers()); @@ -457,7 +449,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable int filled = BufferUtil.fill(_aggregate, b, off, len); // return if we are not complete, not full and filled all the content - if (filled==len && !BufferUtil.isFull(_aggregate)) + if (filled == len && !BufferUtil.isFull(_aggregate)) { if (!_state.compareAndSet(OutputState.PENDING, OutputState.ASYNC)) throw new IllegalStateException(); @@ -465,12 +457,12 @@ public class HttpOutput extends ServletOutputStream implements Runnable } // adjust offset/length - off+=filled; - len-=filled; + off += filled; + len -= filled; } // Do the asynchronous writing from the callback - new AsyncWrite(b,off,len,last).iterate(); + new AsyncWrite(b, off, len, last).iterate(); return; case PENDING: @@ -494,7 +486,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable // Should we aggregate? int capacity = getBufferSize(); boolean last = isLastContentToWrite(len); - if (!last && len<=_commitSize) + if (!last && len <= _commitSize) { if (_aggregate == null) _aggregate = _channel.getByteBufferPool().acquire(capacity, _interceptor.isOptimizedForDirectBuffers()); @@ -503,21 +495,21 @@ public class HttpOutput extends ServletOutputStream implements Runnable int filled = BufferUtil.fill(_aggregate, b, off, len); // return if we are not complete, not full and filled all the content - if (filled==len && !BufferUtil.isFull(_aggregate)) + if (filled == len && !BufferUtil.isFull(_aggregate)) return; // adjust offset/length - off+=filled; - len-=filled; + off += filled; + len -= filled; } // flush any content from the aggregate if (BufferUtil.hasContent(_aggregate)) { - write(_aggregate, last && len==0); + write(_aggregate, last && len == 0); // should we fill aggregate again from the buffer? - if (len>0 && !last && len<=_commitSize && len<=BufferUtil.space(_aggregate)) + if (len > 0 && !last && len <= _commitSize && len <= BufferUtil.space(_aggregate)) { BufferUtil.append(_aggregate, b, off, len); return; @@ -525,26 +517,26 @@ public class HttpOutput extends ServletOutputStream implements Runnable } // write any remaining content in the buffer directly - if (len>0) + if (len > 0) { // write a buffer capacity at a time to avoid JVM pooling large direct buffers // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6210541 ByteBuffer view = ByteBuffer.wrap(b, off, len); - while (len>getBufferSize()) + while (len > getBufferSize()) { - int p=view.position(); - int l=p+getBufferSize(); - view.limit(p+getBufferSize()); - write(view,false); - len-=getBufferSize(); - view.limit(l+Math.min(len,getBufferSize())); + int p = view.position(); + int l = p + getBufferSize(); + view.limit(p + getBufferSize()); + write(view, false); + len -= getBufferSize(); + view.limit(l + Math.min(len, getBufferSize())); view.position(l); } - write(view,last); + write(view, last); } else if (last) { - write(BufferUtil.EMPTY_BUFFER,true); + write(BufferUtil.EMPTY_BUFFER, true); } if (last) @@ -554,9 +546,9 @@ public class HttpOutput extends ServletOutputStream implements Runnable public void write(ByteBuffer buffer) throws IOException { // Async or Blocking ? - while(true) + while (true) { - switch(_state.get()) + switch (_state.get()) { case OPEN: // process blocking below @@ -571,7 +563,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable // Do the asynchronous writing from the callback boolean last = isLastContentToWrite(buffer.remaining()); - new AsyncWrite(buffer,last).iterate(); + new AsyncWrite(buffer, last).iterate(); return; case PENDING: @@ -590,17 +582,16 @@ public class HttpOutput extends ServletOutputStream implements Runnable break; } - // handle blocking write - int len=BufferUtil.length(buffer); + int len = BufferUtil.length(buffer); boolean last = isLastContentToWrite(len); // flush any content from the aggregate if (BufferUtil.hasContent(_aggregate)) - write(_aggregate, last && len==0); + write(_aggregate, last && len == 0); // write any remaining content in the buffer directly - if (len>0) + if (len > 0) write(buffer, last); else if (last) write(BufferUtil.EMPTY_BUFFER, true); @@ -612,13 +603,13 @@ public class HttpOutput extends ServletOutputStream implements Runnable @Override public void write(int b) throws IOException { - _written+=1; - boolean complete=_channel.getResponse().isAllContentWritten(_written); + _written += 1; + boolean complete = _channel.getResponse().isAllContentWritten(_written); // Async or Blocking ? - while(true) + while (true) { - switch(_state.get()) + switch (_state.get()) { case OPEN: if (_aggregate == null) @@ -692,7 +683,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable public void sendContent(ByteBuffer content) throws IOException { if (LOG.isDebugEnabled()) - LOG.debug("sendContent({})",BufferUtil.toDetailString(content)); + LOG.debug("sendContent({})", BufferUtil.toDetailString(content)); write(content, true); closed(); @@ -706,7 +697,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable */ public void sendContent(InputStream in) throws IOException { - try(Blocker blocker = _writeBlock.acquire()) + try (Blocker blocker = _writeBlocker.acquire()) { new InputStreamWritingCB(in, blocker).iterate(); blocker.block(); @@ -728,7 +719,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable */ public void sendContent(ReadableByteChannel in) throws IOException { - try(Blocker blocker = _writeBlock.acquire()) + try (Blocker blocker = _writeBlocker.acquire()) { new ReadableByteChannelWritingCB(in, blocker).iterate(); blocker.block(); @@ -750,7 +741,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable */ public void sendContent(HttpContent content) throws IOException { - try(Blocker blocker = _writeBlock.acquire()) + try (Blocker blocker = _writeBlocker.acquire()) { sendContent(content, blocker); blocker.block(); @@ -766,13 +757,14 @@ public class HttpOutput extends ServletOutputStream implements Runnable /** * Asynchronous send of whole content. - * @param content The whole content to send + * + * @param content The whole content to send * @param callback The callback to use to notify success or failure */ public void sendContent(ByteBuffer content, final Callback callback) { if (LOG.isDebugEnabled()) - LOG.debug("sendContent(buffer={},{})",BufferUtil.toDetailString(content),callback); + LOG.debug("sendContent(buffer={},{})", BufferUtil.toDetailString(content), callback); write(content, true, new Callback.Nested(callback) { @@ -796,13 +788,13 @@ public class HttpOutput extends ServletOutputStream implements Runnable * Asynchronous send of stream content. * The stream will be closed after reading all content. * - * @param in The stream content to send + * @param in The stream content to send * @param callback The callback to use to notify success or failure */ public void sendContent(InputStream in, Callback callback) { if (LOG.isDebugEnabled()) - LOG.debug("sendContent(stream={},{})",in,callback); + LOG.debug("sendContent(stream={},{})", in, callback); new InputStreamWritingCB(in, callback).iterate(); } @@ -811,13 +803,13 @@ public class HttpOutput extends ServletOutputStream implements Runnable * Asynchronous send of channel content. * The channel will be closed after reading all content. * - * @param in The channel content to send + * @param in The channel content to send * @param callback The callback to use to notify success or failure */ public void sendContent(ReadableByteChannel in, Callback callback) { if (LOG.isDebugEnabled()) - LOG.debug("sendContent(channel={},{})",in,callback); + LOG.debug("sendContent(channel={},{})", in, callback); new ReadableByteChannelWritingCB(in, callback).iterate(); } @@ -826,12 +818,12 @@ public class HttpOutput extends ServletOutputStream implements Runnable * Asynchronous send of HTTP content. * * @param httpContent The HTTP content to send - * @param callback The callback to use to notify success or failure + * @param callback The callback to use to notify success or failure */ public void sendContent(HttpContent httpContent, Callback callback) { if (LOG.isDebugEnabled()) - LOG.debug("sendContent(http={},{})",httpContent,callback); + LOG.debug("sendContent(http={},{})", httpContent, callback); if (BufferUtil.hasContent(_aggregate)) { @@ -846,7 +838,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable while (true) { - switch(_state.get()) + switch (_state.get()) { case OPEN: if (!_state.compareAndSet(OutputState.OPEN, OutputState.PENDING)) @@ -867,37 +859,36 @@ public class HttpOutput extends ServletOutputStream implements Runnable break; } - ByteBuffer buffer = _channel.useDirectBuffers() ? httpContent.getDirectBuffer() : null; if (buffer == null) buffer = httpContent.getIndirectBuffer(); - if (buffer!=null) + if (buffer != null) { - sendContent(buffer,callback); + sendContent(buffer, callback); return; } try { - ReadableByteChannel rbc=httpContent.getReadableByteChannel(); - if (rbc!=null) + ReadableByteChannel rbc = httpContent.getReadableByteChannel(); + if (rbc != null) { // Close of the rbc is done by the async sendContent - sendContent(rbc,callback); + sendContent(rbc, callback); return; } InputStream in = httpContent.getInputStream(); - if (in!=null) + if (in != null) { - sendContent(in,callback); + sendContent(in, callback); return; } - throw new IllegalArgumentException("unknown content for "+httpContent); + throw new IllegalArgumentException("unknown content for " + httpContent); } - catch(Throwable th) + catch (Throwable th) { abort(th); callback.failed(th); @@ -917,9 +908,13 @@ public class HttpOutput extends ServletOutputStream implements Runnable public void recycle() { - _interceptor=_channel; - if (BufferUtil.hasContent(_aggregate)) - BufferUtil.clear(_aggregate); + _interceptor = _channel; + HttpConfiguration config = _channel.getHttpConfiguration(); + _bufferSize = config.getOutputBufferSize(); + _commitSize = config.getOutputAggregationSize(); + if (_commitSize > _bufferSize) + _commitSize = _bufferSize; + releaseBuffer(); _written = 0; reopen(); } @@ -949,15 +944,12 @@ public class HttpOutput extends ServletOutputStream implements Runnable throw new IllegalStateException(); } - /** - * @see javax.servlet.ServletOutputStream#isReady() - */ @Override public boolean isReady() { while (true) { - switch(_state.get()) + switch (_state.get()) { case OPEN: return true; @@ -993,31 +985,31 @@ public class HttpOutput extends ServletOutputStream implements Runnable @Override public void run() { - loop: while (true) + while (true) { OutputState state = _state.get(); - if(_onError!=null) + if (_onError != null) { - switch(state) + switch (state) { case CLOSED: case ERROR: { - _onError=null; - break loop; + _onError = null; + return; } default: { if (_state.compareAndSet(state, OutputState.ERROR)) { - Throwable th=_onError; - _onError=null; + Throwable th = _onError; + _onError = null; if (LOG.isDebugEnabled()) - LOG.debug("onError",th); + LOG.debug("onError", th); _writeListener.onError(th); close(); - break loop; + return; } } } @@ -1042,7 +1034,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable try { _writeListener.onWritePossible(); - break loop; + break; } catch (Throwable e) { @@ -1066,25 +1058,25 @@ public class HttpOutput extends ServletOutputStream implements Runnable @Override public String toString() { - return String.format("%s@%x{%s}",this.getClass().getSimpleName(),hashCode(),_state.get()); + return String.format("%s@%x{%s}", this.getClass().getSimpleName(), hashCode(), _state.get()); } private abstract class AsyncICB extends IteratingCallback { final boolean _last; - + AsyncICB(boolean last) { - _last=last; + _last = last; } - + @Override protected void onCompleteSuccess() { - while(true) + while (true) { - OutputState last=_state.get(); - switch(last) + OutputState last = _state.get(); + switch (last) { case PENDING: if (!_state.compareAndSet(OutputState.PENDING, OutputState.ASYNC)) @@ -1113,7 +1105,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable @Override public void onCompleteFailure(Throwable e) { - _onError=e==null?new IOException():e; + _onError = e == null ? new IOException() : e; if (_channel.getState().onWritePossible()) _channel.execute(_channel); } @@ -1133,15 +1125,15 @@ public class HttpOutput extends ServletOutputStream implements Runnable { if (BufferUtil.hasContent(_aggregate)) { - _flushed=true; + _flushed = true; write(_aggregate, false, this); return Action.SCHEDULED; } if (!_flushed) { - _flushed=true; - write(BufferUtil.EMPTY_BUFFER,false,this); + _flushed = true; + write(BufferUtil.EMPTY_BUFFER, false, this); return Action.SCHEDULED; } @@ -1159,23 +1151,23 @@ public class HttpOutput extends ServletOutputStream implements Runnable public AsyncWrite(byte[] b, int off, int len, boolean last) { super(last); - _buffer=ByteBuffer.wrap(b, off, len); - _len=len; + _buffer = ByteBuffer.wrap(b, off, len); + _len = len; // always use a view for large byte arrays to avoid JVM pooling large direct buffers - _slice=_len _initParams; private ClassLoader _classLoader; private String _contextPath = "/"; + private String _contextPathEncoded = "/"; private String _displayName; @@ -507,7 +506,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu /* ------------------------------------------------------------ */ /** - * @return Returns the _contextPath. + * @return Returns the contextPath. */ @ManagedAttribute("True if URLs are compacted to replace the multiple '/'s with a single '/'") public String getContextPath() @@ -515,6 +514,15 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu return _contextPath; } + /* ------------------------------------------------------------ */ + /** + * @return Returns the encoded contextPath. + */ + public String getContextPathEncoded() + { + return _contextPathEncoded; + } + /* ------------------------------------------------------------ */ /* * @see javax.servlet.ServletContext#getInitParameter(java.lang.String) @@ -1108,7 +1116,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu if (_contextPath.length() == 1) baseRequest.setContextPath(""); else - baseRequest.setContextPath(_contextPath); + baseRequest.setContextPath(_contextPathEncoded); baseRequest.setServletPath(null); baseRequest.setPathInfo(pathInfo); } @@ -1485,6 +1493,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu } _contextPath = contextPath; + _contextPathEncoded = URIUtil.encodePath(contextPath); if (getServer() != null && (getServer().isStarting() || getServer().isStarted())) { @@ -2074,6 +2083,8 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu @Override public RequestDispatcher getRequestDispatcher(String uriInContext) { + // uriInContext is encoded, potentially with query + if (uriInContext == null) return null; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IPAccessHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IPAccessHandler.java index ffca1ac7918..ef52fdd3233 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IPAccessHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IPAccessHandler.java @@ -100,6 +100,8 @@ import org.eclipse.jetty.util.log.Logger; * to define a range of the internet addresses (e.g. 127., 10.10., 172.16.1.). * They also used the first "/" character of the URI pattern to separate it from the * internet address. Both of these features have been deprecated in the current version. + * @deprecated + * @see InetAccessHandler */ public class IPAccessHandler extends HandlerWrapper { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/InetAccessHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/InetAccessHandler.java new file mode 100644 index 00000000000..d642ef0206a --- /dev/null +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/InetAccessHandler.java @@ -0,0 +1,156 @@ +// +// ======================================================================== +// Copyright (c) 1995-2016 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.server.handler; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.server.HttpChannel; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.util.IncludeExcludeSet; +import org.eclipse.jetty.util.InetAddressSet; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + + +/** + * Inet Address Access Handler + *

    + * Controls access to the wrapped handler by the real remote IP. Control is provided + * by and {@link IncludeExcludeSet} over a {@link InetAddressSet}. This handler + * uses the real internet address of the connection, not one reported in the forwarded + * for headers, as this cannot be as easily forged. + *

    + + */ +public class InetAccessHandler extends HandlerWrapper +{ + private static final Logger LOG = Log.getLogger(InetAccessHandler.class); + IncludeExcludeSet _set = new IncludeExcludeSet<>(InetAddressSet.class); + + /* ------------------------------------------------------------ */ + /** + * Creates new handler object + */ + public InetAccessHandler() + { + super(); + } + + /* ------------------------------------------------------------ */ + /** + * Include a InetAddress pattern + * @see InetAddressSet + * @param pattern InetAddress pattern to exclude + */ + public void include(String pattern) + { + _set.include(pattern); + } + + /* ------------------------------------------------------------ */ + /** + * Include a InetAddress pattern + * @see InetAddressSet + * @param patterns InetAddress patterns to exclude + */ + public void include(String... patterns) + { + _set.include(patterns); + } + + /* ------------------------------------------------------------ */ + /** + * Exclude a InetAddress pattern + * @see InetAddressSet + * @param pattern InetAddress pattern to exclude + */ + public void exclude(String pattern) + { + _set.exclude(pattern); + } + + /* ------------------------------------------------------------ */ + /** + * Include a InetAddress pattern + * @see InetAddressSet + * @param patterns InetAddress patterns to exclude + */ + public void exclude(String... patterns) + { + _set.exclude(patterns); + } + + + /* ------------------------------------------------------------ */ + /** + * Checks the incoming request against the whitelist and blacklist + * + * @see org.eclipse.jetty.server.handler.HandlerWrapper#handle(java.lang.String, org.eclipse.jetty.server.Request, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + */ + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + // Get the real remote IP (not the one set by the forwarded headers (which may be forged)) + HttpChannel channel = baseRequest.getHttpChannel(); + if (channel!=null) + { + EndPoint endp=channel.getEndPoint(); + if (endp!=null) + { + InetSocketAddress address = endp.getRemoteAddress(); + if (address!=null && !isAllowed(address.getAddress())) + { + response.sendError(HttpStatus.FORBIDDEN_403); + baseRequest.setHandled(true); + return; + } + } + } + + getHandler().handle(target,baseRequest, request, response); + } + + /* ------------------------------------------------------------ */ + /** + * Check if specified request is allowed by current IPAccess rules. + * + * @param address internet address + * @return true if address is allowed + * + */ + protected boolean isAllowed(InetAddress address) + { + return _set.test(address); + } + + /* ------------------------------------------------------------ */ + @Override + public void dump(Appendable out, String indent) throws IOException + { + dumpBeans(out,indent,_set.getIncluded(),_set.getExcluded()); + } + } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ThreadLimitHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ThreadLimitHandler.java new file mode 100644 index 00000000000..9684845e331 --- /dev/null +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ThreadLimitHandler.java @@ -0,0 +1,440 @@ +// +// ======================================================================== +// Copyright (c) 1995-2016 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.server.handler; + +import java.io.Closeable; +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ExecutionException; + +import javax.servlet.AsyncContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.http.HostPortHttpField; +import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.http.QuotedCSV; +import org.eclipse.jetty.server.ForwardedRequestCustomizer; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.util.IncludeExcludeSet; +import org.eclipse.jetty.util.InetAddressSet; +import org.eclipse.jetty.util.StringUtil; +import org.eclipse.jetty.util.annotation.ManagedAttribute; +import org.eclipse.jetty.util.annotation.ManagedOperation; +import org.eclipse.jetty.util.annotation.Name; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.thread.Locker; + + +/** + *

    Handler to limit the threads per IP address for DOS protection

    + *

    The ThreadLimitHandler applies a limit to the number of Threads + * that can be used simultaneously per remote IP address. + *

    + *

    The handler makes a determination of the remote IP separately to + * any that may be made by the {@link ForwardedRequestCustomizer} or similar: + *

      + *
    • This handler will use either only a single style + * of forwarded header. This is on the assumption that a trusted local proxy + * will produce only a single forwarded header and that any additional + * headers are likely from untrusted client side proxies.
    • + *
    • If multiple instances of a forwarded header are provided, this + * handler will use the right-most instance, which will have been set from + * the trusted local proxy
    • + *
    + * Requests in excess of the limit will be asynchronously suspended until + * a thread is available. + *

    This is a simpler alternative to DosFilter

    + */ +public class ThreadLimitHandler extends HandlerWrapper +{ + private static final Logger LOG = Log.getLogger(ThreadLimitHandler.class); + + private final static String REMOTE = "o.e.j.s.h.TLH.REMOTE"; + private final static String PERMIT = "o.e.j.s.h.TLH.PASS"; + private final boolean _rfc7239; + private final String _forwardedHeader; + private final IncludeExcludeSet _includeExcludeSet = new IncludeExcludeSet<>(InetAddressSet.class); + private final ConcurrentMap _remotes = new ConcurrentHashMap<>(); + private volatile boolean _enabled; + private int _threadLimit=10; + + public ThreadLimitHandler() + { + this(null,false); + } + + public ThreadLimitHandler(@Name("forwardedHeader") String forwardedHeader) + { + this(forwardedHeader,HttpHeader.FORWARDED.is(forwardedHeader)); + } + + public ThreadLimitHandler(@Name("forwardedHeader") String forwardedHeader, @Name("rfc7239") boolean rfc7239) + { + super(); + _rfc7239 = rfc7239; + _forwardedHeader = forwardedHeader; + _enabled = true; + } + + @Override + protected void doStart() throws Exception + { + super.doStart(); + LOG.info(String.format("ThreadLimitHandler enable=%b limit=%d include=%s",_enabled,_threadLimit,_includeExcludeSet)); + } + + @ManagedAttribute("true if this handler is enabled") + public boolean isEnabled() + { + return _enabled; + } + + public void setEnabled(boolean enabled) + { + _enabled = enabled; + LOG.info(String.format("ThreadLimitHandler enable=%b limit=%d include=%s",_enabled,_threadLimit,_includeExcludeSet)); + } + + @ManagedAttribute("The maximum threads that can be dispatched per remote IP") + public int getThreadLimit() + { + return _threadLimit; + } + + public void setThreadLimit(int threadLimit) + { + if (threadLimit<=0) + throw new IllegalArgumentException("limit must be >0"); + _threadLimit = threadLimit; + } + + @ManagedOperation("Include IP in thread limits") + public void include(String inetAddressPattern) + { + _includeExcludeSet.include(inetAddressPattern); + } + + @ManagedOperation("Exclude IP from thread limits") + public void exclude(String inetAddressPattern) + { + _includeExcludeSet.exclude(inetAddressPattern); + } + + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + // Allow ThreadLimit to be enabled dynamically without restarting server + if (!_enabled) + { + // if disabled, handle normally + super.handle(target,baseRequest,request,response); + } + else + { + // Get the remote address of the request + Remote remote = getRemote(baseRequest); + if (remote==null) + { + // if remote is not known, handle normally + super.handle(target,baseRequest,request,response); + } + else + { + // Do we already have a future permit from a previous invocation? + Closeable permit = (Closeable)baseRequest.getAttribute(PERMIT); + try + { + if (permit!=null) + { + // Yes, remove it from any future async cycles. + baseRequest.removeAttribute(PERMIT); + } + else + { + // No, then lets try to acquire one + CompletableFuture future_permit=remote.acquire(); + + // Did we get a permit? + if (future_permit.isDone()) + { + // yes + permit=future_permit.get(); + } + else + { + if (LOG.isDebugEnabled()) + LOG.debug("Threadlimited {} {}",remote,target); + // No, lets asynchronously suspend the request + AsyncContext async = baseRequest.startAsync(); + // let's never timeout the async. If this is a DOS, then good to make them wait, if this is not + // then give them maximum time to get a thread. + async.setTimeout(0); + + // dispatch the request when we do eventually get a pass + future_permit.thenAccept(c-> + { + baseRequest.setAttribute(PERMIT,c); + async.dispatch(); + }); + return; + } + } + + // Use the permit + super.handle(target,baseRequest,request,response); + } + catch (InterruptedException | ExecutionException e) + { + throw new ServletException(e); + } + finally + { + if (permit!=null) + permit.close(); + } + } + } + } + + protected int getThreadLimit(String ip) + { + if (!_includeExcludeSet.isEmpty()) + { + try + { + if (!_includeExcludeSet.test(InetAddress.getByName(ip))) + { + LOG.debug("excluded {}",ip); + return 0; + } + } + catch(Exception e) + { + LOG.ignore(e); + } + } + return _threadLimit; + } + + protected Remote getRemote(Request baseRequest) + { + Remote remote = (Remote)baseRequest.getAttribute(REMOTE); + if (remote!=null) + return remote; + + String ip=getRemoteIP(baseRequest); + LOG.debug("ip={}",ip); + if (ip==null) + return null; + + int limit = getThreadLimit(ip); + if (limit<=0) + return null; + + remote = _remotes.get(ip); + if (remote==null) + { + Remote r = new Remote(ip,limit); + remote = _remotes.putIfAbsent(ip,r); + if (remote==null) + remote = r; + } + + baseRequest.setAttribute(REMOTE,remote); + + return remote; + } + + + protected String getRemoteIP(Request baseRequest) + { + // Do we have a forwarded header set? + if (_forwardedHeader!=null && !_forwardedHeader.isEmpty()) + { + // Yes, then try to get the remote IP from the header + String remote = _rfc7239?getForwarded(baseRequest):getXForwardedFor(baseRequest); + if (remote!=null && !remote.isEmpty()) + return remote; + } + + // If no remote IP from a header, determine it directly from the channel + // Do not use the request methods, as they may have been lied to by the + // RequestCustomizer! + InetSocketAddress inet_addr = baseRequest.getHttpChannel().getRemoteAddress(); + if (inet_addr!=null && inet_addr.getAddress()!=null) + return inet_addr.getAddress().getHostAddress(); + return null; + } + + private String getForwarded(Request request) + { + // Get the right most Forwarded for value. + // This is the value from the closest proxy and the only one that + // can be trusted. + RFC7239 rfc7239 = new RFC7239(); + HttpFields httpFields = request.getHttpFields(); + for (HttpField field : httpFields) + if (_forwardedHeader.equalsIgnoreCase(field.getName())) + rfc7239.addValue(field.getValue()); + + if (rfc7239.getFor()!=null) + return new HostPortHttpField(rfc7239.getFor()).getHost(); + + return null; + } + + private String getXForwardedFor(Request request) + { + // Get the right most XForwarded-For for value. + // This is the value from the closest proxy and the only one that + // can be trusted. + String forwarded_for = null; + HttpFields httpFields = request.getHttpFields(); + for (HttpField field : httpFields) + if (_forwardedHeader.equalsIgnoreCase(field.getName())) + forwarded_for = field.getValue(); + + if (forwarded_for==null || forwarded_for.isEmpty()) + return null; + + int comma = forwarded_for.lastIndexOf(','); + return (comma>=0)?forwarded_for.substring(comma+1).trim():forwarded_for; + } + + + private final class Remote implements Closeable + { + private final String _ip; + private final int _limit; + private final Locker _locker = new Locker(); + private int _permits; + private Deque> _queue = new ArrayDeque<>(); + private final CompletableFuture _permitted = CompletableFuture.completedFuture(this); + + public Remote(String ip, int limit) + { + _ip=ip; + _limit=limit; + } + + public CompletableFuture acquire() + { + try(Locker.Lock lock = _locker.lock()) + { + // Do we have available passes? + if (_permits<_limit) + { + // Yes - increment the allocated passes + _permits++; + // return the already completed future + return _permitted; // TODO is it OK to share/reuse this? + } + + // No pass available, so queue a new future + CompletableFuture pass = new CompletableFuture(); + _queue.addLast(pass); + return pass; + } + } + + @Override + public void close() throws IOException + { + try(Locker.Lock lock = _locker.lock()) + { + // reduce the allocated passes + _permits--; + while(true) + { + // Are there any future passes waiting? + CompletableFuture permit = _queue.pollFirst(); + + // No - we are done + if (permit==null) + break; + + // Yes - if we can complete them, we are done + if (permit.complete(this)) + { + _permits++; + break; + } + + // Somebody else must have completed/failed that future pass, + // so let's try for another. + } + } + } + + @Override + public String toString() + { + try(Locker.Lock lock = _locker.lock()) + { + return String.format("R[ip=%s,p=%d,l=%d,q=%d]",_ip,_permits,_limit,_queue.size()); + } + } + } + + private final class RFC7239 extends QuotedCSV + { + String _for; + + private RFC7239() + { + super(false); + } + + String getFor() + { + return _for; + } + + @Override + protected void parsedParam(StringBuffer buffer, int valueLength, int paramName, int paramValue) + { + if (valueLength==0 && paramValue>paramName) + { + String name=StringUtil.asciiToLowerCase(buffer.substring(paramName,paramValue-1)); + if ("for".equalsIgnoreCase(name)) + { + String value=buffer.substring(paramValue); + + // if unknown, clear any leftward values + if ("unknown".equalsIgnoreCase(value)) + _for = null; + // Otherwise accept IP or token(starting with '_') as remote keys + else + _for=value; + } + } + } + } +} diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java index 37b7a5aa788..2ec6e6e2a53 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java @@ -30,10 +30,8 @@ import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.http.CompressedContentFormat; import org.eclipse.jetty.http.HttpField; -import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpMethod; -import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.http.pathmap.PathSpecSet; import org.eclipse.jetty.server.HttpOutput; @@ -67,6 +65,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory private int _compressionLevel=Deflater.DEFAULT_COMPRESSION; private boolean _checkGzExists = true; private boolean _syncFlush = false; + private int _inflateBufferSize = -1; // non-static, as other GzipHandler instances may have different configurations private final ThreadLocal _deflater = new ThreadLocal<>(); @@ -79,6 +78,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory private HttpField _vary; + /* ------------------------------------------------------------ */ /** * Instantiates a new gzip handler. @@ -400,6 +400,24 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory return _vary; } + /* ------------------------------------------------------------ */ + /** + * @return size in bytes of the buffer to inflate compressed request, or 0 for no inflation. + */ + public int getInflateBufferSize() + { + return _inflateBufferSize; + } + + /* ------------------------------------------------------------ */ + /** + * @param size size in bytes of the buffer to inflate compressed request, or 0 for no inflation. + */ + public void setInflateBufferSize(int size) + { + _inflateBufferSize = size; + } + /* ------------------------------------------------------------ */ /** * @see org.eclipse.jetty.server.handler.HandlerWrapper#handle(java.lang.String, org.eclipse.jetty.server.Request, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) @@ -411,6 +429,19 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory String path = context==null?baseRequest.getRequestURI():URIUtil.addPaths(baseRequest.getServletPath(),baseRequest.getPathInfo()); LOG.debug("{} handle {} in {}",this,baseRequest,context); + // Handle request inflation + if (_inflateBufferSize>0) + { + HttpField ce = baseRequest.getHttpFields().getField(HttpHeader.CONTENT_ENCODING); + if (ce!=null && "gzip".equalsIgnoreCase(ce.getValue())) + { + // TODO should check ce.contains and then remove just the gzip encoding + baseRequest.getHttpFields().remove(HttpHeader.CONTENT_ENCODING); + baseRequest.getHttpFields().add(new HttpField("X-Content-Encoding",ce.getValue())); + baseRequest.getHttpInput().addInterceptor(new GzipHttpInputInterceptor(baseRequest.getHttpChannel().getByteBufferPool(),_inflateBufferSize)); + } + } + HttpOutput out = baseRequest.getResponse().getHttpOutput(); // Are we already being gzipped? HttpOutput.Interceptor interceptor = out.getInterceptor(); @@ -426,7 +457,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory } // If not a supported method - no Vary because no matter what client, this URI is always excluded - if (!_methods.matches(baseRequest.getMethod())) + if (!_methods.test(baseRequest.getMethod())) { LOG.debug("{} excluded by method {}",this,request); _handler.handle(target,baseRequest, request, response); @@ -489,11 +520,21 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory } } - // install interceptor and handle - out.setInterceptor(new GzipHttpOutputInterceptor(this,getVaryField(),baseRequest.getHttpChannel(),out.getInterceptor(),isSyncFlush())); + HttpOutput.Interceptor orig_interceptor = out.getInterceptor(); + try + { + // install interceptor and handle + out.setInterceptor(new GzipHttpOutputInterceptor(this,getVaryField(),baseRequest.getHttpChannel(),orig_interceptor,isSyncFlush())); - if (_handler!=null) - _handler.handle(target,baseRequest, request, response); + if (_handler!=null) + _handler.handle(target,baseRequest, request, response); + } + finally + { + // reset interceptor if request not handled + if (!baseRequest.isHandled() && !baseRequest.isAsyncStarted()) + out.setInterceptor(orig_interceptor); + } } /* ------------------------------------------------------------ */ @@ -508,14 +549,14 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory if (ua == null) return false; - return _agentPatterns.matches(ua); + return _agentPatterns.test(ua); } /* ------------------------------------------------------------ */ @Override public boolean isMimeTypeGzipable(String mimetype) { - return _mimeTypes.matches(mimetype); + return _mimeTypes.test(mimetype); } /* ------------------------------------------------------------ */ @@ -531,7 +572,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory if (requestURI == null) return true; - return _paths.matches(requestURI); + return _paths.test(requestURI); } /* ------------------------------------------------------------ */ diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHttpInputInterceptor.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHttpInputInterceptor.java new file mode 100644 index 00000000000..4f55cd956b5 --- /dev/null +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHttpInputInterceptor.java @@ -0,0 +1,88 @@ +// +// ======================================================================== +// Copyright (c) 1995-2016 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.server.handler.gzip; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http.GZIPContentDecoder; +import org.eclipse.jetty.io.ByteBufferPool; +import org.eclipse.jetty.server.HttpInput; +import org.eclipse.jetty.server.HttpInput.Content; +import org.eclipse.jetty.util.component.Destroyable; + +/** + * A HttpInput Interceptor that inflates GZIP encoded request content. + */ +public class GzipHttpInputInterceptor implements HttpInput.Interceptor, Destroyable +{ + private final Decoder _decoder; + private ByteBuffer _chunk; + + public GzipHttpInputInterceptor(ByteBufferPool pool, int bufferSize) + { + _decoder = new Decoder(pool, bufferSize); + } + + @Override + public Content readFrom(Content content) + { + _decoder.decodeChunks(content.getByteBuffer()); + final ByteBuffer chunk = _chunk; + + if (chunk == null) + return null; + + return new Content(chunk) + { + @Override + public void succeeded() + { + _decoder.release(chunk); + } + }; + } + + @Override + public void destroy() + { + _decoder.destroy(); + } + + private class Decoder extends GZIPContentDecoder + { + private Decoder(ByteBufferPool pool, int bufferSize) + { + super(pool, bufferSize); + } + + @Override + protected boolean decodedChunk(final ByteBuffer chunk) + { + _chunk = chunk; + return true; + } + + @Override + public void decodeChunks(ByteBuffer compressed) + { + _chunk = null; + super.decodeChunks(compressed); + } + } +} diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHttpOutputInterceptor.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHttpOutputInterceptor.java index 2aadead2dbd..7be253c7fa7 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHttpOutputInterceptor.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHttpOutputInterceptor.java @@ -29,6 +29,7 @@ import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.http.PreEncodedHttpField; +import org.eclipse.jetty.http.QuotedCSV; import org.eclipse.jetty.server.HttpChannel; import org.eclipse.jetty.server.HttpOutput; import org.eclipse.jetty.server.Response; @@ -190,7 +191,8 @@ public class GzipHttpOutputInterceptor implements HttpOutput.Interceptor } // Has the Content-Encoding header already been set? - String ce=response.getHeader("Content-Encoding"); + HttpFields fields = response.getHttpFields(); + String ce=fields.get(HttpHeader.CONTENT_ENCODING); if (ce != null) { LOG.debug("{} exclude by content-encoding {}",this,ce); @@ -203,9 +205,13 @@ public class GzipHttpOutputInterceptor implements HttpOutput.Interceptor if (_state.compareAndSet(GZState.MIGHT_COMPRESS,GZState.COMMITTING)) { // We are varying the response due to accept encoding header. - HttpFields fields = response.getHttpFields(); if (_vary != null) - fields.add(_vary); + { + if (fields.contains(HttpHeader.VARY)) + fields.addCSV(HttpHeader.VARY,_vary.getValues()); + else + fields.add(_vary); + } long content_length = response.getContentLength(); if (content_length<0 && complete) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/DatabaseAdaptor.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/DatabaseAdaptor.java index 107ef24ad7d..456764a8dfb 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/DatabaseAdaptor.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/DatabaseAdaptor.java @@ -130,6 +130,9 @@ public class DatabaseAdaptor */ public String convertIdentifier (String identifier) { + if (identifier == null) + return null; + if (_dbName == null) throw new IllegalStateException ("DbAdaptor missing metadata"); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionCacheFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionCacheFactory.java index 373579a5b77..6f933de8fd0 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionCacheFactory.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionCacheFactory.java @@ -28,11 +28,36 @@ public class DefaultSessionCacheFactory implements SessionCacheFactory { int _evictionPolicy; boolean _saveOnInactiveEvict; + boolean _saveOnCreate; boolean _removeUnloadableSessions; + /** + * @return the saveOnCreate + */ + public boolean isSaveOnCreate() + { + return _saveOnCreate; + } + + + + /** + * @param saveOnCreate the saveOnCreate to set + */ + public void setSaveOnCreate(boolean saveOnCreate) + { + _saveOnCreate = saveOnCreate; + } + + + + + /** + * @return + */ public boolean isRemoveUnloadableSessions() { return _removeUnloadableSessions; @@ -41,6 +66,9 @@ public class DefaultSessionCacheFactory implements SessionCacheFactory + /** + * @param removeUnloadableSessions + */ public void setRemoveUnloadableSessions(boolean removeUnloadableSessions) { _removeUnloadableSessions = removeUnloadableSessions; @@ -49,6 +77,9 @@ public class DefaultSessionCacheFactory implements SessionCacheFactory + /** + * @return + */ public int getEvictionPolicy() { return _evictionPolicy; @@ -57,6 +88,9 @@ public class DefaultSessionCacheFactory implements SessionCacheFactory + /** + * @param evictionPolicy + */ public void setEvictionPolicy(int evictionPolicy) { _evictionPolicy = evictionPolicy; @@ -65,6 +99,9 @@ public class DefaultSessionCacheFactory implements SessionCacheFactory + /** + * @return + */ public boolean isSaveOnInactiveEvict() { return _saveOnInactiveEvict; @@ -73,6 +110,9 @@ public class DefaultSessionCacheFactory implements SessionCacheFactory + /** + * @param saveOnInactiveEvict + */ public void setSaveOnInactiveEvict(boolean saveOnInactiveEvict) { _saveOnInactiveEvict = saveOnInactiveEvict; @@ -90,6 +130,7 @@ public class DefaultSessionCacheFactory implements SessionCacheFactory DefaultSessionCache cache = new DefaultSessionCache(handler); cache.setEvictionPolicy(getEvictionPolicy()); cache.setSaveOnInactiveEviction(isSaveOnInactiveEvict()); + cache.setSaveOnCreate(isSaveOnCreate()); cache.setRemoveUnloadableSessions(isRemoveUnloadableSessions()); return cache; } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionIdManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionIdManager.java index ad9a1c15504..9ee4635e6aa 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionIdManager.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionIdManager.java @@ -336,9 +336,9 @@ public class DefaultSessionIdManager extends AbstractLifeCycle implements Sessio { String inst = System.getenv("JETTY_WORKER_INSTANCE"); _workerName = "node"+ (inst==null?"0":inst); - LOG.warn("No workerName configured for DefaultSessionIdManager, using {}",_workerName); } + LOG.info("DefaultSessionIdManager workerName={}",_workerName); _workerAttr=(_workerName!=null && _workerName.startsWith("$"))?_workerName.substring(1):null; if (_houseKeeper == null) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/HouseKeeper.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/HouseKeeper.java index e1bbb481e70..6c87ca97b95 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/HouseKeeper.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/HouseKeeper.java @@ -46,6 +46,7 @@ public class HouseKeeper extends AbstractLifeCycle protected boolean _ownScheduler = false; private long _intervalMs = DEFAULT_PERIOD_MS; + @@ -93,27 +94,86 @@ public class HouseKeeper extends AbstractLifeCycle if (_sessionIdManager == null) throw new IllegalStateException ("No SessionIdManager for Housekeeper"); - - if (_sessionIdManager instanceof DefaultSessionIdManager) - { - //try and use a common scheduler, fallback to own - _scheduler = ((DefaultSessionIdManager)_sessionIdManager).getServer().getBean(Scheduler.class); - } - - if (_scheduler == null) - { - _scheduler = new ScheduledExecutorScheduler(); - _ownScheduler = true; - _scheduler.start(); - } - else if (!_scheduler.isStarted()) - throw new IllegalStateException("Shared scheduler not started"); - setIntervalSec(getIntervalSec()); super.doStart(); } + + /** + * Get a scheduler. First try a common scheduler, failing that + * create our own. + * + * @throws Exception + */ + protected void findScheduler () throws Exception + { + if (_scheduler == null) + { + if (_sessionIdManager instanceof DefaultSessionIdManager) + { + //try and use a common scheduler, fallback to own + _scheduler = ((DefaultSessionIdManager)_sessionIdManager).getServer().getBean(Scheduler.class); + } + + if (_scheduler == null) + { + _scheduler = new ScheduledExecutorScheduler(); + _ownScheduler = true; + _scheduler.start(); + if (LOG.isDebugEnabled()) LOG.debug("Using own scheduler for scavenging"); + } + else if (!_scheduler.isStarted()) + throw new IllegalStateException("Shared scheduler not started"); + } + } + + /** + * If scavenging is not scheduled, schedule it. + * @throws Exception + */ + protected void startScavenging() throws Exception + { + synchronized (this) + { + if (_scheduler != null) + { + //cancel any previous task + if (_task!=null) + _task.cancel(); + if (_runner == null) + _runner = new Runner(); + LOG.info("Scavenging every {}ms", _intervalMs); + _task = _scheduler.schedule(_runner,_intervalMs,TimeUnit.MILLISECONDS); + } + } + } + + /** + * If scavenging is scheduled, stop it. + * + * @throws Exception + */ + protected void stopScavenging() throws Exception + { + synchronized (this) + { + if (_task!=null) + { + _task.cancel(); + LOG.info("Stopped scavenging"); + } + _task = null; + if (_ownScheduler) + { + _scheduler.stop(); + _scheduler = null; + } + } + _runner = null; + } + + /** * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStop() */ @@ -122,13 +182,8 @@ public class HouseKeeper extends AbstractLifeCycle { synchronized(this) { - if (_task != null) - _task.cancel(); - _task=null; - if (_ownScheduler && _scheduler !=null) - _scheduler.stop(); + stopScavenging(); _scheduler = null; - _runner = null; } super.doStop(); } @@ -137,37 +192,43 @@ public class HouseKeeper extends AbstractLifeCycle /** * Set the period between scavenge cycles * @param sec the interval (in seconds) + * @throws Exception */ - public void setIntervalSec (long sec) + public void setIntervalSec (long sec) throws Exception { - if (sec<=0) - sec=60; - - long old_period=_intervalMs; - long period=sec*1000L; - - _intervalMs=period; - - //add a bit of variability into the scavenge time so that not all - //nodes with the same scavenge interval sync up - long tenPercent = _intervalMs/10; - if ((System.currentTimeMillis()%2) == 0) - _intervalMs += tenPercent; - - if (LOG.isDebugEnabled()) - LOG.debug("Scavenging every "+_intervalMs+" ms"); - - synchronized (this) + if (isStarted() || isStarting()) { - if (_scheduler != null && (period!=old_period || _task==null)) + if (sec <= 0) { - if (_task!=null) - _task.cancel(); - if (_runner == null) - _runner = new Runner(); - _task = _scheduler.schedule(_runner,_intervalMs,TimeUnit.MILLISECONDS); + _intervalMs = 0L; + LOG.info("Scavenging disabled"); + stopScavenging(); + } + else + { + if (sec < 10) + LOG.warn("Short interval of {}sec for session scavenging.", sec); + + _intervalMs=sec*1000L; + + //add a bit of variability into the scavenge time so that not all + //nodes with the same scavenge interval sync up + long tenPercent = _intervalMs/10; + if ((System.currentTimeMillis()%2) == 0) + _intervalMs += tenPercent; + + if (isStarting() || isStarted()) + { + findScheduler(); + startScavenging(); + } } } + else + { + _intervalMs=sec*1000L; + } + } @@ -183,6 +244,8 @@ public class HouseKeeper extends AbstractLifeCycle } + + /** * Periodically do session housekeeping diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionDataStore.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionDataStore.java index 5db388c2bb9..ec23c7e200a 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionDataStore.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionDataStore.java @@ -65,6 +65,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore public final static int MAX_INTERVAL_NOT_SET = -999; protected DatabaseAdaptor _dbAdaptor; + protected String _schemaName = null; protected String _tableName = "JettySessions"; protected String _idColumn = "sessionId"; protected String _contextPathColumn = "contextPath"; @@ -85,7 +86,15 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore { _dbAdaptor = dbadaptor; } - + public String getSchemaName() + { + return _schemaName; + } + public void setSchemaName(String schemaName) + { + checkNotNull(schemaName); + _schemaName = schemaName; + } public String getTableName() { @@ -97,6 +106,11 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore _tableName = tableName; } + private String getSchemaTableName() + { + return (getSchemaName()!=null?getSchemaName()+".":"")+getTableName(); + } + public String getIdColumn() { return _idColumn; @@ -223,12 +237,12 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore public String getCreateIndexOverExpiryStatementAsString (String indexName) { - return "create index "+indexName+" on "+getTableName()+" ("+getExpiryTimeColumn()+")"; + return "create index "+indexName+" on "+getSchemaTableName()+" ("+getExpiryTimeColumn()+")"; } public String getCreateIndexOverSessionStatementAsString (String indexName) { - return "create index "+indexName+" on "+getTableName()+" ("+getIdColumn()+", "+getContextPathColumn()+")"; + return "create index "+indexName+" on "+getSchemaTableName()+" ("+getIdColumn()+", "+getContextPathColumn()+")"; } public String getAlterTableForMaxIntervalAsString () @@ -236,7 +250,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore if (_dbAdaptor == null) throw new IllegalStateException ("No DBAdaptor"); String longType = _dbAdaptor.getLongType(); - String stem = "alter table "+getTableName()+" add "+getMaxIntervalColumn()+" "+longType; + String stem = "alter table "+getSchemaTableName()+" add "+getMaxIntervalColumn()+" "+longType; if (_dbAdaptor.getDBName().contains("oracle")) return stem + " default "+ MAX_INTERVAL_NOT_SET + " not null"; else @@ -250,7 +264,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore } public String getInsertSessionStatementAsString() { - return "insert into "+getTableName()+ + return "insert into "+getSchemaTableName()+ " ("+getIdColumn()+", "+getContextPathColumn()+", "+getVirtualHostColumn()+", "+getLastNodeColumn()+ ", "+getAccessTimeColumn()+", "+getLastAccessTimeColumn()+", "+getCreateTimeColumn()+", "+getCookieTimeColumn()+ ", "+getLastSavedTimeColumn()+", "+getExpiryTimeColumn()+", "+getMaxIntervalColumn()+", "+getMapColumn()+") "+ @@ -260,7 +274,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore public PreparedStatement getUpdateSessionStatement(Connection connection, String canonicalContextPath) throws SQLException { - String s = "update "+getTableName()+ + String s = "update "+getSchemaTableName()+ " set "+getLastNodeColumn()+" = ?, "+getAccessTimeColumn()+" = ?, "+ getLastAccessTimeColumn()+" = ?, "+getLastSavedTimeColumn()+" = ?, "+getExpiryTimeColumn()+" = ?, "+ getMaxIntervalColumn()+" = ?, "+getMapColumn()+" = ? where "; @@ -293,7 +307,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore if (_dbAdaptor.isEmptyStringNull()) { PreparedStatement statement = connection.prepareStatement("select "+getIdColumn()+", "+getExpiryTimeColumn()+ - " from "+getTableName()+" where "+ + " from "+getSchemaTableName()+" where "+ getContextPathColumn()+" is null and "+ getVirtualHostColumn()+" = ? and "+getExpiryTimeColumn()+" >0 and "+getExpiryTimeColumn()+" <= ?"); statement.setString(1, vhost); @@ -303,7 +317,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore } PreparedStatement statement = connection.prepareStatement("select "+getIdColumn()+", "+getExpiryTimeColumn()+ - " from "+getTableName()+" where "+getContextPathColumn()+" = ? and "+ + " from "+getSchemaTableName()+" where "+getContextPathColumn()+" = ? and "+ getVirtualHostColumn()+" = ? and "+ getExpiryTimeColumn()+" >0 and "+getExpiryTimeColumn()+" <= ?"); @@ -325,7 +339,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore if (_dbAdaptor.isEmptyStringNull()) { PreparedStatement statement = connection.prepareStatement("select "+getIdColumn()+", "+getExpiryTimeColumn()+ - " from "+getTableName()+" where "+ + " from "+getSchemaTableName()+" where "+ getLastNodeColumn() + " = ? and "+ getContextPathColumn()+" is null and "+ getVirtualHostColumn()+" = ? and "+getExpiryTimeColumn()+" >0 and "+getExpiryTimeColumn()+" <= ?"); @@ -337,7 +351,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore } PreparedStatement statement = connection.prepareStatement("select "+getIdColumn()+", "+getExpiryTimeColumn()+ - " from "+getTableName()+" where "+ + " from "+getSchemaTableName()+" where "+ getLastNodeColumn()+" = ? and "+ getContextPathColumn()+" = ? and "+ getVirtualHostColumn()+" = ? and "+ @@ -358,7 +372,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore throw new IllegalStateException("No DB adaptor"); PreparedStatement statement = connection.prepareStatement("select "+getIdColumn()+", "+getContextPathColumn()+", "+getVirtualHostColumn()+ - " from "+getTableName()+ + " from "+getSchemaTableName()+ " where "+getExpiryTimeColumn()+" >0 and "+getExpiryTimeColumn()+" <= ?"); return statement; } @@ -376,7 +390,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore if (_dbAdaptor.isEmptyStringNull()) { PreparedStatement statement = connection.prepareStatement("select "+getIdColumn()+", "+getExpiryTimeColumn()+ - " from "+getTableName()+ + " from "+getSchemaTableName()+ " where "+getIdColumn()+" = ? and "+ getContextPathColumn()+" is null and "+ getVirtualHostColumn()+" = ?"); @@ -385,7 +399,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore } PreparedStatement statement = connection.prepareStatement("select "+getIdColumn()+", "+getExpiryTimeColumn()+ - " from "+getTableName()+ + " from "+getSchemaTableName()+ " where "+getIdColumn()+" = ? and "+ getContextPathColumn()+" = ? and "+ getVirtualHostColumn()+" = ?"); @@ -422,7 +436,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore { if (_dbAdaptor.isEmptyStringNull()) { - PreparedStatement statement = connection.prepareStatement("select * from "+getTableName()+ + PreparedStatement statement = connection.prepareStatement("select * from "+getSchemaTableName()+ " where "+getIdColumn()+" = ? and "+ getContextPathColumn()+" is null and "+ getVirtualHostColumn()+" = ?"); @@ -433,7 +447,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore } } - PreparedStatement statement = connection.prepareStatement("select * from "+getTableName()+ + PreparedStatement statement = connection.prepareStatement("select * from "+getSchemaTableName()+ " where "+getIdColumn()+" = ? and "+getContextPathColumn()+ " = ? and "+getVirtualHostColumn()+" = ?"); statement.setString(1, id); @@ -451,7 +465,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore if (_dbAdaptor == null) throw new IllegalStateException("No DB adaptor"); - String s = "update "+getTableName()+ + String s = "update "+getSchemaTableName()+ " set "+getLastNodeColumn()+" = ?, "+getAccessTimeColumn()+" = ?, "+ getLastAccessTimeColumn()+" = ?, "+getLastSavedTimeColumn()+" = ?, "+getExpiryTimeColumn()+" = ?, "+ getMaxIntervalColumn()+" = ?, "+getMapColumn()+" = ? where "; @@ -492,7 +506,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore { if (_dbAdaptor.isEmptyStringNull()) { - PreparedStatement statement = connection.prepareStatement("delete from "+getTableName()+ + PreparedStatement statement = connection.prepareStatement("delete from "+getSchemaTableName()+ " where "+getIdColumn()+" = ? and "+getContextPathColumn()+ " = ? and "+getVirtualHostColumn()+" = ?"); statement.setString(1, id); @@ -501,7 +515,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore } } - PreparedStatement statement = connection.prepareStatement("delete from "+getTableName()+ + PreparedStatement statement = connection.prepareStatement("delete from "+getSchemaTableName()+ " where "+getIdColumn()+" = ? and "+getContextPathColumn()+ " = ? and "+getVirtualHostColumn()+" = ?"); statement.setString(1, id); @@ -531,7 +545,8 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore //make the session table if necessary String tableName = _dbAdaptor.convertIdentifier(getTableName()); - try (ResultSet result = metaData.getTables(null, null, tableName, null)) + String schemaName = _dbAdaptor.convertIdentifier(getSchemaName()); + try (ResultSet result = metaData.getTables(null, schemaName, tableName, null)) { if (!result.next()) { @@ -544,8 +559,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore ResultSet colResult = null; try { - colResult = metaData.getColumns(null, null, - _dbAdaptor.convertIdentifier(getTableName()), + colResult = metaData.getColumns(null, schemaName, tableName, _dbAdaptor.convertIdentifier(getMaxIntervalColumn())); } catch (SQLException s) @@ -585,7 +599,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore boolean index1Exists = false; boolean index2Exists = false; - try (ResultSet result = metaData.getIndexInfo(null, null, tableName, false, false)) + try (ResultSet result = metaData.getIndexInfo(null, schemaName, tableName, false, true)) { while (result.next()) { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/NullSessionCache.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/NullSessionCache.java index 846d47919ce..f4df822343a 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/NullSessionCache.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/NullSessionCache.java @@ -37,6 +37,7 @@ public class NullSessionCache extends AbstractSessionCache public NullSessionCache(SessionHandler handler) { super(handler); + super.setEvictionPolicy(EVICT_ON_SESSION_EXIT); } /** @@ -104,4 +105,15 @@ public class NullSessionCache extends AbstractSessionCache return null; } + /** + * @see org.eclipse.jetty.server.session.AbstractSessionCache#setEvictionPolicy(int) + */ + @Override + public void setEvictionPolicy(int evictionTimeout) + { + LOG.warn("Ignoring eviction setting:"+evictionTimeout); + } + + + } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/NullSessionCacheFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/NullSessionCacheFactory.java new file mode 100644 index 00000000000..5a23c37de87 --- /dev/null +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/NullSessionCacheFactory.java @@ -0,0 +1,86 @@ +// +// ======================================================================== +// Copyright (c) 1995-2016 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.server.session; + +/** + * NullSessionCacheFactory + * + * Factory for NullSessionCaches. + */ +public class NullSessionCacheFactory implements SessionCacheFactory +{ + boolean _saveOnCreate; + boolean _removeUnloadableSessions; + + + /** + * @return the saveOnCreate + */ + public boolean isSaveOnCreate() + { + return _saveOnCreate; + } + + + + /** + * @param saveOnCreate the saveOnCreate to set + */ + public void setSaveOnCreate(boolean saveOnCreate) + { + _saveOnCreate = saveOnCreate; + } + + + + /** + * @return the removeUnloadableSessions + */ + public boolean isRemoveUnloadableSessions() + { + return _removeUnloadableSessions; + } + + + + /** + * @param removeUnloadableSessions the removeUnloadableSessions to set + */ + public void setRemoveUnloadableSessions(boolean removeUnloadableSessions) + { + _removeUnloadableSessions = removeUnloadableSessions; + } + + + + /** + * @see org.eclipse.jetty.server.session.SessionCacheFactory#getSessionCache(org.eclipse.jetty.server.session.SessionHandler) + */ + @Override + public SessionCache getSessionCache(SessionHandler handler) + { + NullSessionCache cache = new NullSessionCache(handler); + cache.setSaveOnCreate(isSaveOnCreate()); + cache.setRemoveUnloadableSessions(isRemoveUnloadableSessions()); + return cache; + + } + +} diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionContext.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionContext.java index 10c9bf71831..402fe596c7e 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionContext.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionContext.java @@ -25,28 +25,26 @@ import org.eclipse.jetty.server.handler.ContextHandler.Context; /** * SessionContext * - * The worker name which identifies this server instance, and the particular - * Context. + * Information about the context to which sessions belong: the Context, + * the SessionHandler of the context, and the unique name of the node. * - * A SessionManager is 1:1 with a SessionContext. + * A SessionHandler is 1:1 with a SessionContext. */ public class SessionContext { public final static String NULL_VHOST = "0.0.0.0"; private ContextHandler.Context _context; + private SessionHandler _sessionHandler; private String _workerName; private String _canonicalContextPath; private String _vhost; - - public String getWorkerName() - { - return _workerName; - } public SessionContext (String workerName, ContextHandler.Context context) { + if (context != null) + _sessionHandler = context.getContextHandler().getChildHandlerByClass(SessionHandler.class); _workerName = workerName; _context = context; _canonicalContextPath = canonicalizeContextPath(_context); @@ -54,6 +52,17 @@ public class SessionContext } + public String getWorkerName() + { + return _workerName; + } + + public SessionHandler getSessionHandler() + { + return _sessionHandler; + } + + public Context getContext () { return _context; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionData.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionData.java index 152e1a980c3..6ee6e96e42f 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionData.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionData.java @@ -351,7 +351,7 @@ public class SessionData implements Serializable public boolean isExpiredAt (long time) { if (LOG.isDebugEnabled()) - LOG.debug("Testing expiry on session {}: Never expires? {} Is expired?{}", _id, (getExpiry()<= 0), (getExpiry() < time)); + LOG.debug("Testing expiry on session {}: expires at {} now {}", _id, getExpiry(), time); if (getExpiry() <= 0) return false; //never expires return (getExpiry() <= time); diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncRequestReadTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncRequestReadTest.java index 985d8c01bed..820e7ebf0c2 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncRequestReadTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncRequestReadTest.java @@ -354,6 +354,7 @@ public class AsyncRequestReadTest for (int i=read;i-->0;) { int c=in.read(); + // System.err.println("in="+c); if (c<0) break; out.write(c); diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ConnectorStatisticsTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ConnectorStatisticsTest.java deleted file mode 100644 index 2fa7d21ebb0..00000000000 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ConnectorStatisticsTest.java +++ /dev/null @@ -1,266 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 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.server; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.PrintWriter; -import java.net.Socket; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.CyclicBarrier; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.server.handler.AbstractHandler; -import org.eclipse.jetty.server.handler.HandlerWrapper; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Ignore; -import org.junit.Test; - -@Ignore("Ignored while refactoring the connection events and statistics") -public class ConnectorStatisticsTest -{ - private static final Logger LOG = Log.getLogger(ConnectorStatisticsTest.class); - - private static Server _server; - private static ConnectorStatistics _statistics; - private static AbstractNetworkConnector _connector; - private static CyclicBarrier _connect; - private static CountDownLatch _closed; - - private Socket[] _socket; - private PrintWriter[] _out; - private BufferedReader[] _in; - - @BeforeClass - public static void initClass() throws Exception - { - _connect = new CyclicBarrier(2); - - _server = new Server(); - _connector = new ServerConnector(_server); - _statistics = new ConnectorStatistics(); - _connector.addBean(_statistics); - _server.addConnector(_connector); - - HandlerWrapper wrapper = new HandlerWrapper() - { - @Override - public void handle(String path, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException - { - try - { - _connect.await(); - } - catch (Exception ex) - { - LOG.debug(ex); - } - finally - { - super.handle(path, request, httpRequest, httpResponse); - } - } - }; - _server.setHandler(wrapper); - - Handler handler = new AbstractHandler() - { - @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { - try{Thread.sleep(1);} catch(Exception e){} - baseRequest.setHandled(true); - PrintWriter out = response.getWriter(); - out.write("Server response\n"); - out.close(); - - response.setStatus(HttpServletResponse.SC_OK); - } - }; - wrapper.setHandler(handler); - - _server.start(); - } - - @AfterClass - public static void destroy() throws Exception - { - _server.stop(); - _server.join(); - } - - @Before - public void init() throws Exception - { - _statistics.reset(); - } - - @After - public void tini() throws Exception - { - } - - @Test - public void testSingleRequest() throws Exception - { - doInit(1); - - sendRequest(1, 1); - - doClose(1); - - assertEquals(1, _statistics.getConnections()); - assertEquals(0, _statistics.getConnectionsOpen()); - assertEquals(1, _statistics.getConnectionsOpenMax()); - assertTrue(_statistics.getConnectionsOpen() <= _statistics.getConnectionsOpenMax()); - - assertTrue(_statistics.getConnectionDurationMean() > 0); - assertTrue(_statistics.getConnectionDurationMax() > 0); - assertTrue(_statistics.getConnectionDurationMean() <= _statistics.getConnectionDurationMax()); - - assertEquals(1, _statistics.getMessagesIn()); - assertEquals(1.0, _statistics.getMessagesInPerConnectionMean(), 0.01); - assertEquals(1, _statistics.getMessagesInPerConnectionMax()); - assertTrue(_statistics.getMessagesInPerConnectionMean() <= _statistics.getMessagesInPerConnectionMax()); - } - - @Test - public void testMultipleRequests() throws Exception - { - doInit(1); - - sendRequest(1, 1); - - sendRequest(1, 1); - - doClose(1); - - assertEquals(1, _statistics.getConnections()); - assertEquals(0, _statistics.getConnectionsOpen()); - assertEquals(1, _statistics.getConnectionsOpenMax()); - assertTrue(_statistics.getConnectionsOpen() <= _statistics.getConnectionsOpenMax()); - - assertTrue(_statistics.getConnectionDurationMean() > 0); - assertTrue(_statistics.getConnectionDurationMax() > 0); - assertTrue(_statistics.getConnectionDurationMean() <= _statistics.getConnectionDurationMax()); - - assertEquals(2, _statistics.getMessagesIn()); - assertEquals(2.0, _statistics.getMessagesInPerConnectionMean(), 0.01); - assertEquals(2, _statistics.getMessagesInPerConnectionMax()); - assertTrue(_statistics.getMessagesInPerConnectionMean() <= _statistics.getMessagesInPerConnectionMax()); - } - - @Test - public void testMultipleConnections() throws Exception - { - doInit(3); - - sendRequest(1, 1); // request 1 connection 1 - - sendRequest(2, 2); // request 1 connection 2 - - sendRequest(3, 3); // request 1 connection 3 - - sendRequest(2, 3); // request 2 connection 2 - - sendRequest(3, 3); // request 2 connection 3 - - sendRequest(3, 3); // request 3 connection 3 - - doClose(3); - - assertEquals(3, _statistics.getConnections()); - assertEquals(0, _statistics.getConnectionsOpen()); - assertEquals(3, _statistics.getConnectionsOpenMax()); - assertTrue(_statistics.getConnectionsOpen() <= _statistics.getConnectionsOpenMax()); - - assertTrue(_statistics.getConnectionDurationMean() > 0); - assertTrue(_statistics.getConnectionDurationMax() > 0); - assertTrue(_statistics.getConnectionDurationMean() <= _statistics.getConnectionDurationMax()); - - assertEquals(6, _statistics.getMessagesIn()); - assertEquals(2.0, _statistics.getMessagesInPerConnectionMean(), 0.01); - assertEquals(3, _statistics.getMessagesInPerConnectionMax()); - assertTrue(_statistics.getMessagesInPerConnectionMean() <= _statistics.getMessagesInPerConnectionMax()); - } - - protected void doInit(int count) - { - _socket = new Socket[count]; - _out = new PrintWriter[count]; - _in = new BufferedReader[count]; - - _closed = new CountDownLatch(count); - } - - private void doClose(int count) throws Exception - { - for (int idx=0; idx < count; idx++) - { - if (_socket[idx] != null) - { - _socket[idx].close(); - } - } - - _closed.await(); - } - - private void sendRequest(int id, int count) throws Exception - { - int idx = id - 1; - - if (idx < 0) - throw new IllegalArgumentException("Connection ID <= 0"); - - _socket[idx] = _socket[idx] == null ? new Socket("localhost", _connector.getLocalPort()) : _socket[idx]; - _out[idx] = _out[idx] == null ? new PrintWriter(_socket[idx].getOutputStream(), true) : _out[idx]; - _in[idx] = _in[idx] == null ? new BufferedReader(new InputStreamReader(_socket[idx].getInputStream())) : _in[idx]; - - _connect.reset(); - - _out[idx].write("GET / HTTP/1.1\r\nHost: localhost\r\n\r\n"); - _out[idx].flush(); - - _connect.await(); - - assertEquals(count, _statistics.getConnectionsOpen()); - - String line=_in[idx].readLine(); - while(line!=null) - { - if ("Server response".equals(line)) - break; - line=_in[idx].readLine(); - } - } -} diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ConnectorTimeoutTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ConnectorTimeoutTest.java index 9f2966b0fe8..e5188af3bfb 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ConnectorTimeoutTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ConnectorTimeoutTest.java @@ -73,7 +73,12 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture { super.before(); if (_httpConfiguration!=null) + { _httpConfiguration.setBlockingTimeout(-1L); + _httpConfiguration.setMinRequestDataRate(-1); + _httpConfiguration.setIdleTimeout(-1); + } + } @Test(timeout=60000) @@ -732,41 +737,6 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture int offset=in.indexOf("Hello World"); Assert.assertTrue(offset > 0); } - - - - @Test(timeout=60000) - public void testMaxIdleWithDelayedDispatch() throws Exception - { - configureServer(new EchoHandler()); - Socket client=newSocket(_serverURI.getHost(),_serverURI.getPort()); - client.setSoTimeout(10000); - - Assert.assertFalse(client.isClosed()); - - OutputStream os=client.getOutputStream(); - InputStream is=client.getInputStream(); - - String content="Wibble"; - byte[] contentB=content.getBytes("utf-8"); - os.write(( - "POST /echo HTTP/1.1\r\n"+ - "host: "+_serverURI.getHost()+":"+_serverURI.getPort()+"\r\n"+ - "content-type: text/plain; charset=utf-8\r\n"+ - "content-length: "+contentB.length+"\r\n"+ - "\r\n").getBytes("utf-8")); - os.flush(); - - long start = System.currentTimeMillis(); - IO.toString(is); - - Thread.sleep(sleepTime); - Assert.assertEquals(-1, is.read()); - - Assert.assertTrue(System.currentTimeMillis() - start > minimumTestRuntime); - Assert.assertTrue(System.currentTimeMillis() - start < maximumTestRuntime); - } - protected static class SlowResponseHandler extends AbstractHandler { diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpInputTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpInputTest.java index 5a404f30760..dde2f0b643e 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpInputTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpInputTest.java @@ -18,93 +18,76 @@ package org.eclipse.jetty.server; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.nullValue; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - import java.io.EOFException; import java.io.IOException; import java.util.Queue; +import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeoutException; import javax.servlet.ReadListener; -import org.eclipse.jetty.toolchain.test.AdvancedRunner; import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.ConcurrentArrayQueue; import org.hamcrest.Matchers; import org.junit.After; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; -@RunWith(AdvancedRunner.class) public class HttpInputTest { - Queue _history = new ConcurrentArrayQueue() - { - @Override - public boolean add(String s) - { - //System.err.println("history: "+s); - return super.add(s); - } - }; - Queue _fillAndParseSimulate = new ConcurrentArrayQueue<>(); - HttpInput _in; - - ReadListener _listener = new ReadListener() + private final Queue _history = new LinkedBlockingQueue<>(); + private final Queue _fillAndParseSimulate = new LinkedBlockingQueue<>(); + private final ReadListener _listener = new ReadListener() { @Override public void onError(Throwable t) { - _history.add("onError:"+t); + _history.add("onError:" + t); } - + @Override public void onDataAvailable() throws IOException { _history.add("onDataAvailable"); } - + @Override public void onAllDataRead() throws IOException { _history.add("onAllDataRead"); } }; - + private HttpInput _in; + public class TContent extends HttpInput.Content { private final String _content; + public TContent(String content) { super(BufferUtil.toBuffer(content)); - _content=content; + _content = content; } - + @Override public void succeeded() { - _history.add("Content succeeded "+_content); + _history.add("Content succeeded " + _content); super.succeeded(); } - + @Override public void failed(Throwable x) { - _history.add("Content failed "+_content); + _history.add("Content failed " + _content); super.failed(x); } } - + @Before public void before() { - _in=new HttpInput(new HttpChannelState(new HttpChannel(null,new HttpConfiguration(),null,null) + _in = new HttpInput(new HttpChannelState(new HttpChannel(null, new HttpConfiguration(), null, null) { @Override public void asyncReadFillInterested() @@ -113,7 +96,6 @@ public class HttpInputTest } }) { - @Override public void onReadUnready() { @@ -127,7 +109,7 @@ public class HttpInputTest _history.add("onReadPossible"); return super.onReadPossible(); } - + @Override public boolean onReadReady() { @@ -139,9 +121,9 @@ public class HttpInputTest @Override protected void produceContent() throws IOException { - _history.add("produceContent "+_fillAndParseSimulate.size()); - - for (String s=_fillAndParseSimulate.poll();s!=null;s=_fillAndParseSimulate.poll()) + _history.add("produceContent " + _fillAndParseSimulate.size()); + + for (String s = _fillAndParseSimulate.poll(); s != null; s = _fillAndParseSimulate.poll()) { if ("_EOF_".equals(s)) _in.eof(); @@ -153,28 +135,28 @@ public class HttpInputTest @Override protected void blockForContent() throws IOException { - _history.add("blockForContent"); + _history.add("blockForContent"); super.blockForContent(); } }; } - + @After public void after() { - assertThat(_history.poll(),nullValue()); + Assert.assertThat(_history.poll(), Matchers.nullValue()); } - + @Test public void testEmpty() throws Exception { - assertThat(_in.available(),equalTo(0)); - assertThat(_history.poll(),equalTo("produceContent 0")); - assertThat(_history.poll(),nullValue()); - - assertThat(_in.isFinished(),equalTo(false)); - assertThat(_in.isReady(),equalTo(true)); - assertThat(_history.poll(),nullValue()); + Assert.assertThat(_in.available(), Matchers.equalTo(0)); + Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 0")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); + + Assert.assertThat(_in.isFinished(), Matchers.equalTo(false)); + Assert.assertThat(_in.isReady(), Matchers.equalTo(true)); + Assert.assertThat(_history.poll(), Matchers.nullValue()); } @Test @@ -184,44 +166,43 @@ public class HttpInputTest _in.addContent(new TContent("CD")); _fillAndParseSimulate.offer("EF"); _fillAndParseSimulate.offer("GH"); - assertThat(_in.available(),equalTo(2)); - assertThat(_in.isFinished(),equalTo(false)); - assertThat(_in.isReady(),equalTo(true)); + Assert.assertThat(_in.available(), Matchers.equalTo(2)); + Assert.assertThat(_in.isFinished(), Matchers.equalTo(false)); + Assert.assertThat(_in.isReady(), Matchers.equalTo(true)); - assertThat(_in.getContentConsumed(),equalTo(0L)); - assertThat(_in.read(),equalTo((int)'A')); - assertThat(_in.getContentConsumed(),equalTo(1L)); - assertThat(_in.read(),equalTo((int)'B')); - assertThat(_in.getContentConsumed(),equalTo(2L)); - - assertThat(_history.poll(),equalTo("Content succeeded AB")); - assertThat(_history.poll(),nullValue()); - - assertThat(_in.read(),equalTo((int)'C')); - assertThat(_in.read(),equalTo((int)'D')); - - assertThat(_history.poll(),equalTo("Content succeeded CD")); - assertThat(_history.poll(),nullValue()); - - assertThat(_in.read(),equalTo((int)'E')); - assertThat(_in.read(),equalTo((int)'F')); + Assert.assertThat(_in.getContentConsumed(), Matchers.equalTo(0L)); + Assert.assertThat(_in.read(), Matchers.equalTo((int)'A')); + Assert.assertThat(_in.getContentConsumed(), Matchers.equalTo(1L)); + Assert.assertThat(_in.read(), Matchers.equalTo((int)'B')); + Assert.assertThat(_in.getContentConsumed(), Matchers.equalTo(2L)); - assertThat(_history.poll(),equalTo("produceContent 2")); - assertThat(_history.poll(),equalTo("Content succeeded EF")); - assertThat(_history.poll(),nullValue()); - - assertThat(_in.read(),equalTo((int)'G')); - assertThat(_in.read(),equalTo((int)'H')); - - assertThat(_history.poll(),equalTo("Content succeeded GH")); - assertThat(_history.poll(),nullValue()); - - assertThat(_in.getContentConsumed(),equalTo(8L)); - - assertThat(_history.poll(),nullValue()); + Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded AB")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); + + Assert.assertThat(_in.read(), Matchers.equalTo((int)'C')); + Assert.assertThat(_in.read(), Matchers.equalTo((int)'D')); + + Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded CD")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); + + Assert.assertThat(_in.read(), Matchers.equalTo((int)'E')); + Assert.assertThat(_in.read(), Matchers.equalTo((int)'F')); + + Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 2")); + Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded EF")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); + + Assert.assertThat(_in.read(), Matchers.equalTo((int)'G')); + Assert.assertThat(_in.read(), Matchers.equalTo((int)'H')); + + Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded GH")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); + + Assert.assertThat(_in.getContentConsumed(), Matchers.equalTo(8L)); + + Assert.assertThat(_history.poll(), Matchers.nullValue()); } - @Test public void testReRead() throws Exception { @@ -229,88 +210,86 @@ public class HttpInputTest _in.addContent(new TContent("CD")); _fillAndParseSimulate.offer("EF"); _fillAndParseSimulate.offer("GH"); - assertThat(_in.available(),equalTo(2)); - assertThat(_in.isFinished(),equalTo(false)); - assertThat(_in.isReady(),equalTo(true)); + Assert.assertThat(_in.available(), Matchers.equalTo(2)); + Assert.assertThat(_in.isFinished(), Matchers.equalTo(false)); + Assert.assertThat(_in.isReady(), Matchers.equalTo(true)); + + Assert.assertThat(_in.getContentConsumed(), Matchers.equalTo(0L)); + Assert.assertThat(_in.read(), Matchers.equalTo((int)'A')); + Assert.assertThat(_in.getContentConsumed(), Matchers.equalTo(1L)); + Assert.assertThat(_in.read(), Matchers.equalTo((int)'B')); + Assert.assertThat(_in.getContentConsumed(), Matchers.equalTo(2L)); + + Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded AB")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); + Assert.assertThat(_in.read(), Matchers.equalTo((int)'C')); + Assert.assertThat(_in.read(), Matchers.equalTo((int)'D')); + + Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded CD")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); + Assert.assertThat(_in.read(), Matchers.equalTo((int)'E')); - assertThat(_in.getContentConsumed(),equalTo(0L)); - assertThat(_in.read(),equalTo((int)'A')); - assertThat(_in.getContentConsumed(),equalTo(1L)); - assertThat(_in.read(),equalTo((int)'B')); - assertThat(_in.getContentConsumed(),equalTo(2L)); - - assertThat(_history.poll(),equalTo("Content succeeded AB")); - assertThat(_history.poll(),nullValue()); - assertThat(_in.read(),equalTo((int)'C')); - assertThat(_in.read(),equalTo((int)'D')); - - assertThat(_history.poll(),equalTo("Content succeeded CD")); - assertThat(_history.poll(),nullValue()); - assertThat(_in.read(),equalTo((int)'E')); - _in.prependContent(new HttpInput.Content(BufferUtil.toBuffer("abcde"))); - assertThat(_in.available(),equalTo(5)); - assertThat(_in.isFinished(),equalTo(false)); - assertThat(_in.isReady(),equalTo(true)); + Assert.assertThat(_in.available(), Matchers.equalTo(5)); + Assert.assertThat(_in.isFinished(), Matchers.equalTo(false)); + Assert.assertThat(_in.isReady(), Matchers.equalTo(true)); - assertThat(_in.getContentConsumed(),equalTo(0L)); - assertThat(_in.read(),equalTo((int)'a')); - assertThat(_in.getContentConsumed(),equalTo(1L)); - assertThat(_in.read(),equalTo((int)'b')); - assertThat(_in.getContentConsumed(),equalTo(2L)); - assertThat(_in.read(),equalTo((int)'c')); - assertThat(_in.read(),equalTo((int)'d')); - assertThat(_in.read(),equalTo((int)'e')); - - - - assertThat(_in.read(),equalTo((int)'F')); + Assert.assertThat(_in.getContentConsumed(), Matchers.equalTo(0L)); + Assert.assertThat(_in.read(), Matchers.equalTo((int)'a')); + Assert.assertThat(_in.getContentConsumed(), Matchers.equalTo(1L)); + Assert.assertThat(_in.read(), Matchers.equalTo((int)'b')); + Assert.assertThat(_in.getContentConsumed(), Matchers.equalTo(2L)); + Assert.assertThat(_in.read(), Matchers.equalTo((int)'c')); + Assert.assertThat(_in.read(), Matchers.equalTo((int)'d')); + Assert.assertThat(_in.read(), Matchers.equalTo((int)'e')); - assertThat(_history.poll(),equalTo("produceContent 2")); - assertThat(_history.poll(),equalTo("Content succeeded EF")); - assertThat(_history.poll(),nullValue()); - - assertThat(_in.read(),equalTo((int)'G')); - assertThat(_in.read(),equalTo((int)'H')); - - assertThat(_history.poll(),equalTo("Content succeeded GH")); - assertThat(_history.poll(),nullValue()); - - assertThat(_in.getContentConsumed(),equalTo(8L)); - - assertThat(_history.poll(),nullValue()); + Assert.assertThat(_in.read(), Matchers.equalTo((int)'F')); + + Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 2")); + Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded EF")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); + + Assert.assertThat(_in.read(), Matchers.equalTo((int)'G')); + Assert.assertThat(_in.read(), Matchers.equalTo((int)'H')); + + Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded GH")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); + + Assert.assertThat(_in.getContentConsumed(), Matchers.equalTo(8L)); + + Assert.assertThat(_history.poll(), Matchers.nullValue()); } - + @Test public void testBlockingRead() throws Exception { new Thread() { - public void run() + public void run() { try { Thread.sleep(500); _in.addContent(new TContent("AB")); } - catch(Throwable th) + catch (Throwable th) { th.printStackTrace(); } } }.start(); - - assertThat(_in.read(),equalTo((int)'A')); - - assertThat(_history.poll(),equalTo("produceContent 0")); - assertThat(_history.poll(),equalTo("blockForContent")); - assertThat(_history.poll(),nullValue()); - - assertThat(_in.read(),equalTo((int)'B')); - - assertThat(_history.poll(),equalTo("Content succeeded AB")); - assertThat(_history.poll(),nullValue()); + + Assert.assertThat(_in.read(), Matchers.equalTo((int)'A')); + + Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 0")); + Assert.assertThat(_history.poll(), Matchers.equalTo("blockForContent")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); + + Assert.assertThat(_in.read(), Matchers.equalTo((int)'B')); + + Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded AB")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); } @Test @@ -320,26 +299,26 @@ public class HttpInputTest _in.addContent(new TContent("CD")); _in.eof(); - assertThat(_in.isFinished(),equalTo(false)); - assertThat(_in.available(),equalTo(2)); - assertThat(_in.isFinished(),equalTo(false)); + Assert.assertThat(_in.isFinished(), Matchers.equalTo(false)); + Assert.assertThat(_in.available(), Matchers.equalTo(2)); + Assert.assertThat(_in.isFinished(), Matchers.equalTo(false)); - assertThat(_in.read(),equalTo((int)'A')); - assertThat(_in.read(),equalTo((int)'B')); - assertThat(_history.poll(),equalTo("Content succeeded AB")); - assertThat(_history.poll(),nullValue()); - - assertThat(_in.read(),equalTo((int)'C')); - assertThat(_in.isFinished(),equalTo(false)); - assertThat(_in.read(),equalTo((int)'D')); - assertThat(_history.poll(),equalTo("Content succeeded CD")); - assertThat(_history.poll(),nullValue()); - assertThat(_in.isFinished(),equalTo(false)); - - assertThat(_in.read(),equalTo(-1)); - assertThat(_in.isFinished(),equalTo(true)); - - assertThat(_history.poll(),nullValue()); + Assert.assertThat(_in.read(), Matchers.equalTo((int)'A')); + Assert.assertThat(_in.read(), Matchers.equalTo((int)'B')); + Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded AB")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); + + Assert.assertThat(_in.read(), Matchers.equalTo((int)'C')); + Assert.assertThat(_in.isFinished(), Matchers.equalTo(false)); + Assert.assertThat(_in.read(), Matchers.equalTo((int)'D')); + Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded CD")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); + Assert.assertThat(_in.isFinished(), Matchers.equalTo(false)); + + Assert.assertThat(_in.read(), Matchers.equalTo(-1)); + Assert.assertThat(_in.isFinished(), Matchers.equalTo(true)); + + Assert.assertThat(_history.poll(), Matchers.nullValue()); } @Test @@ -349,256 +328,251 @@ public class HttpInputTest _in.addContent(new TContent("CD")); _in.earlyEOF(); - assertThat(_in.isFinished(),equalTo(false)); - assertThat(_in.available(),equalTo(2)); - assertThat(_in.isFinished(),equalTo(false)); + Assert.assertThat(_in.isFinished(), Matchers.equalTo(false)); + Assert.assertThat(_in.available(), Matchers.equalTo(2)); + Assert.assertThat(_in.isFinished(), Matchers.equalTo(false)); + + Assert.assertThat(_in.read(), Matchers.equalTo((int)'A')); + Assert.assertThat(_in.read(), Matchers.equalTo((int)'B')); + + Assert.assertThat(_in.read(), Matchers.equalTo((int)'C')); + Assert.assertThat(_in.isFinished(), Matchers.equalTo(false)); + Assert.assertThat(_in.read(), Matchers.equalTo((int)'D')); - assertThat(_in.read(),equalTo((int)'A')); - assertThat(_in.read(),equalTo((int)'B')); - - assertThat(_in.read(),equalTo((int)'C')); - assertThat(_in.isFinished(),equalTo(false)); - assertThat(_in.read(),equalTo((int)'D')); - try { _in.read(); - fail(); + Assert.fail(); } - catch(EOFException eof) + catch (EOFException eof) { - assertThat(_in.isFinished(),equalTo(true)); + Assert.assertThat(_in.isFinished(), Matchers.equalTo(true)); } - assertThat(_history.poll(),equalTo("Content succeeded AB")); - assertThat(_history.poll(),equalTo("Content succeeded CD")); - assertThat(_history.poll(),nullValue()); + Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded AB")); + Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded CD")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); } - + @Test public void testBlockingEOF() throws Exception { new Thread() { - public void run() + public void run() { try { Thread.sleep(500); _in.eof(); } - catch(Throwable th) + catch (Throwable th) { th.printStackTrace(); } } }.start(); - assertThat(_in.isFinished(),equalTo(false)); - assertThat(_in.read(),equalTo(-1)); - assertThat(_in.isFinished(),equalTo(true)); - - assertThat(_history.poll(),equalTo("produceContent 0")); - assertThat(_history.poll(),equalTo("blockForContent")); - assertThat(_history.poll(),nullValue()); + Assert.assertThat(_in.isFinished(), Matchers.equalTo(false)); + Assert.assertThat(_in.read(), Matchers.equalTo(-1)); + Assert.assertThat(_in.isFinished(), Matchers.equalTo(true)); + + Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 0")); + Assert.assertThat(_history.poll(), Matchers.equalTo("blockForContent")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); } - + @Test public void testAsyncEmpty() throws Exception { _in.setReadListener(_listener); - assertThat(_history.poll(),equalTo("produceContent 0")); - assertThat(_history.poll(),equalTo("unready")); - assertThat(_history.poll(),nullValue()); - - _in.run(); - assertThat(_history.poll(),equalTo("onDataAvailable")); - assertThat(_history.poll(),nullValue()); + Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 0")); + Assert.assertThat(_history.poll(), Matchers.equalTo("unready")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); - assertThat(_in.isReady(),equalTo(false)); - assertThat(_history.poll(),equalTo("produceContent 0")); - assertThat(_history.poll(),equalTo("unready")); - assertThat(_history.poll(),nullValue()); - - assertThat(_in.isReady(),equalTo(false)); - assertThat(_history.poll(),equalTo("produceContent 0")); - assertThat(_history.poll(),equalTo("unready")); - assertThat(_history.poll(),nullValue()); + _in.run(); + Assert.assertThat(_history.poll(), Matchers.equalTo("onDataAvailable")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); + + Assert.assertThat(_in.isReady(), Matchers.equalTo(false)); + Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 0")); + Assert.assertThat(_history.poll(), Matchers.equalTo("unready")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); + + Assert.assertThat(_in.isReady(), Matchers.equalTo(false)); + Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 0")); + Assert.assertThat(_history.poll(), Matchers.equalTo("unready")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); } - @Test public void testAsyncRead() throws Exception { _in.setReadListener(_listener); - assertThat(_history.poll(),equalTo("produceContent 0")); - assertThat(_history.poll(),equalTo("unready")); - assertThat(_history.poll(),nullValue()); - - _in.run(); - assertThat(_history.poll(),equalTo("onDataAvailable")); - assertThat(_history.poll(),nullValue()); + Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 0")); + Assert.assertThat(_history.poll(), Matchers.equalTo("unready")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); + + _in.run(); + Assert.assertThat(_history.poll(), Matchers.equalTo("onDataAvailable")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); + + Assert.assertThat(_in.isReady(), Matchers.equalTo(false)); + Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 0")); + Assert.assertThat(_history.poll(), Matchers.equalTo("unready")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); - assertThat(_in.isReady(),equalTo(false)); - assertThat(_history.poll(),equalTo("produceContent 0")); - assertThat(_history.poll(),equalTo("unready")); - assertThat(_history.poll(),nullValue()); - _in.addContent(new TContent("AB")); _fillAndParseSimulate.add("CD"); - - assertThat(_history.poll(),equalTo("onReadPossible")); - assertThat(_history.poll(),nullValue()); + + Assert.assertThat(_history.poll(), Matchers.equalTo("onReadPossible")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); _in.run(); - assertThat(_history.poll(),equalTo("onDataAvailable")); - assertThat(_history.poll(),nullValue()); + Assert.assertThat(_history.poll(), Matchers.equalTo("onDataAvailable")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); - assertThat(_in.isReady(),equalTo(true)); - assertThat(_in.read(),equalTo((int)'A')); - - assertThat(_in.isReady(),equalTo(true)); - assertThat(_in.read(),equalTo((int)'B')); + Assert.assertThat(_in.isReady(), Matchers.equalTo(true)); + Assert.assertThat(_in.read(), Matchers.equalTo((int)'A')); - assertThat(_history.poll(),equalTo("Content succeeded AB")); - assertThat(_history.poll(),nullValue()); - - assertThat(_in.isReady(),equalTo(true)); - assertThat(_history.poll(),equalTo("produceContent 1")); - assertThat(_history.poll(),equalTo("onReadPossible")); - assertThat(_history.poll(),nullValue()); + Assert.assertThat(_in.isReady(), Matchers.equalTo(true)); + Assert.assertThat(_in.read(), Matchers.equalTo((int)'B')); - assertThat(_in.read(),equalTo((int)'C')); - - assertThat(_in.isReady(),equalTo(true)); - assertThat(_in.read(),equalTo((int)'D')); - assertThat(_history.poll(),equalTo("Content succeeded CD")); - assertThat(_history.poll(),nullValue()); - + Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded AB")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); - assertThat(_in.isReady(),equalTo(false)); - assertThat(_history.poll(),equalTo("produceContent 0")); - assertThat(_history.poll(),equalTo("unready")); - assertThat(_history.poll(),nullValue()); + Assert.assertThat(_in.isReady(), Matchers.equalTo(true)); + Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 1")); + Assert.assertThat(_history.poll(), Matchers.equalTo("onReadPossible")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); + + Assert.assertThat(_in.read(), Matchers.equalTo((int)'C')); + + Assert.assertThat(_in.isReady(), Matchers.equalTo(true)); + Assert.assertThat(_in.read(), Matchers.equalTo((int)'D')); + Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded CD")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); + + Assert.assertThat(_in.isReady(), Matchers.equalTo(false)); + Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 0")); + Assert.assertThat(_history.poll(), Matchers.equalTo("unready")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); } - + @Test public void testAsyncEOF() throws Exception { _in.setReadListener(_listener); - assertThat(_history.poll(),equalTo("produceContent 0")); - assertThat(_history.poll(),equalTo("unready")); - assertThat(_history.poll(),nullValue()); + Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 0")); + Assert.assertThat(_history.poll(), Matchers.equalTo("unready")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); _in.run(); - assertThat(_history.poll(),equalTo("onDataAvailable")); - assertThat(_history.poll(),nullValue()); + Assert.assertThat(_history.poll(), Matchers.equalTo("onDataAvailable")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); _in.eof(); - assertThat(_in.isReady(),equalTo(true)); - assertThat(_in.isFinished(),equalTo(false)); - assertThat(_history.poll(),equalTo("onReadPossible")); - assertThat(_history.poll(),nullValue()); + Assert.assertThat(_in.isReady(), Matchers.equalTo(true)); + Assert.assertThat(_in.isFinished(), Matchers.equalTo(false)); + Assert.assertThat(_history.poll(), Matchers.equalTo("onReadPossible")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); - assertThat(_in.read(),equalTo(-1)); - assertThat(_in.isFinished(),equalTo(true)); - assertThat(_history.poll(),equalTo("ready")); - assertThat(_history.poll(),nullValue()); + Assert.assertThat(_in.read(), Matchers.equalTo(-1)); + Assert.assertThat(_in.isFinished(), Matchers.equalTo(true)); + Assert.assertThat(_history.poll(), Matchers.equalTo("ready")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); } - + @Test public void testAsyncReadEOF() throws Exception { _in.setReadListener(_listener); - assertThat(_history.poll(),equalTo("produceContent 0")); - assertThat(_history.poll(),equalTo("unready")); - assertThat(_history.poll(),nullValue()); - - _in.run(); - assertThat(_history.poll(),equalTo("onDataAvailable")); - assertThat(_history.poll(),nullValue()); + Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 0")); + Assert.assertThat(_history.poll(), Matchers.equalTo("unready")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); + + _in.run(); + Assert.assertThat(_history.poll(), Matchers.equalTo("onDataAvailable")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); + + Assert.assertThat(_in.isReady(), Matchers.equalTo(false)); + Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 0")); + Assert.assertThat(_history.poll(), Matchers.equalTo("unready")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); - assertThat(_in.isReady(),equalTo(false)); - assertThat(_history.poll(),equalTo("produceContent 0")); - assertThat(_history.poll(),equalTo("unready")); - assertThat(_history.poll(),nullValue()); - _in.addContent(new TContent("AB")); _fillAndParseSimulate.add("_EOF_"); - - assertThat(_history.poll(),equalTo("onReadPossible")); - assertThat(_history.poll(),nullValue()); - + + Assert.assertThat(_history.poll(), Matchers.equalTo("onReadPossible")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); + _in.run(); - assertThat(_history.poll(),equalTo("onDataAvailable")); - assertThat(_history.poll(),nullValue()); + Assert.assertThat(_history.poll(), Matchers.equalTo("onDataAvailable")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); - assertThat(_in.isReady(),equalTo(true)); - assertThat(_in.read(),equalTo((int)'A')); - - assertThat(_in.isReady(),equalTo(true)); - assertThat(_in.read(),equalTo((int)'B')); + Assert.assertThat(_in.isReady(), Matchers.equalTo(true)); + Assert.assertThat(_in.read(), Matchers.equalTo((int)'A')); - assertThat(_history.poll(),equalTo("Content succeeded AB")); - assertThat(_history.poll(),nullValue()); + Assert.assertThat(_in.isReady(), Matchers.equalTo(true)); + Assert.assertThat(_in.read(), Matchers.equalTo((int)'B')); - assertThat(_in.isFinished(),equalTo(false)); - assertThat(_in.isReady(),equalTo(true)); - assertThat(_history.poll(),equalTo("produceContent 1")); - assertThat(_history.poll(),equalTo("onReadPossible")); - assertThat(_history.poll(),nullValue()); + Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded AB")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); - assertThat(_in.isFinished(),equalTo(false)); - assertThat(_in.read(),equalTo(-1)); - assertThat(_in.isFinished(),equalTo(true)); - assertThat(_history.poll(),equalTo("ready")); - assertThat(_history.poll(),nullValue()); - - assertThat(_in.isReady(),equalTo(true)); - assertThat(_history.poll(),nullValue()); + Assert.assertThat(_in.isFinished(), Matchers.equalTo(false)); + Assert.assertThat(_in.isReady(), Matchers.equalTo(true)); + Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 1")); + Assert.assertThat(_history.poll(), Matchers.equalTo("onReadPossible")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); + Assert.assertThat(_in.isFinished(), Matchers.equalTo(false)); + Assert.assertThat(_in.read(), Matchers.equalTo(-1)); + Assert.assertThat(_in.isFinished(), Matchers.equalTo(true)); + Assert.assertThat(_history.poll(), Matchers.equalTo("ready")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); + + Assert.assertThat(_in.isReady(), Matchers.equalTo(true)); + Assert.assertThat(_history.poll(), Matchers.nullValue()); } - @Test public void testAsyncError() throws Exception { _in.setReadListener(_listener); - assertThat(_history.poll(),equalTo("produceContent 0")); - assertThat(_history.poll(),equalTo("unready")); - assertThat(_history.poll(),nullValue()); + Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 0")); + Assert.assertThat(_history.poll(), Matchers.equalTo("unready")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); _in.run(); - assertThat(_history.poll(),equalTo("onDataAvailable")); - assertThat(_history.poll(),nullValue()); + Assert.assertThat(_history.poll(), Matchers.equalTo("onDataAvailable")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); + + Assert.assertThat(_in.isReady(), Matchers.equalTo(false)); + Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 0")); + Assert.assertThat(_history.poll(), Matchers.equalTo("unready")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); - assertThat(_in.isReady(),equalTo(false)); - assertThat(_history.poll(),equalTo("produceContent 0")); - assertThat(_history.poll(),equalTo("unready")); - assertThat(_history.poll(),nullValue()); - _in.failed(new TimeoutException()); - assertThat(_history.poll(),equalTo("onReadPossible")); - assertThat(_history.poll(),nullValue()); - - _in.run(); - assertThat(_in.isFinished(),equalTo(true)); - assertThat(_history.poll(),equalTo("onError:java.util.concurrent.TimeoutException")); - assertThat(_history.poll(),nullValue()); + Assert.assertThat(_history.poll(), Matchers.equalTo("onReadPossible")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); - assertThat(_in.isReady(),equalTo(true)); + _in.run(); + Assert.assertThat(_in.isFinished(), Matchers.equalTo(true)); + Assert.assertThat(_history.poll(), Matchers.equalTo("onError:java.util.concurrent.TimeoutException")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); + + Assert.assertThat(_in.isReady(), Matchers.equalTo(true)); try { _in.read(); - fail(); + Assert.fail(); } - catch(IOException e) + catch (IOException e) { - assertThat(e.getCause(),Matchers.instanceOf(TimeoutException.class)); - assertThat(_in.isFinished(),equalTo(true)); + Assert.assertThat(e.getCause(), Matchers.instanceOf(TimeoutException.class)); + Assert.assertThat(_in.isFinished(), Matchers.equalTo(true)); } - assertThat(_history.poll(),nullValue()); + Assert.assertThat(_history.poll(), Matchers.nullValue()); } - @Test public void testRecycle() throws Exception @@ -609,7 +583,7 @@ public class HttpInputTest _in.recycle(); testReadEOF(); } - + @Test public void testConsumeAll() throws Exception { @@ -617,20 +591,20 @@ public class HttpInputTest _in.addContent(new TContent("CD")); _fillAndParseSimulate.offer("EF"); _fillAndParseSimulate.offer("GH"); - assertThat(_in.read(),equalTo((int)'A')); - - assertFalse(_in.consumeAll()); - assertThat(_in.getContentConsumed(),equalTo(8L)); + Assert.assertThat(_in.read(), Matchers.equalTo((int)'A')); - assertThat(_history.poll(),equalTo("Content succeeded AB")); - assertThat(_history.poll(),equalTo("Content succeeded CD")); - assertThat(_history.poll(),equalTo("produceContent 2")); - assertThat(_history.poll(),equalTo("Content succeeded EF")); - assertThat(_history.poll(),equalTo("Content succeeded GH")); - assertThat(_history.poll(),equalTo("produceContent 0")); - assertThat(_history.poll(),nullValue()); + Assert.assertFalse(_in.consumeAll()); + Assert.assertThat(_in.getContentConsumed(), Matchers.equalTo(8L)); + + Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded AB")); + Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded CD")); + Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 2")); + Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded EF")); + Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded GH")); + Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 0")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); } - + @Test public void testConsumeAllEOF() throws Exception { @@ -639,16 +613,16 @@ public class HttpInputTest _fillAndParseSimulate.offer("EF"); _fillAndParseSimulate.offer("GH"); _fillAndParseSimulate.offer("_EOF_"); - assertThat(_in.read(),equalTo((int)'A')); - - assertTrue(_in.consumeAll()); - assertThat(_in.getContentConsumed(),equalTo(8L)); + Assert.assertThat(_in.read(), Matchers.equalTo((int)'A')); - assertThat(_history.poll(),equalTo("Content succeeded AB")); - assertThat(_history.poll(),equalTo("Content succeeded CD")); - assertThat(_history.poll(),equalTo("produceContent 3")); - assertThat(_history.poll(),equalTo("Content succeeded EF")); - assertThat(_history.poll(),equalTo("Content succeeded GH")); - assertThat(_history.poll(),nullValue()); + Assert.assertTrue(_in.consumeAll()); + Assert.assertThat(_in.getContentConsumed(), Matchers.equalTo(8L)); + + Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded AB")); + Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded CD")); + Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 3")); + Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded EF")); + Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded GH")); + Assert.assertThat(_history.poll(), Matchers.nullValue()); } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java index a7e7f8cdbe4..d22b4c896f3 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java @@ -867,12 +867,12 @@ public class ResponseTest assertEquals("minimal=value",fields.get("Set-Cookie")); fields.clear(); - //test cookies with same name, domain and path, only 1 allowed - response.addSetCookie("everything","wrong","domain","path",0,"to be replaced",true,true,0); + //test cookies with same name, domain and path + response.addSetCookie("everything","something","domain","path",0,"noncomment",true,true,0); response.addSetCookie("everything","value","domain","path",0,"comment",true,true,0); - assertEquals("everything=value;Version=1;Path=path;Domain=domain;Expires=Thu, 01-Jan-1970 00:00:00 GMT;Max-Age=0;Secure;HttpOnly;Comment=comment",fields.get("Set-Cookie")); Enumeration e =fields.getValues("Set-Cookie"); assertTrue(e.hasMoreElements()); + assertEquals("everything=something;Version=1;Path=path;Domain=domain;Expires=Thu, 01-Jan-1970 00:00:00 GMT;Max-Age=0;Secure;HttpOnly;Comment=noncomment",e.nextElement()); assertEquals("everything=value;Version=1;Path=path;Domain=domain;Expires=Thu, 01-Jan-1970 00:00:00 GMT;Max-Age=0;Secure;HttpOnly;Comment=comment",e.nextElement()); assertFalse(e.hasMoreElements()); assertEquals("Thu, 01 Jan 1970 00:00:00 GMT",fields.get("Expires")); @@ -929,6 +929,7 @@ public class ResponseTest response.addSetCookie("everything","value","","",0,"comment",true,true,0); e =fields.getValues("Set-Cookie"); assertTrue(e.hasMoreElements()); + assertEquals("everything=other;Version=1;Expires=Thu, 01-Jan-1970 00:00:00 GMT;Max-Age=0;Secure;HttpOnly;Comment=blah",e.nextElement()); assertEquals("everything=value;Version=1;Expires=Thu, 01-Jan-1970 00:00:00 GMT;Max-Age=0;Secure;HttpOnly;Comment=comment",e.nextElement()); assertFalse(e.hasMoreElements()); @@ -953,16 +954,17 @@ public class ResponseTest fields.clear(); response.addSetCookie("name","value","domain",null,-1,null,false,false,-1); response.addSetCookie("name","other","domain",null,-1,null,false,false,-1); - assertEquals("name=other;Domain=domain",fields.get("Set-Cookie")); response.addSetCookie("name","more","domain",null,-1,null,false,false,-1); - assertEquals("name=more;Domain=domain",fields.get("Set-Cookie")); + e = fields.getValues("Set-Cookie"); + assertTrue(e.hasMoreElements()); + assertThat(e.nextElement(), Matchers.startsWith("name=value")); + assertThat(e.nextElement(), Matchers.startsWith("name=other")); + assertThat(e.nextElement(), Matchers.startsWith("name=more")); + response.addSetCookie("foo","bar","domain",null,-1,null,false,false,-1); response.addSetCookie("foo","bob","domain",null,-1,null,false,false,-1); - assertEquals("name=more;Domain=domain",fields.get("Set-Cookie")); + assertThat(fields.get("Set-Cookie"), Matchers.startsWith("name=value")); - e=fields.getValues("Set-Cookie"); - assertEquals("name=more;Domain=domain",e.nextElement()); - assertEquals("foo=bob;Domain=domain",e.nextElement()); fields.clear(); response.addSetCookie("name","value%=",null,null,-1,null,false,false,0); diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ServerConnectorTimeoutTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ServerConnectorTimeoutTest.java index bfc0b16edb4..98bc92de45f 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ServerConnectorTimeoutTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ServerConnectorTimeoutTest.java @@ -18,27 +18,37 @@ package org.eclipse.jetty.server; -import static org.junit.Assert.assertTrue; - import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.Socket; import java.nio.charset.StandardCharsets; import java.util.Locale; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.session.SessionHandler; import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.log.StacklessLogging; +import org.hamcrest.Matchers; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import static org.hamcrest.Matchers.containsString; +import static org.junit.Assert.assertTrue; + public class ServerConnectorTimeoutTest extends ConnectorTimeoutTest { @Before public void init() throws Exception { ServerConnector connector = new ServerConnector(_server,1,1); - connector.setIdleTimeout(MAX_IDLE_TIME); // 250 msec max idle + connector.setIdleTimeout(MAX_IDLE_TIME); startServer(connector); } @@ -113,4 +123,49 @@ public class ServerConnectorTimeoutTest extends ConnectorTimeoutTest return response; } } + + @Test + public void testHttpWriteIdleTimeout() throws Exception + { + _httpConfiguration.setBlockingTimeout(500); + configureServer(new AbstractHandler() + { + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + baseRequest.setHandled(true); + IO.copy(request.getInputStream(), response.getOutputStream()); + } + }); + Socket client=newSocket(_serverURI.getHost(),_serverURI.getPort()); + client.setSoTimeout(10000); + + Assert.assertFalse(client.isClosed()); + + OutputStream os=client.getOutputStream(); + InputStream is=client.getInputStream(); + + try (StacklessLogging scope = new StacklessLogging(HttpChannel.class)) + { + os.write(( + "POST /echo HTTP/1.0\r\n"+ + "host: "+_serverURI.getHost()+":"+_serverURI.getPort()+"\r\n"+ + "content-type: text/plain; charset=utf-8\r\n"+ + "content-length: 20\r\n"+ + "\r\n").getBytes("utf-8")); + os.flush(); + + os.write("123456789\n".getBytes("utf-8")); + os.flush(); + Thread.sleep(1000); + os.write("=========\n".getBytes("utf-8")); + os.flush(); + + Thread.sleep(2000); + + String response =IO.toString(is); + Assert.assertThat(response,containsString(" 500 ")); + Assert.assertThat(response, Matchers.not(containsString("========="))); + } + } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ShutdownMonitorTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ShutdownMonitorTest.java index f0e4e7f1f67..3bb2ee8ec0b 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ShutdownMonitorTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ShutdownMonitorTest.java @@ -18,6 +18,7 @@ package org.eclipse.jetty.server; +import java.io.BufferedReader; import java.io.Closeable; import java.io.InputStreamReader; import java.io.LineNumberReader; @@ -26,7 +27,8 @@ import java.net.InetAddress; import java.net.Socket; import org.eclipse.jetty.util.thread.ShutdownThread; -import org.junit.AfterClass; +import org.junit.After; +import org.junit.Assert; import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -34,14 +36,55 @@ import static org.junit.Assert.assertTrue; public class ShutdownMonitorTest { - @AfterClass - public static void afterClass() + @After + public void dispose() { ShutdownMonitor.reset(); } - + @Test - public void testShutdownMonitor() throws Exception + public void testStatus() throws Exception + { + ShutdownMonitor monitor = ShutdownMonitor.getInstance(); + monitor.setDebug(true); + monitor.setPort(0); + monitor.setExitVm(false); + monitor.start(); + String key = monitor.getKey(); + int port = monitor.getPort(); + + // Try more than once to be sure that the ServerSocket has not been closed. + for (int i = 0; i < 2; ++i) + { + try (Socket socket = new Socket("localhost", port)) + { + OutputStream output = socket.getOutputStream(); + String command = "status"; + output.write((key + "\r\n" + command + "\r\n").getBytes()); + output.flush(); + + BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream())); + String reply = input.readLine(); + assertEquals("OK", reply); + // Socket must be closed afterwards. + Assert.assertNull(input.readLine()); + } + } + } + + @Test + public void testStartStopDifferentPortDifferentKey() throws Exception + { + testStartStop(false); + } + + @Test + public void testStartStopSamePortDifferentKey() throws Exception + { + testStartStop(true); + } + + private void testStartStop(boolean reusePort) throws Exception { ShutdownMonitor monitor = ShutdownMonitor.getInstance(); monitor.setDebug(true); @@ -58,8 +101,8 @@ public class ShutdownMonitorTest monitor.await(); assertTrue(!monitor.isAlive()); - // should be able to change port and key because it is stopped - monitor.setPort(0); + // Should be able to change port and key because it is stopped. + monitor.setPort(reusePort ? port : 0); String newKey = "foo"; monitor.setKey(newKey); monitor.start(); @@ -78,8 +121,12 @@ public class ShutdownMonitorTest public void testForceStopCommand() throws Exception { ShutdownMonitor monitor = ShutdownMonitor.getInstance(); + monitor.setDebug(true); monitor.setPort(0); - try(CloseableServer server = new CloseableServer()) + monitor.setExitVm(false); + monitor.start(); + + try (CloseableServer server = new CloseableServer()) { server.start(); @@ -105,10 +152,12 @@ public class ShutdownMonitorTest public void testOldStopCommandWithStopOnShutdownTrue() throws Exception { ShutdownMonitor monitor = ShutdownMonitor.getInstance(); - monitor.setExitVm(false); - + monitor.setDebug(true); monitor.setPort(0); - try(CloseableServer server = new CloseableServer()) + monitor.setExitVm(false); + monitor.start(); + + try (CloseableServer server = new CloseableServer()) { server.setStopAtShutdown(true); server.start(); @@ -135,9 +184,12 @@ public class ShutdownMonitorTest public void testOldStopCommandWithStopOnShutdownFalse() throws Exception { ShutdownMonitor monitor = ShutdownMonitor.getInstance(); - monitor.setExitVm(false); + monitor.setDebug(true); monitor.setPort(0); - try(CloseableServer server = new CloseableServer()) + monitor.setExitVm(false); + monitor.start(); + + try (CloseableServer server = new CloseableServer()) { server.setStopAtShutdown(false); server.start(); @@ -222,7 +274,6 @@ public class ShutdownMonitorTest { throw new RuntimeException(e); } - } } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/StatisticsHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/StatisticsHandlerTest.java index e56e3de5b34..9dcf01f9ead 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/StatisticsHandlerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/StatisticsHandlerTest.java @@ -18,12 +18,6 @@ package org.eclipse.jetty.server.handler; -import static org.hamcrest.Matchers.greaterThanOrEqualTo; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - import java.io.IOException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.CyclicBarrier; @@ -37,7 +31,7 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.eclipse.jetty.server.ConnectorStatistics; +import org.eclipse.jetty.io.ConnectionStatistics; import org.eclipse.jetty.server.LocalConnector; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; @@ -45,10 +39,16 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + public class StatisticsHandlerTest { private Server _server; - private ConnectorStatistics _statistics; + private ConnectionStatistics _statistics; private LocalConnector _connector; private LatchHandler _latchHandler; private StatisticsHandler _statsHandler; @@ -59,7 +59,7 @@ public class StatisticsHandlerTest _server = new Server(); _connector = new LocalConnector(_server); - _statistics = new ConnectorStatistics(); + _statistics = new ConnectionStatistics(); _connector.addBean(_statistics); _server.addConnector(_connector); @@ -110,7 +110,7 @@ public class StatisticsHandlerTest barrier[0].await(); - assertEquals(1, _statistics.getConnectionsOpen()); + assertEquals(1, _statistics.getConnections()); assertEquals(1, _statsHandler.getRequests()); assertEquals(1, _statsHandler.getRequestsActive()); @@ -145,7 +145,7 @@ public class StatisticsHandlerTest barrier[0].await(); - assertEquals(2, _statistics.getConnectionsOpen()); + assertEquals(2, _statistics.getConnections()); assertEquals(2, _statsHandler.getRequests()); assertEquals(1, _statsHandler.getRequestsActive()); @@ -208,7 +208,7 @@ public class StatisticsHandlerTest barrier[0].await(); - assertEquals(2, _statistics.getConnectionsOpen()); + assertEquals(2, _statistics.getConnections()); assertEquals(2, _statsHandler.getRequests()); assertEquals(2, _statsHandler.getRequestsActive()); @@ -282,7 +282,7 @@ public class StatisticsHandlerTest barrier[0].await(); - assertEquals(1, _statistics.getConnectionsOpen()); + assertEquals(1, _statistics.getConnections()); assertEquals(1, _statsHandler.getRequests()); assertEquals(1, _statsHandler.getRequestsActive()); assertEquals(1, _statsHandler.getDispatched()); @@ -336,7 +336,7 @@ public class StatisticsHandlerTest barrier[0].await(); // entered app handler - assertEquals(1, _statistics.getConnectionsOpen()); + assertEquals(1, _statistics.getConnections()); assertEquals(1, _statsHandler.getRequests()); assertEquals(1, _statsHandler.getRequestsActive()); assertEquals(2, _statsHandler.getDispatched()); @@ -416,7 +416,7 @@ public class StatisticsHandlerTest barrier[0].await(); - assertEquals(1, _statistics.getConnectionsOpen()); + assertEquals(1, _statistics.getConnections()); assertEquals(1, _statsHandler.getRequests()); assertEquals(1, _statsHandler.getRequestsActive()); assertEquals(1, _statsHandler.getDispatched()); @@ -532,7 +532,7 @@ public class StatisticsHandlerTest barrier[0].await(); - assertEquals(1, _statistics.getConnectionsOpen()); + assertEquals(1, _statistics.getConnections()); assertEquals(1, _statsHandler.getRequests()); assertEquals(1, _statsHandler.getRequestsActive()); assertEquals(1, _statsHandler.getDispatched()); diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ThreadLimitHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ThreadLimitHandlerTest.java new file mode 100644 index 00000000000..a1436a503f2 --- /dev/null +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ThreadLimitHandlerTest.java @@ -0,0 +1,248 @@ +// +// ======================================================================== +// Copyright (c) 1995-2016 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.server.handler; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +import java.io.IOException; +import java.net.Socket; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.LocalConnector; +import org.eclipse.jetty.server.NetworkConnector; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.hamcrest.Matchers; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class ThreadLimitHandlerTest +{ + private Server _server; + private NetworkConnector _connector; + private LocalConnector _local; + + + @Before + public void before() + throws Exception + { + _server = new Server(); + _connector = new ServerConnector(_server); + _local = new LocalConnector(_server); + _server.setConnectors(new Connector[] { _local,_connector }); + + } + + @After + public void after() + throws Exception + { + _server.stop(); + } + + + @Test + public void testNoForwardHeaders() throws Exception + { + AtomicReference last = new AtomicReference<>(); + ThreadLimitHandler handler = new ThreadLimitHandler(null,false) + { + @Override + protected int getThreadLimit(String ip) + { + last.set(ip); + return super.getThreadLimit(ip); + } + }; + handler.setHandler(new AbstractHandler() + { + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + baseRequest.setHandled(true); + response.setStatus(HttpStatus.OK_200); + } + }); + _server.setHandler(handler); + _server.start(); + + last.set(null); + _local.getResponse("GET / HTTP/1.0\r\n\r\n"); + Assert.assertThat(last.get(),Matchers.is("0.0.0.0")); + + last.set(null); + _local.getResponse("GET / HTTP/1.0\r\nX-Forwarded-For: 1.2.3.4\r\n\r\n"); + Assert.assertThat(last.get(),Matchers.is("0.0.0.0")); + + last.set(null); + _local.getResponse("GET / HTTP/1.0\r\nForwarded: for=1.2.3.4\r\n\r\n"); + Assert.assertThat(last.get(),Matchers.is("0.0.0.0")); + } + + @Test + public void testXForwardForHeaders() throws Exception + { + AtomicReference last = new AtomicReference<>(); + ThreadLimitHandler handler = new ThreadLimitHandler("X-Forwarded-For") + { + @Override + protected int getThreadLimit(String ip) + { + last.set(ip); + return super.getThreadLimit(ip); + } + }; + _server.setHandler(handler); + _server.start(); + + last.set(null); + _local.getResponse("GET / HTTP/1.0\r\n\r\n"); + Assert.assertThat(last.get(),Matchers.is("0.0.0.0")); + + last.set(null); + _local.getResponse("GET / HTTP/1.0\r\nX-Forwarded-For: 1.2.3.4\r\n\r\n"); + Assert.assertThat(last.get(),Matchers.is("1.2.3.4")); + + last.set(null); + _local.getResponse("GET / HTTP/1.0\r\nForwarded: for=1.2.3.4\r\n\r\n"); + Assert.assertThat(last.get(),Matchers.is("0.0.0.0")); + + last.set(null); + _local.getResponse("GET / HTTP/1.0\r\nX-Forwarded-For: 1.1.1.1\r\nX-Forwarded-For: 6.6.6.6,1.2.3.4\r\nForwarded: for=1.2.3.4\r\n\r\n"); + Assert.assertThat(last.get(),Matchers.is("1.2.3.4")); + + } + + @Test + public void testForwardHeaders() throws Exception + { + AtomicReference last = new AtomicReference<>(); + ThreadLimitHandler handler = new ThreadLimitHandler("Forwarded") + { + @Override + protected int getThreadLimit(String ip) + { + last.set(ip); + return super.getThreadLimit(ip); + } + }; + _server.setHandler(handler); + _server.start(); + + last.set(null); + _local.getResponse("GET / HTTP/1.0\r\n\r\n"); + Assert.assertThat(last.get(),Matchers.is("0.0.0.0")); + + last.set(null); + _local.getResponse("GET / HTTP/1.0\r\nX-Forwarded-For: 1.2.3.4\r\n\r\n"); + Assert.assertThat(last.get(),Matchers.is("0.0.0.0")); + + last.set(null); + _local.getResponse("GET / HTTP/1.0\r\nForwarded: for=1.2.3.4\r\n\r\n"); + Assert.assertThat(last.get(),Matchers.is("1.2.3.4")); + + last.set(null); + _local.getResponse("GET / HTTP/1.0\r\nX-Forwarded-For: 1.1.1.1\r\nForwarded: for=6.6.6.6; for=1.2.3.4\r\nX-Forwarded-For: 6.6.6.6\r\nForwarded: proto=https\r\n\r\n"); + Assert.assertThat(last.get(),Matchers.is("1.2.3.4")); + } + + + + @Test + public void testLimit() throws Exception + { + ThreadLimitHandler handler = new ThreadLimitHandler("Forwarded"); + + handler.setThreadLimit(4); + + AtomicInteger count = new AtomicInteger(0); + AtomicInteger total = new AtomicInteger(0); + CountDownLatch latch = new CountDownLatch(1); + handler.setHandler(new AbstractHandler() + { + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + baseRequest.setHandled(true); + response.setStatus(HttpStatus.OK_200); + if ("/other".equals(target)) + return; + + try + { + count.incrementAndGet(); + total.incrementAndGet(); + latch.await(); + } + catch (InterruptedException e) + { + throw new ServletException(e); + } + finally + { + count.decrementAndGet(); + } + + } + }); + _server.setHandler(handler); + _server.start(); + + Socket[] client = new Socket[10]; + for (int i=0;i history = new ConcurrentArrayQueue<>(); + final Queue history = new LinkedBlockingQueue<>(); _connector.addBean(new SocketCustomizationListener() { diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslConnectionFactoryTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslConnectionFactoryTest.java index 32c244e3e90..4d32ed6788e 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslConnectionFactoryTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslConnectionFactoryTest.java @@ -28,6 +28,7 @@ import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.List; import java.util.Queue; +import java.util.concurrent.LinkedBlockingQueue; import javax.net.ssl.SNIHostName; import javax.net.ssl.SNIServerName; @@ -49,7 +50,6 @@ import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.SocketCustomizationListener; import org.eclipse.jetty.server.SslConnectionFactory; import org.eclipse.jetty.server.handler.AbstractHandler; -import org.eclipse.jetty.util.ConcurrentArrayQueue; import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.hamcrest.Matchers; @@ -198,8 +198,8 @@ public class SslConnectionFactoryTest @Test public void testSocketCustomization() throws Exception { - final Queue history = new ConcurrentArrayQueue<>(); - + final Queue history = new LinkedBlockingQueue<>(); + _connector.addBean(new SocketCustomizationListener() { @Override diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslContextFactoryReloadTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslContextFactoryReloadTest.java new file mode 100644 index 00000000000..c167f30ea96 --- /dev/null +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslContextFactoryReloadTest.java @@ -0,0 +1,265 @@ +// +// ======================================================================== +// Copyright (c) 1995-2016 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.server.ssl; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.http.HttpTester; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.HttpConnectionFactory; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.SecureRequestCustomizer; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.SslConnectionFactory; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler; +import org.eclipse.jetty.util.thread.Scheduler; +import org.hamcrest.Matchers; +import org.junit.After; +import org.junit.Assert; +import org.junit.Test; + +public class SslContextFactoryReloadTest +{ + public static final String KEYSTORE_1 = "src/test/resources/reload_keystore_1.jks"; + public static final String KEYSTORE_2 = "src/test/resources/reload_keystore_2.jks"; + + private Server server; + private SslContextFactory sslContextFactory; + private ServerConnector connector; + + private void start(Handler handler) throws Exception + { + server = new Server(); + + sslContextFactory = new SslContextFactory(); + sslContextFactory.setKeyStorePath(KEYSTORE_1); + sslContextFactory.setKeyStorePassword("storepwd"); + sslContextFactory.setKeyStoreType("JKS"); + sslContextFactory.setKeyStoreProvider(null); + + HttpConfiguration httpsConfig = new HttpConfiguration(); + httpsConfig.addCustomizer(new SecureRequestCustomizer()); + connector = new ServerConnector(server, + new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()), + new HttpConnectionFactory(httpsConfig)); + server.addConnector(connector); + + server.setHandler(handler); + + server.start(); + } + + @After + public void dispose() throws Exception + { + if (server != null) + server.stop(); + } + + @Test + public void testReload() throws Exception + { + start(new EchoHandler()); + + SSLContext ctx = SSLContext.getInstance("TLSv1.2"); + ctx.init(null, SslContextFactory.TRUST_ALL_CERTS, null); + SSLSocketFactory socketFactory = ctx.getSocketFactory(); + try (SSLSocket client1 = (SSLSocket)socketFactory.createSocket("localhost", connector.getLocalPort())) + { + String serverDN1 = client1.getSession().getPeerPrincipal().getName(); + Assert.assertThat(serverDN1, Matchers.startsWith("CN=localhost1")); + + String request = "" + + "GET / HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "\r\n"; + + OutputStream output1 = client1.getOutputStream(); + output1.write(request.getBytes(StandardCharsets.UTF_8)); + output1.flush(); + + HttpTester.Response response1 = HttpTester.parseResponse(HttpTester.from(client1.getInputStream())); + Assert.assertNotNull(response1); + Assert.assertThat(response1.getStatus(), Matchers.equalTo(HttpStatus.OK_200)); + + // Reconfigure SslContextFactory. + sslContextFactory.reload(sslContextFactory -> + { + sslContextFactory.setKeyStorePath(KEYSTORE_2); + sslContextFactory.setKeyStorePassword("storepwd"); + }); + + // New connection should use the new keystore. + try (SSLSocket client2 = (SSLSocket)socketFactory.createSocket("localhost", connector.getLocalPort())) + { + String serverDN2 = client2.getSession().getPeerPrincipal().getName(); + Assert.assertThat(serverDN2, Matchers.startsWith("CN=localhost2")); + + OutputStream output2 = client1.getOutputStream(); + output2.write(request.getBytes(StandardCharsets.UTF_8)); + output2.flush(); + + HttpTester.Response response2 = HttpTester.parseResponse(HttpTester.from(client1.getInputStream())); + Assert.assertNotNull(response2); + Assert.assertThat(response2.getStatus(), Matchers.equalTo(HttpStatus.OK_200)); + } + + // Must still be possible to make requests with the first connection. + output1.write(request.getBytes(StandardCharsets.UTF_8)); + output1.flush(); + + response1 = HttpTester.parseResponse(HttpTester.from(client1.getInputStream())); + Assert.assertNotNull(response1); + Assert.assertThat(response1.getStatus(), Matchers.equalTo(HttpStatus.OK_200)); + } + } + + @Test + public void testReloadWhileServing() throws Exception + { + start(new EchoHandler()); + + Scheduler scheduler = new ScheduledExecutorScheduler(); + scheduler.start(); + try + { + SSLContext ctx = SSLContext.getInstance("TLSv1.2"); + ctx.init(null, SslContextFactory.TRUST_ALL_CERTS, null); + SSLSocketFactory socketFactory = ctx.getSocketFactory(); + + // Perform 4 reloads while connections are being served. + AtomicInteger reloads = new AtomicInteger(4); + long reloadPeriod = 500; + AtomicBoolean running = new AtomicBoolean(true); + scheduler.schedule(new Runnable() + { + @Override + public void run() + { + if (reloads.decrementAndGet() == 0) + { + running.set(false); + } + else + { + try + { + sslContextFactory.reload(sslContextFactory -> + { + if (sslContextFactory.getKeyStorePath().endsWith(KEYSTORE_1)) + sslContextFactory.setKeyStorePath(KEYSTORE_2); + else + sslContextFactory.setKeyStorePath(KEYSTORE_1); + }); + scheduler.schedule(this, reloadPeriod, TimeUnit.MILLISECONDS); + } + catch (Exception x) + { + running.set(false); + reloads.set(-1); + } + } + } + }, reloadPeriod, TimeUnit.MILLISECONDS); + + byte[] content = new byte[16 * 1024]; + while (running.get()) + { + try (SSLSocket client = (SSLSocket)socketFactory.createSocket("localhost", connector.getLocalPort())) + { + // We need to invalidate the session every time we open a new SSLSocket. + // This is because when the client uses session resumption, it caches + // the server certificates and then checks that it is the same during + // a new TLS handshake. If the SslContextFactory is reloaded during the + // TLS handshake, the client will see the new certificate and blow up. + // Note that browsers can handle this case better: they will just not + // use session resumption and fallback to the normal TLS handshake. + client.getSession().invalidate(); + + String request1 = "" + + "POST / HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "Content-Length: " + content.length + "\r\n" + + "\r\n"; + OutputStream outputStream = client.getOutputStream(); + outputStream.write(request1.getBytes(StandardCharsets.UTF_8)); + outputStream.write(content); + outputStream.flush(); + + InputStream inputStream = client.getInputStream(); + HttpTester.Response response1 = HttpTester.parseResponse(HttpTester.from(inputStream)); + Assert.assertNotNull(response1); + Assert.assertThat(response1.getStatus(), Matchers.equalTo(HttpStatus.OK_200)); + + String request2 = "" + + "GET / HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "Connection: close\r\n" + + "\r\n"; + outputStream.write(request2.getBytes(StandardCharsets.UTF_8)); + outputStream.flush(); + + HttpTester.Response response2 = HttpTester.parseResponse(HttpTester.from(inputStream)); + Assert.assertNotNull(response2); + Assert.assertThat(response2.getStatus(), Matchers.equalTo(HttpStatus.OK_200)); + } + } + + Assert.assertEquals(0, reloads.get()); + } + finally + { + scheduler.stop(); + } + } + + private static class EchoHandler extends AbstractHandler + { + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + baseRequest.setHandled(true); + if (HttpMethod.POST.is(request.getMethod())) + IO.copy(request.getInputStream(), response.getOutputStream()); + else + response.setContentLength(0); + } + } +} diff --git a/jetty-server/src/test/resources/jetty-logging.properties b/jetty-server/src/test/resources/jetty-logging.properties index f345cd6cb5e..adf68c7c337 100644 --- a/jetty-server/src/test/resources/jetty-logging.properties +++ b/jetty-server/src/test/resources/jetty-logging.properties @@ -1,3 +1,3 @@ org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog -org.eclipse.jetty.LEVEL=INFO +#org.eclipse.jetty.LEVEL=DEBUG #org.eclipse.jetty.server.LEVEL=DEBUG diff --git a/jetty-server/src/test/resources/reload_keystore_1.jks b/jetty-server/src/test/resources/reload_keystore_1.jks new file mode 100644 index 00000000000..d615c22234d Binary files /dev/null and b/jetty-server/src/test/resources/reload_keystore_1.jks differ diff --git a/jetty-server/src/test/resources/reload_keystore_2.jks b/jetty-server/src/test/resources/reload_keystore_2.jks new file mode 100644 index 00000000000..3707c3a3613 Binary files /dev/null and b/jetty-server/src/test/resources/reload_keystore_2.jks differ diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java index 4e049c37d1a..96b424990bc 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java @@ -423,7 +423,7 @@ public class ServletContextHandler extends ContextHandler */ public ServletHolder addServlet(Class servlet,String pathSpec) { - return getServletHandler().addServletWithMapping(servlet,pathSpec); + return getServletHandler().addServletWithMapping(servlet, pathSpec); } /* ------------------------------------------------------------ */ diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/StatisticsServlet.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/StatisticsServlet.java index 09bb2fe08d9..d97eb76bdaa 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/StatisticsServlet.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/StatisticsServlet.java @@ -31,6 +31,7 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.io.ConnectionStatistics; import org.eclipse.jetty.server.AbstractConnector; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.ConnectorStatistics; @@ -38,14 +39,10 @@ import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.StatisticsHandler; +import org.eclipse.jetty.util.component.Container; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -/** - * StatisticsServlet - * - * - */ public class StatisticsServlet extends HttpServlet { private static final Logger LOG = Log.getLogger(StatisticsServlet.class); @@ -55,11 +52,6 @@ public class StatisticsServlet extends HttpServlet private MemoryMXBean _memoryBean; private Connector[] _connectors; - - - /** - * @see javax.servlet.GenericServlet#init() - */ public void init() throws ServletException { ServletContext context = getServletContext(); @@ -87,21 +79,11 @@ public class StatisticsServlet extends HttpServlet } } - - - /** - * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) - */ public void doPost(HttpServletRequest sreq, HttpServletResponse sres) throws ServletException, IOException { doGet(sreq, sres); } - - - /** - * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) - */ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { if (_statsHandler == null) @@ -119,11 +101,17 @@ public class StatisticsServlet extends HttpServlet } } + if (Boolean.valueOf( req.getParameter("statsReset"))) + { + _statsHandler.statsReset(); + return; + } + String wantXml = req.getParameter("xml"); if (wantXml == null) wantXml = req.getParameter("XML"); - if (wantXml != null && "true".equalsIgnoreCase(wantXml)) + if (Boolean.valueOf(wantXml)) { sendXmlResponse(resp); } @@ -131,7 +119,6 @@ public class StatisticsServlet extends HttpServlet { sendTextResponse(resp); } - } private boolean isLoopbackAddress(String address) @@ -199,24 +186,45 @@ public class StatisticsServlet extends HttpServlet sb.append(" ").append(protocol).append("\n"); sb.append(" \n"); - ConnectorStatistics connectorStats = null; - + ConnectionStatistics connectionStats = null; if (connector instanceof AbstractConnector) - connectorStats = ((AbstractConnector)connector).getBean(ConnectorStatistics.class); - if (connectorStats == null) - sb.append(" false\n"); - else + connectionStats = ((AbstractConnector)connector).getBean(ConnectionStatistics.class); + if (connectionStats != null) { sb.append(" true\n"); - sb.append(" ").append(connectorStats.getConnections()).append("\n"); - sb.append(" ").append(connectorStats.getConnectionsOpen()).append("\n"); - sb.append(" ").append(connectorStats.getConnectionsOpenMax()).append("\n"); - sb.append(" ").append(connectorStats.getConnectionDurationMean()).append("\n"); - sb.append(" ").append(connectorStats.getConnectionDurationMax()).append("\n"); - sb.append(" ").append(connectorStats.getConnectionDurationStdDev()).append("\n"); - sb.append(" ").append(connectorStats.getMessagesIn()).append("\n"); - sb.append(" ").append(connectorStats.getMessagesIn()).append("\n"); - sb.append(" ").append(connectorStats.getStartedMillis()).append("\n"); + sb.append(" ").append(connectionStats.getConnectionsTotal()).append("\n"); + sb.append(" ").append(connectionStats.getConnections()).append("\n"); + sb.append(" ").append(connectionStats.getConnectionsMax()).append("\n"); + sb.append(" ").append(connectionStats.getConnectionDurationMean()).append("\n"); + sb.append(" ").append(connectionStats.getConnectionDurationMax()).append("\n"); + sb.append(" ").append(connectionStats.getConnectionDurationStdDev()).append("\n"); + sb.append(" ").append(connectionStats.getReceivedBytes()).append("\n"); + sb.append(" ").append(connectionStats.getSentBytes()).append("\n"); + sb.append(" ").append(connectionStats.getReceivedMessages()).append("\n"); + sb.append(" ").append(connectionStats.getSentMessages()).append("\n"); + } + else + { + ConnectorStatistics connectorStats = null; + if (connector instanceof AbstractConnector) + connectorStats = ((AbstractConnector)connector).getBean(ConnectorStatistics.class); + if (connectorStats != null) + { + sb.append(" true\n"); + sb.append(" ").append(connectorStats.getConnections()).append("\n"); + sb.append(" ").append(connectorStats.getConnectionsOpen()).append("\n"); + sb.append(" ").append(connectorStats.getConnectionsOpenMax()).append("\n"); + sb.append(" ").append(connectorStats.getConnectionDurationMean()).append("\n"); + sb.append(" ").append(connectorStats.getConnectionDurationMax()).append("\n"); + sb.append(" ").append(connectorStats.getConnectionDurationStdDev()).append("\n"); + sb.append(" ").append(connectorStats.getMessagesIn()).append("\n"); + sb.append(" ").append(connectorStats.getMessagesIn()).append("\n"); + sb.append(" ").append(connectorStats.getStartedMillis()).append("\n"); + } + else + { + sb.append(" false\n"); + } } sb.append(" \n"); } @@ -234,12 +242,6 @@ public class StatisticsServlet extends HttpServlet pout.write(sb.toString()); } - - - /** - * @param response - * @throws IOException - */ private void sendTextResponse(HttpServletResponse response) throws IOException { StringBuilder sb = new StringBuilder(); @@ -254,28 +256,44 @@ public class StatisticsServlet extends HttpServlet sb.append(protocol).append(" "); sb.append("
    \n"); - ConnectorStatistics connectorStats = null; - - if (connector instanceof AbstractConnector) - connectorStats = ((AbstractConnector)connector).getBean(ConnectorStatistics.class); - - if (connectorStats != null) + ConnectionStatistics connectionStats = null; + if (connector instanceof Container) + connectionStats = ((Container)connector).getBean(ConnectionStatistics.class); + if (connectionStats != null) { - sb.append("Statistics gathering started ").append(connectorStats.getStartedMillis()).append("ms ago").append("
    \n"); - sb.append("Total connections: ").append(connectorStats.getConnections()).append("
    \n"); - sb.append("Current connections open: ").append(connectorStats.getConnectionsOpen()).append("
    \n");; - sb.append("Max concurrent connections open: ").append(connectorStats.getConnectionsOpenMax()).append("
    \n"); - sb.append("Mean connection duration: ").append(connectorStats.getConnectionDurationMean()).append("
    \n"); - sb.append("Max connection duration: ").append(connectorStats.getConnectionDurationMax()).append("
    \n"); - sb.append("Connection duration standard deviation: ").append(connectorStats.getConnectionDurationStdDev()).append("
    \n"); - sb.append("Total messages in: ").append(connectorStats.getMessagesIn()).append("
    \n"); - sb.append("Total messages out: ").append(connectorStats.getMessagesOut()).append("
    \n"); + sb.append("Total connections: ").append(connectionStats.getConnectionsTotal()).append("
    \n"); + sb.append("Current connections open: ").append(connectionStats.getConnections()).append("
    \n"); + sb.append("Max concurrent connections open: ").append(connectionStats.getConnectionsMax()).append("
    \n"); + sb.append("Mean connection duration: ").append(connectionStats.getConnectionDurationMean()).append("
    \n"); + sb.append("Max connection duration: ").append(connectionStats.getConnectionDurationMax()).append("
    \n"); + sb.append("Connection duration standard deviation: ").append(connectionStats.getConnectionDurationStdDev()).append("
    \n"); + sb.append("Total bytes received: ").append(connectionStats.getReceivedBytes()).append("
    \n"); + sb.append("Total bytes sent: ").append(connectionStats.getSentBytes()).append("
    \n"); + sb.append("Total messages received: ").append(connectionStats.getReceivedMessages()).append("
    \n"); + sb.append("Total messages sent: ").append(connectionStats.getSentMessages()).append("
    \n"); } else { - sb.append("Statistics gathering off.\n"); + ConnectorStatistics connectorStats = null; + if (connector instanceof AbstractConnector) + connectorStats = ((AbstractConnector)connector).getBean(ConnectorStatistics.class); + if (connectorStats != null) + { + sb.append("Statistics gathering started ").append(connectorStats.getStartedMillis()).append("ms ago").append("
    \n"); + sb.append("Total connections: ").append(connectorStats.getConnections()).append("
    \n"); + sb.append("Current connections open: ").append(connectorStats.getConnectionsOpen()).append("
    \n"); + sb.append("Max concurrent connections open: ").append(connectorStats.getConnectionsOpenMax()).append("
    \n"); + sb.append("Mean connection duration: ").append(connectorStats.getConnectionDurationMean()).append("
    \n"); + sb.append("Max connection duration: ").append(connectorStats.getConnectionDurationMax()).append("
    \n"); + sb.append("Connection duration standard deviation: ").append(connectorStats.getConnectionDurationStdDev()).append("
    \n"); + sb.append("Total messages in: ").append(connectorStats.getMessagesIn()).append("
    \n"); + sb.append("Total messages out: ").append(connectorStats.getMessagesOut()).append("
    \n"); + } + else + { + sb.append("Statistics gathering off.\n"); + } } - } sb.append("

    Memory:

    \n"); @@ -285,6 +303,5 @@ public class StatisticsServlet extends HttpServlet response.setContentType("text/html"); PrintWriter pout = response.getWriter(); pout.write(sb.toString()); - } } diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncIOServletTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncIOServletTest.java deleted file mode 100644 index 6d7b6d793b9..00000000000 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncIOServletTest.java +++ /dev/null @@ -1,1034 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 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.servlet; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.net.Socket; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - -import javax.servlet.AsyncContext; -import javax.servlet.DispatcherType; -import javax.servlet.ReadListener; -import javax.servlet.ServletException; -import javax.servlet.ServletInputStream; -import javax.servlet.ServletOutputStream; -import javax.servlet.WriteListener; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.http.HttpTester; -import org.eclipse.jetty.server.HttpChannel; -import org.eclipse.jetty.server.HttpConnectionFactory; -import org.eclipse.jetty.server.LocalConnector; -import org.eclipse.jetty.server.LocalConnector.LocalEndPoint; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.server.handler.ContextHandler; -import org.eclipse.jetty.server.handler.ContextHandler.Context; -import org.eclipse.jetty.toolchain.test.AdvancedRunner; -import org.eclipse.jetty.toolchain.test.http.SimpleHttpParser; -import org.eclipse.jetty.toolchain.test.http.SimpleHttpResponse; -import org.eclipse.jetty.util.IO; -import org.eclipse.jetty.util.log.StacklessLogging; -import org.hamcrest.Matchers; -import org.junit.After; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; - -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - -@RunWith (AdvancedRunner.class) -public class AsyncIOServletTest -{ - private Server server; - private ServerConnector connector; - private LocalConnector local; - private ServletContextHandler context; - private String path = "/path"; - private static final ThreadLocal scope = new ThreadLocal<>(); - - public void startServer(HttpServlet servlet) throws Exception - { - startServer(servlet,30000); - } - - public void startServer(HttpServlet servlet, long idleTimeout) throws Exception - { - server = new Server(); - connector = new ServerConnector(server); - connector.setIdleTimeout(idleTimeout); - connector.getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration().setDelayDispatchUntilContent(false); - server.addConnector(connector); - local = new LocalConnector(server); - server.addConnector(local); - - context = new ServletContextHandler(server, "/", false, false); - ServletHolder holder = new ServletHolder(servlet); - holder.setAsyncSupported(true); - context.addServlet(holder, path); - - context.addEventListener(new ContextHandler.ContextScopeListener() - { - @Override - public void enterScope(Context context, Request request, Object reason) - { - if (scope.get()!=null) - { - System.err.println(Thread.currentThread()+" Already entered scope!!!"); - scope.get().printStackTrace(); - throw new IllegalStateException(); - } - scope.set(new Throwable()); - } - @Override - public void exitScope(Context context, Request request) - { - if (scope.get()==null) - throw new IllegalStateException(); - scope.set(null); - } - }); - - server.start(); - } - - private static void assertScope() - { - if (scope.get()==null) - Assert.fail("Not in scope"); - } - - @After - public void stopServer() throws Exception - { - server.stop(); - if (scope.get()!=null) - { - System.err.println("Still in scope after stop!"); - scope.get().printStackTrace(); - throw new IllegalStateException("Didn't leave scope"); - } - scope.set(null); - } - - @Test - public void testAsyncReadThrowsException() throws Exception - { - testAsyncReadThrows(new NullPointerException("explicitly_thrown_by_test")); - } - - @Test - public void testAsyncReadThrowsError() throws Exception - { - testAsyncReadThrows(new Error("explicitly_thrown_by_test")); - } - - private void testAsyncReadThrows(final Throwable throwable) throws Exception - { - final CountDownLatch latch = new CountDownLatch(1); - startServer(new HttpServlet() - { - @Override - protected void service(HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException - { - assertScope(); - final AsyncContext asyncContext = request.startAsync(request, response); - request.getInputStream().setReadListener(new ReadListener() - { - @Override - public void onDataAvailable() throws IOException - { - assertScope(); - if (throwable instanceof RuntimeException) - throw (RuntimeException)throwable; - if (throwable instanceof Error) - throw (Error)throwable; - throw new IOException(throwable); - } - - @Override - public void onAllDataRead() throws IOException - { - assertScope(); - } - - @Override - public void onError(Throwable t) - { - assertScope(); - Assert.assertThat("onError type",t,instanceOf(throwable.getClass())); - Assert.assertThat("onError message",t.getMessage(),is(throwable.getMessage())); - latch.countDown(); - response.setStatus(500); - - asyncContext.complete(); - } - }); - } - }); - - String data = "0123456789"; - String request = "GET " + path + " HTTP/1.1\r\n" + - "Host: localhost:" + connector.getLocalPort() + "\r\n" + - "Content-Length: " + data.length() + "\r\n" + - "\r\n" + - data; - - try (Socket client = new Socket("localhost", connector.getLocalPort())) - { - client.setSoTimeout(5000); - OutputStream output = client.getOutputStream(); - output.write(request.getBytes("UTF-8")); - output.flush(); - - BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream())); - String line=in.readLine(); - assertThat(line, containsString("500 Server Error")); - while (line.length()>0) - { - line=in.readLine(); - } - line=in.readLine(); - - assertTrue(latch.await(5, TimeUnit.SECONDS)); - } - } - - @Test - public void testAsyncReadIdleTimeout() throws Exception - { - final int status = 567; - startServer(new HttpServlet() - { - @Override - protected void service(HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException - { - assertScope(); - final AsyncContext asyncContext = request.startAsync(request, response); - asyncContext.setTimeout(0); - final ServletInputStream inputStream = request.getInputStream(); - inputStream.setReadListener(new ReadListener() - { - @Override - public void onDataAvailable() throws IOException - { - assertScope(); - while (inputStream.isReady() && !inputStream.isFinished()) - inputStream.read(); - } - - @Override - public void onAllDataRead() throws IOException - { - assertScope(); - } - - @Override - public void onError(Throwable t) - { - assertScope(); - response.setStatus(status); - // Do not put Connection: close header here, the test - // verifies that the server closes no matter what. - asyncContext.complete(); - } - }); - } - },1000); - - String data1 = "0123456789"; - String data2 = "ABCDEF"; - // Only send the first chunk of data and then let it idle timeout. - String request = "GET " + path + " HTTP/1.1\r\n" + - "Host: localhost:" + connector.getLocalPort() + "\r\n" + - "Content-Length: " + (data1.length() + data2.length()) + "\r\n" + - "\r\n" + - data1; - - try (Socket client = new Socket("localhost", connector.getLocalPort())) - { - client.setSoTimeout(5000); - OutputStream output = client.getOutputStream(); - output.write(request.getBytes("UTF-8")); - output.flush(); - - SimpleHttpParser parser = new SimpleHttpParser(); - SimpleHttpResponse response = parser.readResponse(new BufferedReader(new InputStreamReader(client.getInputStream(), "UTF-8"))); - - assertEquals(String.valueOf(status), response.getCode()); - - // Make sure the connection was closed by the server. - assertEquals(-1, client.getInputStream().read()); - } - } - - @Test - public void testOnErrorThrows() throws Exception - { - final AtomicInteger errors = new AtomicInteger(); - startServer(new HttpServlet() - { - @Override - protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException - { - assertScope(); - if (request.getDispatcherType()==DispatcherType.ERROR) - { - response.flushBuffer(); - return; - } - - final AsyncContext asyncContext = request.startAsync(request, response); - request.getInputStream().setReadListener(new ReadListener() - { - @Override - public void onDataAvailable() throws IOException - { - assertScope(); - throw new NullPointerException("explicitly_thrown_by_test_1"); - } - - @Override - public void onAllDataRead() throws IOException - { - assertScope(); - } - - @Override - public void onError(final Throwable t) - { - assertScope(); - errors.incrementAndGet(); - throw new NullPointerException("explicitly_thrown_by_test_2"){{this.initCause(t);}}; - } - }); - } - }); - - String data = "0123456789"; - String request = "GET " + path + " HTTP/1.1\r\n" + - "Host: localhost:" + connector.getLocalPort() + "\r\n" + - "Content-Length: " + data.length() + "\r\n" + - "\r\n" + - data; - - try (Socket client = new Socket("localhost", connector.getLocalPort()); - StacklessLogging stackless = new StacklessLogging(HttpChannel.class)) - { - OutputStream output = client.getOutputStream(); - output.write(request.getBytes("UTF-8")); - output.flush(); - - SimpleHttpParser parser = new SimpleHttpParser(); - SimpleHttpResponse response = parser.readResponse(new BufferedReader(new InputStreamReader(client.getInputStream(), "UTF-8"))); - - Assert.assertEquals("500", response.getCode()); - Assert.assertEquals(1, errors.get()); - } - } - - @Test - public void testAsyncWriteThrowsException() throws Exception - { - testAsyncWriteThrows(new NullPointerException("explicitly_thrown_by_test")); - } - - @Test - public void testAsyncWriteThrowsError() throws Exception - { - testAsyncWriteThrows(new Error("explicitly_thrown_by_test")); - } - - private void testAsyncWriteThrows(final Throwable throwable) throws Exception - { - final CountDownLatch latch = new CountDownLatch(1); - startServer(new HttpServlet() - { - @Override - protected void service(HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException - { - assertScope(); - final AsyncContext asyncContext = request.startAsync(request, response); - response.getOutputStream().setWriteListener(new WriteListener() - { - @Override - public void onWritePossible() throws IOException - { - assertScope(); - if (throwable instanceof RuntimeException) - throw (RuntimeException)throwable; - if (throwable instanceof Error) - throw (Error)throwable; - throw new IOException(throwable); - } - - @Override - public void onError(Throwable t) - { - assertScope(); - latch.countDown(); - response.setStatus(500); - asyncContext.complete(); - Assert.assertSame(throwable, t); - } - }); - } - }); - - String request = "GET " + path + " HTTP/1.1\r\n" + - "Host: localhost:" + connector.getLocalPort() + "\r\n" + - "\r\n"; - - try (Socket client = new Socket("localhost", connector.getLocalPort())) - { - OutputStream output = client.getOutputStream(); - output.write(request.getBytes("UTF-8")); - output.flush(); - - SimpleHttpParser parser = new SimpleHttpParser(); - SimpleHttpResponse response = parser.readResponse(new BufferedReader(new InputStreamReader(client.getInputStream(), "UTF-8"))); - - assertTrue(latch.await(5, TimeUnit.SECONDS)); - Assert.assertEquals("500", response.getCode()); - } - } - - - @Test - public void testAsyncWriteClosed() throws Exception - { - final CountDownLatch latch = new CountDownLatch(1); - String text = "Now is the winter of our discontent. How Now Brown Cow. The quick brown fox jumped over the lazy dog.\n"; - for (int i=0;i<10;i++) - text=text+text; - final byte[] data = text.getBytes(StandardCharsets.ISO_8859_1); - - startServer(new HttpServlet() - { - @Override - protected void service(HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException - { - assertScope(); - response.flushBuffer(); - - final AsyncContext async = request.startAsync(); - final ServletOutputStream out = response.getOutputStream(); - out.setWriteListener(new WriteListener() - { - @Override - public void onWritePossible() throws IOException - { - assertScope(); - while (out.isReady()) - { - try - { - Thread.sleep(100); - out.write(data); - } - catch(IOException e) - { - throw e; - } - catch(Exception e) - { - e.printStackTrace(); - } - } - } - - @Override - public void onError(Throwable t) - { - assertScope(); - async.complete(); - latch.countDown(); - } - }); - } - }); - - String request = "GET " + path + " HTTP/1.1\r\n" + - "Host: localhost:" + connector.getLocalPort() + "\r\n" + - "\r\n"; - - try (Socket client = new Socket("localhost", connector.getLocalPort())) - { - OutputStream output = client.getOutputStream(); - output.write(request.getBytes("UTF-8")); - output.flush(); - - BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream())); - String line=in.readLine(); - assertThat(line, containsString("200 OK")); - while (line.length()>0) - line=in.readLine(); - line=in.readLine(); - assertThat(line, not(containsString(" "))); - line=in.readLine(); - assertThat(line, containsString("discontent. How Now Brown Cow. The ")); - } - - if (!latch.await(5, TimeUnit.SECONDS)) - Assert.fail(); - } - - - @Test - public void testIsReadyAtEOF() throws Exception - { - String text = "TEST\n"; - final byte[] data = text.getBytes(StandardCharsets.ISO_8859_1); - - startServer(new HttpServlet() - { - @Override - protected void service(HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException - { - assertScope(); - response.flushBuffer(); - - final AsyncContext async = request.startAsync(); - final ServletInputStream in = request.getInputStream(); - final ServletOutputStream out = response.getOutputStream(); - - in.setReadListener(new ReadListener() - { - transient int _i=0; - transient boolean _minusOne=false;; - transient boolean _finished=false;; - - @Override - public void onError(Throwable t) - { - assertScope(); - t.printStackTrace(); - async.complete(); - } - - @Override - public void onDataAvailable() throws IOException - { - assertScope(); - while(in.isReady() && !in.isFinished()) - { - int b = in.read(); - if (b==-1) - _minusOne=true; - else if (data[_i++]!=b) - throw new IllegalStateException(); - } - - if (in.isFinished()) - _finished=true; - } - - @Override - public void onAllDataRead() throws IOException - { - assertScope(); - out.write(String.format("i=%d eof=%b finished=%b",_i,_minusOne,_finished).getBytes(StandardCharsets.ISO_8859_1)); - async.complete(); - } - }); - } - }); - - String request = "GET " + path + " HTTP/1.1\r\n" + - "Host: localhost:" + connector.getLocalPort() + "\r\n" + - "Content-Type: text/plain\r\n"+ - "Content-Length: "+data.length+"\r\n" + - "Connection: close\r\n" + - "\r\n"; - - try (Socket client = new Socket("localhost", connector.getLocalPort())) - { - OutputStream output = client.getOutputStream(); - output.write(request.getBytes("UTF-8")); - output.flush(); - output.write(data); - output.flush(); - - BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream())); - String line=in.readLine(); - assertThat(line, containsString("200 OK")); - while (line.length()>0) - line=in.readLine(); - line=in.readLine(); - assertThat(line, containsString("i="+data.length+" eof=true finished=true")); - } - } - - - @Test - public void testOnAllDataRead() throws Exception - { - String text = "X"; - final byte[] data = text.getBytes(StandardCharsets.ISO_8859_1); - - startServer(new HttpServlet() - { - @Override - protected void service(HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException - { - assertScope(); - response.flushBuffer(); - - final AsyncContext async = request.startAsync(); - async.setTimeout(5000); - final ServletInputStream in = request.getInputStream(); - final ServletOutputStream out = response.getOutputStream(); - - in.setReadListener(new ReadListener() - { - @Override - public void onError(Throwable t) - { - assertScope(); - t.printStackTrace(); - async.complete(); - } - - @Override - public void onDataAvailable() throws IOException - { - assertScope(); - try - { - Thread.sleep(1000); - if (!in.isReady()) - throw new IllegalStateException(); - if (in.read()!='X') - throw new IllegalStateException(); - if (!in.isReady()) - throw new IllegalStateException(); - if (in.read()!=-1) - throw new IllegalStateException(); - } - catch(Exception e) - { - e.printStackTrace(); - } - } - - @Override - public void onAllDataRead() throws IOException - { - assertScope(); - out.write("OK\n".getBytes(StandardCharsets.ISO_8859_1)); - async.complete(); - } - }); - } - }); - - String request = "GET " + path + " HTTP/1.1\r\n" + - "Host: localhost:" + connector.getLocalPort() + "\r\n" + - "Content-Type: text/plain\r\n"+ - "Content-Length: "+data.length+"\r\n" + - "Connection: close\r\n" + - "\r\n"; - - try (Socket client = new Socket("localhost", connector.getLocalPort())) - { - client.setSoTimeout(5000); - OutputStream output = client.getOutputStream(); - output.write(request.getBytes("UTF-8")); - output.flush(); - Thread.sleep(100); - output.write(data); - output.flush(); - - BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream())); - String line=in.readLine(); - assertThat(line, containsString("200 OK")); - while (line.length()>0) - line=in.readLine(); - line=in.readLine(); - assertThat(line, containsString("OK")); - } - } - - @Test - public void testOtherThreadOnAllDataRead() throws Exception - { - String text = "X"; - final byte[] data = text.getBytes(StandardCharsets.ISO_8859_1); - - startServer(new HttpServlet() - { - @Override - protected void service(HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException - { - assertScope(); - response.flushBuffer(); - - final AsyncContext async = request.startAsync(); - async.setTimeout(500000); - final ServletInputStream in = request.getInputStream(); - final ServletOutputStream out = response.getOutputStream(); - - if (request.getDispatcherType()==DispatcherType.ERROR) - throw new IllegalStateException(); - - in.setReadListener(new ReadListener() - { - @Override - public void onError(Throwable t) - { - assertScope(); - t.printStackTrace(); - async.complete(); - } - - @Override - public void onDataAvailable() throws IOException - { - assertScope(); - async.start( - new Runnable() - { - public void run() - { - assertScope(); - try - { - Thread.sleep(1000); - if (!in.isReady()) - throw new IllegalStateException(); - if (in.read()!='X') - throw new IllegalStateException(); - if (!in.isReady()) - throw new IllegalStateException(); - if (in.read()!=-1) - throw new IllegalStateException(); - } - catch(Exception e) - { - e.printStackTrace(); - } - } - }); - } - - @Override - public void onAllDataRead() throws IOException - { - out.write("OK\n".getBytes(StandardCharsets.ISO_8859_1)); - async.complete(); - } - }); - } - }); - - String request = "GET " + path + " HTTP/1.1\r\n" + - "Host: localhost:" + connector.getLocalPort() + "\r\n" + - "Content-Type: text/plain\r\n"+ - "Content-Length: "+data.length+"\r\n" + - "Connection: close\r\n" + - "\r\n"; - - try (Socket client = new Socket("localhost", connector.getLocalPort())) - { - client.setSoTimeout(500000); - OutputStream output = client.getOutputStream(); - output.write(request.getBytes("UTF-8")); - output.flush(); - Thread.sleep(100); - output.write(data); - output.flush(); - - BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream())); - String line=in.readLine(); - assertThat(line, containsString("200 OK")); - while (line.length()>0) - line=in.readLine(); - line=in.readLine(); - assertThat(line, containsString("OK")); - } - } - - - @Test - public void testCompleteBeforeOnAllDataRead() throws Exception - { - String text = "XYZ"; - final byte[] data = text.getBytes(StandardCharsets.ISO_8859_1); - final AtomicBoolean allDataRead = new AtomicBoolean(false); - - startServer(new HttpServlet() - { - @Override - protected void service(HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException - { - assertScope(); - response.flushBuffer(); - - final AsyncContext async = request.startAsync(); - final ServletInputStream in = request.getInputStream(); - final ServletOutputStream out = response.getOutputStream(); - - in.setReadListener(new ReadListener() - { - @Override - public void onError(Throwable t) - { - assertScope(); - t.printStackTrace(); - } - - @Override - public void onDataAvailable() throws IOException - { - assertScope(); - while (in.isReady()) - { - int b = in.read(); - if (b<0) - { - out.write("OK\n".getBytes(StandardCharsets.ISO_8859_1)); - async.complete(); - return; - } - } - } - - @Override - public void onAllDataRead() throws IOException - { - assertScope(); - out.write("BAD!!!\n".getBytes(StandardCharsets.ISO_8859_1)); - allDataRead.set(true); - throw new IllegalStateException(); - } - }); - } - }); - - String request = "GET " + path + " HTTP/1.1\r\n" + - "Host: localhost:" + connector.getLocalPort() + "\r\n" + - "Content-Type: text/plain\r\n"+ - "Content-Length: "+data.length+"\r\n" + - "Connection: close\r\n" + - "\r\n"; - - try (Socket client = new Socket("localhost", connector.getLocalPort())) - { - OutputStream output = client.getOutputStream(); - output.write(request.getBytes("UTF-8")); - output.flush(); - Thread.sleep(100); - output.write(data); - output.flush(); - - BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream())); - String line=in.readLine(); - assertThat(line, containsString("200 OK")); - while (line.length()>0) - { - line=in.readLine(); - } - line=in.readLine(); - assertThat(line, containsString("OK")); - Assert.assertFalse(allDataRead.get()); - } - } - - - @Test - public void testEmptyAsyncRead() throws Exception - { - final AtomicBoolean oda = new AtomicBoolean(); - final CountDownLatch latch = new CountDownLatch(1); - - startServer(new HttpServlet() - { - @Override - protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException - { - assertScope(); - final AsyncContext asyncContext = request.startAsync(request, response); - response.setStatus(200); - response.getOutputStream().close(); - request.getInputStream().setReadListener(new ReadListener() - { - @Override - public void onDataAvailable() throws IOException - { - assertScope(); - oda.set(true); - } - - @Override - public void onAllDataRead() throws IOException - { - assertScope(); - asyncContext.complete(); - latch.countDown(); - } - - @Override - public void onError(Throwable t) - { - assertScope(); - t.printStackTrace(); - asyncContext.complete(); - } - }); - } - }); - - String request = "GET " + path + " HTTP/1.1\r\n" + - "Host: localhost:" + connector.getLocalPort() + "\r\n" + - "Connection: close\r\n" + - "\r\n"; - - try (Socket client = new Socket("localhost", connector.getLocalPort())) - { - OutputStream output = client.getOutputStream(); - output.write(request.getBytes("UTF-8")); - output.flush(); - - String response = IO.toString(client.getInputStream()); - assertThat(response,containsString(" 200 OK")); - // wait for onAllDataRead BEFORE closing client - latch.await(); - } - - // ODA not called at all! - Assert.assertFalse(oda.get()); - } - - @Test - public void testWriteFromOnDataAvailable() throws Exception - { - Queue errors = new ConcurrentLinkedQueue<>(); - CountDownLatch writeLatch = new CountDownLatch(1); - startServer(new HttpServlet() - { - @Override - protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException - { - AsyncContext asyncContext = request.startAsync(); - request.getInputStream().setReadListener(new ReadListener() - { - @Override - public void onDataAvailable() throws IOException - { - ServletInputStream input = request.getInputStream(); - ServletOutputStream output = response.getOutputStream(); - while (input.isReady()) - { - byte[] buffer = new byte[512]; - int read = input.read(buffer); - if (read < 0) - { - //if (output.isReady()) - { - asyncContext.complete(); - } - break; - } - if (output.isReady()) - { - output.write(buffer, 0, read); - } - else - Assert.fail(); - } - } - - @Override - public void onAllDataRead() throws IOException - { - } - - @Override - public void onError(Throwable t) - { - errors.offer(t); - } - }); - response.getOutputStream().setWriteListener(new WriteListener() - { - @Override - public void onWritePossible() throws IOException - { - if (writeLatch.getCount()==0) - asyncContext.complete(); - else - writeLatch.countDown(); - } - - @Override - public void onError(Throwable t) - { - errors.offer(t); - } - }); - } - }); - - String content = "0123456789ABCDEF"; - - try (LocalEndPoint endp = local.connect()) - { - String request = "POST " + path + " HTTP/1.1\r\n" + - "Host: localhost:" + connector.getLocalPort() + "\r\n" + - "Transfer-Encoding: chunked\r\n" + - "\r\n" + - Integer.toHexString(content.length())+"\r\n" + - content + "\r\n"; - endp.addInput(ByteBuffer.wrap(request.getBytes("UTF-8"))); - - assertTrue(writeLatch.await(5, TimeUnit.SECONDS)); - - request = "" + - "0\r\n" + - "\r\n"; - endp.addInput(ByteBuffer.wrap(request.getBytes("UTF-8"))); - - HttpTester.Response response = HttpTester.parseResponse(endp.getResponse()); - - assertThat(response.getStatus(), Matchers.equalTo(HttpStatus.OK_200)); - assertThat(response.getContent(), Matchers.equalTo(content)); - assertThat(errors, Matchers.hasSize(0)); - } - } -} diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/EncodedURITest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/EncodedURITest.java new file mode 100644 index 00000000000..17efff7ab9f --- /dev/null +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/EncodedURITest.java @@ -0,0 +1,205 @@ +// +// ======================================================================== +// Copyright (c) 1995-2016 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.servlet; + +import static org.hamcrest.Matchers.startsWith; +import static org.junit.Assert.assertThat; + +import java.io.IOException; +import java.util.EnumSet; + +import javax.servlet.AsyncContext; +import javax.servlet.DispatcherType; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.LocalConnector; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.ContextHandlerCollection; +import org.eclipse.jetty.util.URIUtil; +import org.hamcrest.Matchers; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class EncodedURITest +{ + private Server _server; + private LocalConnector _connector; + private ContextHandlerCollection _contextCollection; + private ServletContextHandler _context0; + private ServletContextHandler _context1; + + @Before + public void init() throws Exception + { + _server = new Server(); + _connector = new LocalConnector(_server); + _connector.getConnectionFactory(HttpConfiguration.ConnectionFactory.class).getHttpConfiguration().setSendServerVersion(false); + _connector.getConnectionFactory(HttpConfiguration.ConnectionFactory.class).getHttpConfiguration().setSendDateHeader(false); + _server.addConnector( _connector ); + + _contextCollection = new ContextHandlerCollection(); + _server.setHandler(_contextCollection); + + _context0 = new ServletContextHandler(); + _context0.setContextPath("/context path"); + _contextCollection.addHandler(_context0); + _context0.addFilter(AsyncFilter.class,"/*",EnumSet.of(DispatcherType.REQUEST)); + _context0.addServlet(TestServlet.class,"/test servlet/*"); + _context0.addServlet(AsyncServlet.class,"/async servlet/*"); + + _context1 = new ServletContextHandler(); + _context1.setContextPath("/redirecting context"); + _contextCollection.addHandler(_context1); + + _server.start(); + } + + @After + public void destroy() throws Exception + { + _server.stop(); + _server.join(); + } + + @Test + public void testTestServlet() throws Exception + { + String response = _connector.getResponse("GET /c%6Fntext%20path/test%20servlet/path%20info HTTP/1.0\n\n"); + assertThat(response,startsWith("HTTP/1.1 200 ")); + assertThat(response,Matchers.containsString("requestURI=/c%6Fntext%20path/test%20servlet/path%20info")); + assertThat(response,Matchers.containsString("contextPath=/context%20path")); + assertThat(response,Matchers.containsString("servletPath=/test servlet")); + assertThat(response,Matchers.containsString("pathInfo=/path info")); + } + + @Test + public void testAsyncFilterTestServlet() throws Exception + { + String response = _connector.getResponse("GET /context%20path/test%20servlet/path%20info?async=true HTTP/1.0\n\n"); + assertThat(response,startsWith("HTTP/1.1 200 ")); + assertThat(response,Matchers.containsString("requestURI=/context%20path/test%20servlet/path%20info")); + assertThat(response,Matchers.containsString("contextPath=/context%20path")); + assertThat(response,Matchers.containsString("servletPath=/test servlet")); + assertThat(response,Matchers.containsString("pathInfo=/path info")); + } + + @Test + public void testAsyncFilterWrapTestServlet() throws Exception + { + String response = _connector.getResponse("GET /context%20path/test%20servlet/path%20info?async=true&wrap=true HTTP/1.0\n\n"); + assertThat(response,startsWith("HTTP/1.1 200 ")); + assertThat(response,Matchers.containsString("requestURI=/context%20path/test%20servlet/path%20info")); + assertThat(response,Matchers.containsString("contextPath=/context%20path")); + assertThat(response,Matchers.containsString("servletPath=/test servlet")); + assertThat(response,Matchers.containsString("pathInfo=/path info")); + } + + @Test + public void testAsyncServletTestServlet() throws Exception + { + String response = _connector.getResponse("GET /context%20path/async%20servlet/path%20info HTTP/1.0\n\n"); + assertThat(response,startsWith("HTTP/1.1 200 ")); + assertThat(response,Matchers.containsString("requestURI=/context%20path/test servlet/path info")); + assertThat(response,Matchers.containsString("contextPath=/context%20path")); + assertThat(response,Matchers.containsString("servletPath=/test servlet")); + assertThat(response,Matchers.containsString("pathInfo=/path info")); + } + + @Test + public void testAsyncServletTestServletEncoded() throws Exception + { + String response = _connector.getResponse("GET /context%20path/async%20servlet/path%20info?encode=true HTTP/1.0\n\n"); + assertThat(response,startsWith("HTTP/1.1 200 ")); + assertThat(response,Matchers.containsString("requestURI=/context%20path/test%20servlet/path%20info")); + assertThat(response,Matchers.containsString("contextPath=/context%20path")); + assertThat(response,Matchers.containsString("servletPath=/test servlet")); + assertThat(response,Matchers.containsString("pathInfo=/path info")); + } + + + public static class TestServlet extends HttpServlet + { + @Override + public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + response.setContentType("text/plain"); + response.getWriter().println("requestURI="+request.getRequestURI()); + response.getWriter().println("contextPath="+request.getContextPath()); + response.getWriter().println("servletPath="+request.getServletPath()); + response.getWriter().println("pathInfo="+request.getPathInfo()); + } + } + + + public static class AsyncServlet extends HttpServlet + { + @Override + public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + AsyncContext async = Boolean.parseBoolean(request.getParameter("wrap")) + ?request.startAsync(request,response) + :request.startAsync(); + + if (Boolean.parseBoolean(request.getParameter("encode"))) + async.dispatch("/test%20servlet"+URIUtil.encodePath(request.getPathInfo())); + else + async.dispatch("/test servlet/path info"+request.getPathInfo()); + return; + } + } + + public static class AsyncFilter implements Filter + { + @Override + public void init(FilterConfig filterConfig) throws ServletException + { + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException + { + if (Boolean.parseBoolean(request.getParameter("async")) && !Boolean.parseBoolean((String)request.getAttribute("async"))) + { + request.setAttribute("async","true"); + AsyncContext async = Boolean.parseBoolean(request.getParameter("wrap")) + ?request.startAsync(request,response) + :request.startAsync(); + async.dispatch(); + return; + } + chain.doFilter(request,response); + } + + @Override + public void destroy() + { + } + } + +} diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/GzipHandlerTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/GzipHandlerTest.java index 6ddadb5e6fc..7b1ef878a5a 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/GzipHandlerTest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/GzipHandlerTest.java @@ -33,8 +33,10 @@ import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -45,6 +47,7 @@ import org.eclipse.jetty.http.HttpTester; import org.eclipse.jetty.server.LocalConnector; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.gzip.GzipHandler; +import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.IO; import org.hamcrest.Matchers; import org.junit.After; @@ -86,6 +89,7 @@ public class GzipHandlerTest GzipHandler gzipHandler = new GzipHandler(); gzipHandler.setExcludedAgentPatterns(); gzipHandler.setMinGzipSize(16); + gzipHandler.setInflateBufferSize(4096); ServletContextHandler context = new ServletContextHandler(gzipHandler,"/ctx"); ServletHandler servlets = context.getServletHandler(); @@ -97,6 +101,7 @@ public class GzipHandlerTest servlets.addServletWithMapping(TestServlet.class,"/content"); servlets.addServletWithMapping(ForwardServlet.class,"/forward"); servlets.addServletWithMapping(IncludeServlet.class,"/include"); + servlets.addServletWithMapping(EchoServlet.class,"/echo/*"); _server.start(); } @@ -134,6 +139,8 @@ public class GzipHandlerTest @Override protected void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException { + if (req.getParameter("vary")!=null) + response.addHeader("Vary",req.getParameter("vary")); response.setHeader("ETag",__contentETag); String ifnm = req.getHeader("If-None-Match"); if (ifnm!=null && ifnm.equals(__contentETag)) @@ -145,6 +152,21 @@ public class GzipHandlerTest } } } + + public static class EchoServlet extends HttpServlet + { + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException + { + response.setContentType(req.getContentType()); + IO.copy(req.getInputStream(),response.getOutputStream()); + } + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException + { + doGet(req,response); + } + } public static class ForwardServlet extends HttpServlet { @@ -181,25 +203,25 @@ public class GzipHandlerTest HttpTester.Response response; request.setMethod("GET"); - request.setURI("/ctx/content"); + request.setURI("/ctx/content?vary=Other"); request.setVersion("HTTP/1.0"); request.setHeader("Host","tester"); response = HttpTester.parseResponse(_connector.getResponses(request.generate())); - + assertThat(response.getStatus(),is(200)); assertThat(response.get("Content-Encoding"),not(equalToIgnoringCase("gzip"))); assertThat(response.get("ETag"),is(__contentETag)); - assertThat(response.get("Vary"),is("Accept-Encoding")); + assertThat(response.getValuesList("Vary"),Matchers.contains("Other","Accept-Encoding")); InputStream testIn = new ByteArrayInputStream(response.getContentBytes()); ByteArrayOutputStream testOut = new ByteArrayOutputStream(); IO.copy(testIn,testOut); assertEquals(__content, testOut.toString("UTF8")); - } + @Test public void testGzipHandler() throws Exception { @@ -208,7 +230,7 @@ public class GzipHandlerTest HttpTester.Response response; request.setMethod("GET"); - request.setURI("/ctx/content"); + request.setURI("/ctx/content?vary=Accept-Encoding,Other"); request.setVersion("HTTP/1.0"); request.setHeader("Host","tester"); request.setHeader("accept-encoding","gzip"); @@ -218,7 +240,7 @@ public class GzipHandlerTest assertThat(response.getStatus(),is(200)); assertThat(response.get("Content-Encoding"),Matchers.equalToIgnoringCase("gzip")); assertThat(response.get("ETag"),is(__contentETagGzip)); - assertThat(response.get("Vary"),is("Accept-Encoding")); + assertThat(response.getCSV("Vary",false),Matchers.contains("Accept-Encoding","Other")); InputStream testIn = new GZIPInputStream(new ByteArrayInputStream(response.getContentBytes())); ByteArrayOutputStream testOut = new ByteArrayOutputStream(); @@ -390,4 +412,68 @@ public class GzipHandlerTest assertThat("Included Paths.size", includedPaths.length, is(2)); assertThat("Included Paths", Arrays.asList(includedPaths), contains("/foo","^/bar.*$")); } + + + @Test + public void testGzipRequest() throws Exception + { + String data = "Hello Nice World! "; + for (int i = 0; i < 10; ++i) + data += data; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + GZIPOutputStream output = new GZIPOutputStream(baos); + output.write(data.getBytes(StandardCharsets.UTF_8)); + output.close(); + byte[] bytes = baos.toByteArray(); + + // generated and parsed test + HttpTester.Request request = HttpTester.newRequest(); + HttpTester.Response response; + + request.setMethod("POST"); + request.setURI("/ctx/echo"); + request.setVersion("HTTP/1.0"); + request.setHeader("Host","tester"); + request.setHeader("Content-Type","text/plain"); + request.setHeader("Content-Encoding","gzip"); + request.setContent(bytes); + + response = HttpTester.parseResponse(_connector.getResponse(request.generate())); + + assertThat(response.getStatus(),is(200)); + assertThat(response.getContent(),is(data)); + + } + + @Test + public void testGzipBomb() throws Exception + { + byte[] data = new byte[512*1024]; + Arrays.fill(data,(byte)'X'); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + GZIPOutputStream output = new GZIPOutputStream(baos); + output.write(data); + output.close(); + byte[] bytes = baos.toByteArray(); + + // generated and parsed test + HttpTester.Request request = HttpTester.newRequest(); + HttpTester.Response response; + + request.setMethod("POST"); + request.setURI("/ctx/echo"); + request.setVersion("HTTP/1.0"); + request.setHeader("Host","tester"); + request.setHeader("Content-Type","text/plain"); + request.setHeader("Content-Encoding","gzip"); + request.setContent(bytes); + + response = HttpTester.parseResponse(_connector.getResponse(request.generate())); + // TODO need to test back pressure works + + assertThat(response.getStatus(),is(200)); + assertThat(response.getContentBytes().length,is(512*1024)); + } + } diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/StatisticsServletTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/StatisticsServletTest.java new file mode 100644 index 00000000000..6d1dcb86731 --- /dev/null +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/StatisticsServletTest.java @@ -0,0 +1,154 @@ +// +// ======================================================================== +// Copyright (c) 1995-2016 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.servlet; + +import org.eclipse.jetty.http.HttpTester; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.server.LocalConnector; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.StatisticsHandler; +import org.eclipse.jetty.server.session.SessionHandler; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.xml.sax.InputSource; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathFactory; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringReader; +import java.nio.ByteBuffer; + +public class StatisticsServletTest +{ + private Server _server; + + private LocalConnector _connector; + + @Before + public void createServer() + { + _server = new Server(); + _connector = new LocalConnector( _server ); + _server.addConnector( _connector ); + } + + + @After + public void destroyServer() + throws Exception + { + _server.stop(); + _server.join(); + } + + @Test + public void getStats() + throws Exception + { + StatisticsHandler statsHandler = new StatisticsHandler(); + _server.setHandler(statsHandler); + ServletContextHandler statsContext = new ServletContextHandler(statsHandler, "/"); + statsContext.addServlet( new ServletHolder( new TestServlet() ), "/test1" ); + ServletHolder servletHolder = new ServletHolder( new StatisticsServlet() ); + servletHolder.setInitParameter( "restrictToLocalhost", "false" ); + statsContext.addServlet( servletHolder, "/stats" ); + statsContext.setSessionHandler( new SessionHandler() ); + _server.start(); + + getResponse("/test1" ); + String response = getResponse("/stats?xml=true" ); + Stats stats = parseStats( response ); + + Assert.assertEquals(1, stats.responses2xx); + + getResponse("/stats?statsReset=true" ); + response = getResponse("/stats?xml=true" ); + stats = parseStats( response ); + + Assert.assertEquals(1, stats.responses2xx); + + getResponse("/test1" ); + getResponse("/nothing" ); + response = getResponse("/stats?xml=true" ); + stats = parseStats( response ); + + Assert.assertEquals(3, stats.responses2xx); + Assert.assertEquals(1, stats.responses4xx); + } + + public String getResponse( String path ) + throws Exception + { + HttpTester.Request request = new HttpTester.Request(); + request.setMethod( "GET" ); + request.setURI( path ); + request.setVersion( HttpVersion.HTTP_1_1 ); + request.setHeader( "Host", "test" ); + + ByteBuffer responseBuffer = _connector.getResponse( request.generate() ); + return HttpTester.parseResponse( responseBuffer ).getContent(); + } + + + public Stats parseStats( String xml ) + throws Exception + { + XPath xPath = XPathFactory.newInstance().newXPath(); + + String responses4xx = xPath.evaluate( "//responses4xx", new InputSource( new StringReader( xml ) ) ); + + String responses2xx = xPath.evaluate( "//responses2xx", new InputSource( new StringReader( xml ) ) ); + + return new Stats(Integer.parseInt( responses2xx), Integer.parseInt( responses4xx )); + } + + public static class Stats + { + int responses2xx,responses4xx; + + public Stats( int responses2xx, int responses4xx ) + { + this.responses2xx = responses2xx; + this.responses4xx = responses4xx; + } + } + + + public static class TestServlet + extends HttpServlet + { + + @Override + protected void doGet( HttpServletRequest req, HttpServletResponse resp ) + throws ServletException, IOException + { + resp.setStatus( HttpServletResponse.SC_OK ); + PrintWriter writer = resp.getWriter(); + writer.write( "Yup!!" ); + } + } + +} diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/BaseBuilder.java b/jetty-start/src/main/java/org/eclipse/jetty/start/BaseBuilder.java index 4c4effcb5fd..bb399f99b20 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/BaseBuilder.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/BaseBuilder.java @@ -50,11 +50,10 @@ public class BaseBuilder * * @param module * the module to add - * @return true if module was added, false if module was not added - * (because that module already exists) + * @return The ini file if module was added, null if module was not added. * @throws IOException if unable to add the module */ - public boolean addModule(Module module) throws IOException; + public String addModule(Module module) throws IOException; } private static final String EXITING_LICENSE_NOT_ACKNOWLEDGED = "Exiting: license not acknowledged!"; @@ -118,7 +117,15 @@ public class BaseBuilder if (!startArgs.getStartModules().isEmpty()) { for (String name:startArgs.getStartModules()) + { newly_added.addAll(modules.enable(name,"--add-to-start")); + if (!newly_added.contains(name)) + { + Set sources = modules.get(name).getEnableSources(); + sources.remove("--add-to-start"); + StartLog.info("%s already enabled by %s",name,sources); + } + } } if (StartLog.isDebugEnabled()) @@ -173,7 +180,6 @@ public class BaseBuilder if (!newly_added.isEmpty()) { - if (Files.exists(startini) && Files.exists(startd)) StartLog.warn("Use both %s and %s is deprecated",getBaseHome().toShortForm(startd),getBaseHome().toShortForm(startini)); @@ -181,6 +187,7 @@ public class BaseBuilder builder.set(useStartD?new StartDirBuilder(this):new StartIniBuilder(this)); newly_added.stream().map(n->modules.get(n)).forEach(module -> { + String ini=null; try { if (module.isSkipFilesValidation()) @@ -189,8 +196,13 @@ public class BaseBuilder } else { - if (builder.get().addModule(module)) - modified.set(true); + // if (explictly added and ini file modified) + if (startArgs.getStartModules().contains(module.getName())) + { + ini=builder.get().addModule(module); + if (ini!=null) + modified.set(true); + } for (String file : module.getFiles()) files.add(new FileArg(module,startArgs.getProperties().expand(file))); } @@ -199,6 +211,26 @@ public class BaseBuilder { throw new RuntimeException(e); } + + if (module.isDynamic()) + { + for (String s:module.getEnableSources()) + StartLog.info("%-15s %s",module.getName(),s); + } + else if (module.isTransitive()) + { + if (module.hasIniTemplate()) + StartLog.info("%-15s transitively enabled, ini template available with --add-to-start=%s", + module.getName(), + module.getName()); + else + StartLog.info("%-15s transitively enabled",module.getName()); + } + else + StartLog.info("%-15s initialized in %s", + module.getName(), + ini); + }); } diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java index 3463ad3ecfe..39c7bbabfa4 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java @@ -243,16 +243,19 @@ public class Main public void listModules(StartArgs args) { + List tags = args.getListModules(); + StartLog.endStartLog(); System.out.println(); - System.out.println("Jetty All Available Modules:"); - System.out.println("----------------------------"); - args.getAllModules().dump(); + System.out.println("Available Modules:"); + System.out.println("=================="); + System.out.println("tags: "+tags); + args.getAllModules().dump(tags); // Dump Enabled Modules System.out.println(); - System.out.println("Jetty Selected Module Ordering:"); - System.out.println("-------------------------------"); + System.out.println("Enabled Modules:"); + System.out.println("================"); Modules modules = args.getAllModules(); modules.dumpEnabled(); } @@ -381,7 +384,7 @@ public class Main } // Show modules - if (args.isListModules()) + if (args.getListModules()!=null) { listModules(args); } diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Module.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Module.java index 7f31cf3390f..e318cc127a9 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/Module.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Module.java @@ -55,7 +55,7 @@ import java.util.stream.Collectors; * A module may be enabled, either directly by name or transiently via a dependency * from another module by name or provided capability. */ -public class Module +public class Module implements Comparable { private static final String VERSION_UNSPECIFIED = "9.2"; private static Pattern MOD_NAME = Pattern.compile("^(.*)\\.mod",Pattern.CASE_INSENSITIVE); @@ -96,6 +96,9 @@ public class Module /** List of provides for this Module */ private final Set _provides=new HashSet<>(); + /** List of tags for this Module */ + private final List _tags=new ArrayList<>(); + /** Boolean true if directly enabled, false if all selections are transitive */ private boolean _notTransitive; @@ -328,6 +331,10 @@ public class Module case "FILES": _files.add(line); break; + case "TAG": + case "TAGS": + _tags.add(line); + break; case "DEFAULTS": // old name introduced in 9.2.x case "INI": // new name for 9.3+ _defaultConfig.add(line); @@ -446,6 +453,16 @@ public class Module return _description; } + public List getTags() + { + return _tags; + } + + public String getPrimaryTag() + { + return _tags.isEmpty()?"*":_tags.get(0); + } + public boolean isEnabled() { return !_enables.isEmpty(); @@ -504,4 +521,13 @@ public class Module out.println(); out.flush(); } + + @Override + public int compareTo(Module m) + { + int by_tag = getPrimaryTag().compareTo(m.getPrimaryTag()); + if (by_tag!=0) + return by_tag; + return getName().compareTo(m.getName()); + } } diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java index d4f59a26716..0a1a3bf577a 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java @@ -21,7 +21,6 @@ package org.eclipse.jetty.start; import java.io.IOException; import java.nio.file.Path; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -30,6 +29,7 @@ import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -57,59 +57,92 @@ public class Modules implements Iterable } } - public void dump() + public void dump(List tags) { - List ordered = _modules.stream().map(m->{return m.getName();}).collect(Collectors.toList()); - Collections.sort(ordered); - ordered.stream().map(n->{return get(n);}).forEach(module-> - { - String status = "[ ]"; - if (module.isTransitive()) + Set exclude = tags.stream().filter(t->t.startsWith("-")).map(t->t.substring(1)).collect(Collectors.toSet()); + Set include = tags.stream().filter(t->!t.startsWith("-")).collect(Collectors.toSet()); + boolean all = include.contains("*") || include.isEmpty(); + AtomicReference tag = new AtomicReference<>(); + + _modules.stream() + .filter(m-> { - status = "[t]"; - } - else if (module.isEnabled()) + boolean included = all || m.getTags().stream().anyMatch(t->include.contains(t)); + boolean excluded = m.getTags().stream().anyMatch(t->exclude.contains(t)); + return included && !excluded; + }) + .sorted() + .forEach(module-> { - status = "[x]"; - } - - System.out.printf("%n %s Module: %s%n",status,module.getName()); - if (module.getProvides().size()>1) - { - System.out.printf(" Provides: %s%n",module.getProvides()); - } - for (String description : module.getDescription()) - { - System.out.printf(" : %s%n",description); - } - for (String parent : module.getDepends()) - { - System.out.printf(" Depend: %s%n",parent); - } - for (String optional : module.getOptional()) - { - System.out.printf(" Optional: %s%n",optional); - } - for (String lib : module.getLibs()) - { - System.out.printf(" LIB: %s%n",lib); - } - for (String xml : module.getXmls()) - { - System.out.printf(" XML: %s%n",xml); - } - for (String jvm : module.getJvmArgs()) - { - System.out.printf(" JVM: %s%n",jvm); - } - if (module.isEnabled()) - { - for (String selection : module.getEnableSources()) + if (!module.getPrimaryTag().equals(tag.get())) { - System.out.printf(" Enabled: %s%n",selection); + tag.set(module.getPrimaryTag()); + System.out.printf("%nModules for tag '%s':%n",module.getPrimaryTag()); + System.out.print("-------------------"); + for (int i=module.getPrimaryTag().length();i-->0;) + System.out.print("-"); + System.out.println(); + } - } - }); + + String label; + Set provides = module.getProvides(); + provides.remove(module.getName()); + System.out.printf("%n Module: %s %s%n",module.getName(),provides.size()>0?provides:""); + for (String description : module.getDescription()) + { + System.out.printf(" : %s%n",description); + } + if (!module.getTags().isEmpty()) + { + label=" Tags: %s"; + for (String t : module.getTags()) + { + System.out.printf(label,t); + label=", %s"; + } + System.out.println(); + } + if (!module.getDepends().isEmpty()) + { + label=" Depend: %s"; + for (String parent : module.getDepends()) + { + System.out.printf(label,parent); + label=", %s"; + } + System.out.println(); + } + if (!module.getOptional().isEmpty()) + { + label=" Optional: %s"; + for (String parent : module.getOptional()) + { + System.out.printf(label,parent); + label=", %s"; + } + System.out.println(); + } + for (String lib : module.getLibs()) + { + System.out.printf(" LIB: %s%n",lib); + } + for (String xml : module.getXmls()) + { + System.out.printf(" XML: %s%n",xml); + } + for (String jvm : module.getJvmArgs()) + { + System.out.printf(" JVM: %s%n",jvm); + } + if (module.isEnabled()) + { + for (String selection : module.getEnableSources()) + { + System.out.printf(" Enabled: %s%n",selection); + } + } + }); } public void dumpEnabled() @@ -125,6 +158,8 @@ public class Modules implements Iterable index=""; name=""; } + if (module.isTransitive() && module.hasIniTemplate()) + System.out.printf(" init template available with --add-to-start=%s%n",module.getName()); } } @@ -262,13 +297,9 @@ public class Modules implements Iterable } // Enable the module - if (module.isEnabled() && !transitive) + if (module.enable(enabledFrom,transitive)) { - StartLog.info("Module %s has already been enabled.", module.getName()); - } - else if (module.enable(enabledFrom,transitive)) - { - StartLog.debug("Enabled %s",module.getName()); + StartLog.debug("enabled %s",module.getName()); newlyEnabled.add(module.getName()); // Expand module properties @@ -283,9 +314,7 @@ public class Modules implements Iterable m.expandProperties(_args.getProperties()); } } - else if (module.isTransitive() && module.hasIniTemplate()) - newlyEnabled.add(module.getName()); - + // Process module dependencies (always processed as may be dynamic) for(String dependsOn:module.getDepends()) { @@ -321,7 +350,7 @@ public class Modules implements Iterable // Is there an obvious default? Optional dftProvider = providers.stream().filter(m->m.getName().equals(dependsOn)).findFirst(); if (dftProvider.isPresent()) - enable(newlyEnabled,dftProvider.get(),"default provider of "+dependsOn+" for "+module.getName(),true); + enable(newlyEnabled,dftProvider.get(),"transitive provider of "+dependsOn+" for "+module.getName(),true); else if (StartLog.isDebugEnabled()) StartLog.debug("Module %s requires %s from one of %s",module,dependsOn,providers); } diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java b/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java index 81327fa7f66..ec6397fb777 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java @@ -170,7 +170,7 @@ public class StartArgs private boolean help = false; private boolean stopCommand = false; - private boolean listModules = false; + private List listModules = null; private boolean listClasspath = false; private boolean listConfig = false; private boolean version = false; @@ -364,7 +364,7 @@ public class StartArgs } else { - System.out.printf(" %s = %s%n",key,properties.expand(prop.value)); + System.out.printf(" %s = %s%n",key,prop.value); if (StartLog.isDebugEnabled()) { System.out.printf(" origin: %s%n",prop.origin); @@ -372,7 +372,7 @@ public class StartArgs { prop = prop.overrides; System.out.printf(" (overrides)%n"); - System.out.printf(" %s = %s%n",key,properties.expand(prop.value)); + System.out.printf(" %s = %s%n",key,prop.value); System.out.printf(" origin: %s%n",prop.origin); } } @@ -398,7 +398,7 @@ public class StartArgs for (String key : sortedKeys) { String value = System.getProperty(key); - System.out.printf(" %s = %s%n",key,properties.expand(value)); + System.out.printf(" %s = %s%n",key,value); } } @@ -750,7 +750,7 @@ public class StartArgs return listConfig; } - public boolean isListModules() + public List getListModules() { return listModules; } @@ -873,7 +873,7 @@ public class StartArgs if (arg.equals("--create-files")) { run = false; - download = true; + download = true;boolean licenseCheckRequired = true; return; } @@ -938,10 +938,25 @@ public class StartArgs return; } + // Module Management + if ("--list-all-modules".equals(arg)) + { + listModules = Collections.singletonList("*"); + run = false; + return; + } + // Module Management if ("--list-modules".equals(arg)) { - listModules = true; + listModules = Collections.singletonList("-internal"); + run = false; + return; + } + + if (arg.startsWith("--list-modules=")) + { + listModules = Props.getValues(arg); run = false; return; } @@ -958,7 +973,7 @@ public class StartArgs if (arg.startsWith("--add-to-startd=")) { String value = Props.getValue(arg); - StartLog.warn("--add-to-startd is deprecated! Instead use: --add-to-start=%s",value); + StartLog.warn("--add-to-startd is deprecated! Instead use: --create-startd --add-to-start=%s",value); createStartd=true; startModules.addAll(Props.getValues(arg)); run = false; @@ -1035,13 +1050,33 @@ public class StartArgs } // Is this a raw property declaration? - int idx = arg.indexOf('='); - if (idx >= 0) + int equals = arg.indexOf('='); + if (equals >= 0) { - String key = arg.substring(0,idx); - String value = arg.substring(idx + 1); + String key = arg.substring(0,equals); + String value = arg.substring(equals + 1); - if (replaceProps) + if (key.endsWith("+")) + { + key = key.substring(0,key.length()-1); + String orig = getProperties().getString(key); + if (orig != null && !orig.isEmpty()) + { + value=orig+value; + source=propertySource.get(key)+","+source; + } + } + else if (key.endsWith(",")) + { + key = key.substring(0,key.length()-1); + String orig = getProperties().getString(key); + if (orig != null && !orig.isEmpty()) + { + value=value.isEmpty()?orig:(orig+","+value); + source=propertySource.get(key)+","+source; + } + } + else if (replaceProps) { if (propertySource.containsKey(key)) { @@ -1050,21 +1085,10 @@ public class StartArgs propertySource.put(key,source); } - if ("OPTION".equals(key) || "OPTIONS".equals(key)) - { - StringBuilder warn = new StringBuilder(); - warn.append("The behavior of the argument "); - warn.append(arg).append(" (seen in ").append(source); - warn.append(") has changed, and is now considered a normal property. "); - warn.append(key).append(" no longer controls what libraries are on your classpath,"); - warn.append(" use --module instead. See --help for details."); - StartLog.warn(warn.toString()); - } - setProperty(key,value,source,replaceProps); return; } - + // Is this an xml file? if (FS.isXml(arg)) { @@ -1169,7 +1193,9 @@ public class StartArgs return; } - if (replaceProp || (!properties.containsKey(key))) + if (value==null || value.isEmpty()) + properties.remove(key,value,source); + else if (replaceProp || (!properties.containsKey(key))) { properties.setProperty(key,value,source); if(key.equals("java.version")) diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/builders/StartDirBuilder.java b/jetty-start/src/main/java/org/eclipse/jetty/start/builders/StartDirBuilder.java index 5f6fca2ae87..23b239c6566 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/builders/StartDirBuilder.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/builders/StartDirBuilder.java @@ -50,7 +50,7 @@ public class StartDirBuilder implements BaseBuilder.Config } @Override - public boolean addModule(Module module) throws IOException + public String addModule(Module module) throws IOException { if (module.isDynamic()) { @@ -59,28 +59,20 @@ public class StartDirBuilder implements BaseBuilder.Config // warn StartLog.warn("%-15s not adding [ini-template] from dynamic module",module.getName()); } - return false; - } - - String mode = ""; - if (module.isTransitive()) - { - mode = "(transitively) "; + return null; } if (module.hasIniTemplate() || !module.isTransitive()) { // Create start.d/{name}.ini Path ini = startDir.resolve(module.getName() + ".ini"); - StartLog.info("%-15s initialised %sin %s",module.getName(),mode,baseHome.toShortForm(ini)); - try (BufferedWriter writer = Files.newBufferedWriter(ini,StandardCharsets.UTF_8,StandardOpenOption.CREATE,StandardOpenOption.TRUNCATE_EXISTING)) { module.writeIniSection(writer); } - return true; + return baseHome.toShortForm(ini); } - return false; + return null; } } diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/builders/StartIniBuilder.java b/jetty-start/src/main/java/org/eclipse/jetty/start/builders/StartIniBuilder.java index d3027489578..369837032be 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/builders/StartIniBuilder.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/builders/StartIniBuilder.java @@ -21,7 +21,6 @@ package org.eclipse.jetty.start.builders; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; -import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; @@ -86,8 +85,14 @@ public class StartIniBuilder implements BaseBuilder.Config } @Override - public boolean addModule(Module module) throws IOException + public String addModule(Module module) throws IOException { + if (modulesPresent.contains(module.getName())) + { + StartLog.info("%-15s already initialised in %s",module.getName(),baseHome.toShortForm(startIni)); + // skip, already present + return null; + } if (module.isDynamic()) { @@ -96,27 +101,19 @@ public class StartIniBuilder implements BaseBuilder.Config // warn StartLog.warn("%-15s not adding [ini-template] from dynamic module",module.getName()); } - return false; - } - - String mode = ""; - if (module.isTransitive()) - { - mode = "(transitively) "; + return null; } if (module.hasIniTemplate() || !module.isTransitive()) { - StartLog.info("%-15s initialised %sin %s",module.getName(),mode,baseHome.toShortForm(startIni)); - // Append to start.ini try (BufferedWriter writer = Files.newBufferedWriter(startIni,StandardCharsets.UTF_8,StandardOpenOption.APPEND,StandardOpenOption.CREATE)) { module.writeIniSection(writer); } - return true; + return baseHome.toShortForm(startIni); } - return false; + return null; } } diff --git a/jetty-start/src/main/resources/org/eclipse/jetty/start/usage.txt b/jetty-start/src/main/resources/org/eclipse/jetty/start/usage.txt index 27f76f44016..44e39c2c8b8 100644 --- a/jetty-start/src/main/resources/org/eclipse/jetty/start/usage.txt +++ b/jetty-start/src/main/resources/org/eclipse/jetty/start/usage.txt @@ -59,7 +59,7 @@ Debug and Start Logging: Module Management: ------------------ - --list-modules List all modules defined by the system. + --list-modules List non verbose modules defined by the system. Looking for module files in ${jetty.base}/modules/*.mod and then ${jetty.home}/modules/*.mod Will also list enabled state based on information @@ -67,6 +67,13 @@ Module Management: o The command line o The ${jetty.base}/start.ini o The ${jetty.base}/start.d/*.ini files + + --list-modules=(,)* + List modules by tag. Use '*' for all tags. Prefix a tag + with '-' to exclude the tag. + + --list-all-modules + List all modules. --module=(,)* Temporarily enable a module from the command line. @@ -140,6 +147,15 @@ Startup / Shutdown Command Line: Properties: + name=value + Set a property that can be expanded in XML files with the element. + + name+=value + Add to an existing property. + + name,=value + Add to an existing property as a comma separated list. + STOP.HOST=[string] The host to use to stop the running Jetty server (defaults to 127.0.0.1) Required along with STOP.PORT if you want to use the --stop option above. diff --git a/jetty-start/src/test/resources/usecases/alternate.ModulePriorEnabled.cmdline.txt b/jetty-start/src/test/resources/usecases/alternate.ModulePriorEnabled.cmdline.txt deleted file mode 100644 index 974f60e896a..00000000000 --- a/jetty-start/src/test/resources/usecases/alternate.ModulePriorEnabled.cmdline.txt +++ /dev/null @@ -1 +0,0 @@ ---module=base diff --git a/jetty-start/src/test/resources/usecases/alternate.ModulePriorEnabled.assert.txt b/jetty-start/src/test/resources/usecases/barebones.alreadyEnabled.assert.txt similarity index 70% rename from jetty-start/src/test/resources/usecases/alternate.ModulePriorEnabled.assert.txt rename to jetty-start/src/test/resources/usecases/barebones.alreadyEnabled.assert.txt index 81f4462c148..9b924722124 100644 --- a/jetty-start/src/test/resources/usecases/alternate.ModulePriorEnabled.assert.txt +++ b/jetty-start/src/test/resources/usecases/barebones.alreadyEnabled.assert.txt @@ -10,4 +10,8 @@ LIB|${jetty.home}/lib/other.jar # The Properties we expect (order is irrelevant) PROP|main.prop=value0 -OUTPUT|INFO : Module base has already been enabled. \ No newline at end of file +# Files / Directories to create +EXISTS|maindir/ +EXISTS|start.ini + +OUTPUT|INFO : main already enabled by \[\$\{jetty.base}/start.ini] diff --git a/jetty-start/src/test/resources/usecases/barebones.alreadyEnabled.prepare.txt b/jetty-start/src/test/resources/usecases/barebones.alreadyEnabled.prepare.txt new file mode 100644 index 00000000000..b780ce19332 --- /dev/null +++ b/jetty-start/src/test/resources/usecases/barebones.alreadyEnabled.prepare.txt @@ -0,0 +1 @@ +--add-to-start=main diff --git a/jetty-start/src/test/resources/usecases/basic-properties.assert.txt b/jetty-start/src/test/resources/usecases/basic-properties.assert.txt index 4e90c5d74ae..e0c620efe12 100644 --- a/jetty-start/src/test/resources/usecases/basic-properties.assert.txt +++ b/jetty-start/src/test/resources/usecases/basic-properties.assert.txt @@ -12,3 +12,5 @@ PROP|main.prop=value0 PROP|port=9090 PROP|other=value PROP|jetty.http.port=9090 +PROP|add=beginningmiddleend +PROP|list=one,two,three diff --git a/jetty-start/src/test/resources/usecases/basic-properties.cmdline.txt b/jetty-start/src/test/resources/usecases/basic-properties.cmdline.txt index 8c38c4dcd41..759df59e929 100644 --- a/jetty-start/src/test/resources/usecases/basic-properties.cmdline.txt +++ b/jetty-start/src/test/resources/usecases/basic-properties.cmdline.txt @@ -1,2 +1,8 @@ other=value port=9090 +add+=beginning +add+=middle +add+=end +list,=one +list,=two +list,=three diff --git a/jetty-start/src/test/resources/usecases/empty.addToStart.assert.txt b/jetty-start/src/test/resources/usecases/empty.addToStart.assert.txt index 10651695c51..9b2e1bbaa03 100644 --- a/jetty-start/src/test/resources/usecases/empty.addToStart.assert.txt +++ b/jetty-start/src/test/resources/usecases/empty.addToStart.assert.txt @@ -14,7 +14,7 @@ LIB|${jetty.home}/lib/extra/extra1.jar # The Properties we expect (order is irrelevant) PROP|extra.prop=value0 -PROP|main.prop=valueT +PROP|main.prop=value0 PROP|optional.prop=value0 # Files / Directories to create diff --git a/jetty-start/src/test/resources/usecases/empty.addToStartCreateStartd.assert.txt b/jetty-start/src/test/resources/usecases/empty.addToStartCreateStartd.assert.txt index 6b2ed3d8921..2445f98b829 100644 --- a/jetty-start/src/test/resources/usecases/empty.addToStartCreateStartd.assert.txt +++ b/jetty-start/src/test/resources/usecases/empty.addToStartCreateStartd.assert.txt @@ -14,12 +14,11 @@ LIB|${jetty.home}/lib/extra/extra1.jar # The Properties we expect (order is irrelevant) PROP|extra.prop=value0 -PROP|main.prop=valueT +PROP|main.prop=value0 PROP|optional.prop=value0 # Files / Directories to create EXISTS|maindir/ -EXISTS|start.d/main.ini EXISTS|start.d/extra.ini EXISTS|start.d/optional.ini diff --git a/jetty-start/src/test/resources/usecases/empty.createStartd.assert.txt b/jetty-start/src/test/resources/usecases/empty.createStartd.assert.txt index 01db3aca0da..91c169d0621 100644 --- a/jetty-start/src/test/resources/usecases/empty.createStartd.assert.txt +++ b/jetty-start/src/test/resources/usecases/empty.createStartd.assert.txt @@ -14,12 +14,11 @@ LIB|${jetty.home}/lib/extra/extra1.jar # The Properties we expect (order is irrelevant) PROP|extra.prop=value0 -PROP|main.prop=valueT +PROP|main.prop=value0 PROP|optional.prop=value0 # Files / Directories to create EXISTS|maindir/ EXISTS|start.d/ -EXISTS|start.d/main.ini EXISTS|start.d/extra.ini EXISTS|start.d/optional.ini diff --git a/jetty-start/src/test/resources/usecases/transientWithoutIniTemplate/modules/transient.mod b/jetty-start/src/test/resources/usecases/transientWithoutIniTemplate/modules/transient.mod index 222f937fecc..57a3e004817 100644 --- a/jetty-start/src/test/resources/usecases/transientWithoutIniTemplate/modules/transient.mod +++ b/jetty-start/src/test/resources/usecases/transientWithoutIniTemplate/modules/transient.mod @@ -4,5 +4,8 @@ etc/t.xml [optional] main +[ini] +transient.option=transient + [ini-template] transient.option=transient diff --git a/jetty-unixsocket/src/main/config/etc/jetty-unixsocket-http2c.xml b/jetty-unixsocket/src/main/config/etc/jetty-unixsocket-http2c.xml index 1213f1b2fd9..40494fd5c79 100644 --- a/jetty-unixsocket/src/main/config/etc/jetty-unixsocket-http2c.xml +++ b/jetty-unixsocket/src/main/config/etc/jetty-unixsocket-http2c.xml @@ -10,7 +10,7 @@ - + diff --git a/jetty-unixsocket/src/main/config/modules/unixsocket-forwarded.mod b/jetty-unixsocket/src/main/config/modules/unixsocket-forwarded.mod index 80d19995880..cb14381ebae 100644 --- a/jetty-unixsocket/src/main/config/modules/unixsocket-forwarded.mod +++ b/jetty-unixsocket/src/main/config/modules/unixsocket-forwarded.mod @@ -4,6 +4,9 @@ by the Unix Domain Socket connector, for use when behind a proxy operating in HTTP mode that adds forwarded-for style HTTP headers. Typically this is an alternate to the Proxy Protocol used mostly for TCP mode. +[Tags] +connector + [depend] unixsocket-http diff --git a/jetty-unixsocket/src/main/config/modules/unixsocket-http.mod b/jetty-unixsocket/src/main/config/modules/unixsocket-http.mod index 05c46bee795..1605722f685 100644 --- a/jetty-unixsocket/src/main/config/modules/unixsocket-http.mod +++ b/jetty-unixsocket/src/main/config/modules/unixsocket-http.mod @@ -4,6 +4,10 @@ It should be used when a proxy is forwarding either HTTP or decrypted HTTPS traffic to the connector and may be used with the unix-socket-http2c modules to upgrade to HTTP/2. +[Tags] +connector +http + [depend] unixsocket diff --git a/jetty-unixsocket/src/main/config/modules/unixsocket-http2c.mod b/jetty-unixsocket/src/main/config/modules/unixsocket-http2c.mod index 4755fe7e02c..6e112221cfe 100644 --- a/jetty-unixsocket/src/main/config/modules/unixsocket-http2c.mod +++ b/jetty-unixsocket/src/main/config/modules/unixsocket-http2c.mod @@ -3,6 +3,10 @@ Adds a HTTP2C connetion factory to the Unix Domain Socket Connector It can be used when either the proxy forwards direct HTTP/2C (unecrypted) or decrypted HTTP/2 traffic. +[Tags] +connector +http2 + [depend] unixsocket-http @@ -16,6 +20,5 @@ etc/jetty-unixsocket-http2c.xml ## Max number of concurrent streams per connection # jetty.http2.maxConcurrentStreams=1024 -## Initial stream send (server to client) window -# jetty.http2.initialStreamSendWindow=65535 - +## Initial stream receive window (client to server) +# jetty.http2.initialStreamRecvWindow=65535 diff --git a/jetty-unixsocket/src/main/config/modules/unixsocket-proxy-protocol.mod b/jetty-unixsocket/src/main/config/modules/unixsocket-proxy-protocol.mod index 11184d39471..cfa3c726fb7 100644 --- a/jetty-unixsocket/src/main/config/modules/unixsocket-proxy-protocol.mod +++ b/jetty-unixsocket/src/main/config/modules/unixsocket-proxy-protocol.mod @@ -8,6 +8,9 @@ SSL properties may be interpreted by the unixsocket-secure module to indicate secure HTTPS traffic. Typically this is an alternate to the forwarded module. +[Tags] +connector + [depend] unixsocket diff --git a/jetty-unixsocket/src/main/config/modules/unixsocket-secure.mod b/jetty-unixsocket/src/main/config/modules/unixsocket-secure.mod index 43344706038..8d099b539fa 100644 --- a/jetty-unixsocket/src/main/config/modules/unixsocket-secure.mod +++ b/jetty-unixsocket/src/main/config/modules/unixsocket-secure.mod @@ -5,6 +5,9 @@ This looks for a secure scheme transported either by the unixsocket-forwarded, unixsocket-proxy-protocol or in a HTTP2 request. +[Tags] +connector + [depend] unixsocket-http diff --git a/jetty-unixsocket/src/main/config/modules/unixsocket.mod b/jetty-unixsocket/src/main/config/modules/unixsocket.mod index c27ec9d2f43..f4defea923c 100644 --- a/jetty-unixsocket/src/main/config/modules/unixsocket.mod +++ b/jetty-unixsocket/src/main/config/modules/unixsocket.mod @@ -7,6 +7,9 @@ needless fragmentation and have better dispatch behaviours. When enabled with corresponding support modules, the connector can accept HTTP, HTTPS or HTTP2C traffic. +[Tags] +connector + [depend] server diff --git a/jetty-util/src/main/config/modules/jcl.mod b/jetty-util/src/main/config/modules/jcl-impl.mod similarity index 95% rename from jetty-util/src/main/config/modules/jcl.mod rename to jetty-util/src/main/config/modules/jcl-impl.mod index c72533a6c40..6569c5c52e4 100644 --- a/jetty-util/src/main/config/modules/jcl.mod +++ b/jetty-util/src/main/config/modules/jcl-impl.mod @@ -2,6 +2,11 @@ Provides a Java Commons Logging implementation. To receive jetty logs the jetty-slf4j and slf4j-jcl must also be enabled. +[tags] +logging +jcl +internal + [depends] [provides] diff --git a/jetty-util/src/main/config/modules/jcl-slf4j.mod b/jetty-util/src/main/config/modules/jcl-slf4j.mod index bc5ebfbbf03..7cabf92dcaa 100644 --- a/jetty-util/src/main/config/modules/jcl-slf4j.mod +++ b/jetty-util/src/main/config/modules/jcl-slf4j.mod @@ -1,6 +1,11 @@ [description] -Provides a Java Commons Logging implementation that logs to the SLF4J API. -Requires another module that provides and SLF4J implementation. +Provides a Java Commons Logging (JCL) to SLF4J logging bridge. + +[tags] +logging +jcl +slf4j +internal [depends] slf4j-api diff --git a/jetty-util/src/main/config/modules/jetty-jul.mod b/jetty-util/src/main/config/modules/jetty-jul.mod deleted file mode 100644 index ed7340af74c..00000000000 --- a/jetty-util/src/main/config/modules/jetty-jul.mod +++ /dev/null @@ -1,9 +0,0 @@ -[description] -Provides a Jetty Logging implementation that logs to the Java Util Logging API. -Requires another module that provides a Java Util Logging implementation. - -[provide] -logging - -[exec] --Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.JavaUtilLog diff --git a/jetty-util/src/main/config/modules/jetty-log4j.mod b/jetty-util/src/main/config/modules/jetty-log4j.mod deleted file mode 100644 index 7717400b784..00000000000 --- a/jetty-util/src/main/config/modules/jetty-log4j.mod +++ /dev/null @@ -1,8 +0,0 @@ -[description] -Provides a Jetty Logging implementation that logs to the log4j API. -Uses the slf4j mechanism as an intermediary -Requires another module that provides an log4j implementation. - -[depend] -jetty-slf4j -slf4j-log4j diff --git a/jetty-util/src/main/config/modules/jetty-log4j2.mod b/jetty-util/src/main/config/modules/jetty-log4j2.mod deleted file mode 100644 index c77ca46b8ba..00000000000 --- a/jetty-util/src/main/config/modules/jetty-log4j2.mod +++ /dev/null @@ -1,8 +0,0 @@ -[description] -Provides a Jetty Logging implementation that logs to the log4j API. -Uses the slf4j and log4j v1.2 mechanisms as intermediaries. -Requires another module that provides an log4j2 implementation. - -[depend] -jetty-slf4j -slf4j-log4j2 diff --git a/jetty-util/src/main/config/modules/jetty-logback.mod b/jetty-util/src/main/config/modules/jetty-logback.mod deleted file mode 100644 index e5373fd5301..00000000000 --- a/jetty-util/src/main/config/modules/jetty-logback.mod +++ /dev/null @@ -1,7 +0,0 @@ -[description] -Provides a Jetty Logging implementation that logs to logback. -Uses the slf4j API as an intermediary - -[depend] -jetty-slf4j -slf4j-logback diff --git a/jetty-util/src/main/config/modules/jetty-logging.mod b/jetty-util/src/main/config/modules/jetty-logging.mod deleted file mode 100644 index 3b46e5954ca..00000000000 --- a/jetty-util/src/main/config/modules/jetty-logging.mod +++ /dev/null @@ -1,13 +0,0 @@ -[description] -Enables the Jetty Logging implementation and installs a template -configuration in ${jetty.base} resources/jetty-logging.properties. - -[depends] -resources - -[provide] -logging - -[files] -basehome:modules/jetty-logging/jetty-logging.properties|resources/jetty-logging.properties - diff --git a/jetty-util/src/main/config/modules/jetty-slf4j.mod b/jetty-util/src/main/config/modules/jetty-slf4j.mod deleted file mode 100644 index 3836363748d..00000000000 --- a/jetty-util/src/main/config/modules/jetty-slf4j.mod +++ /dev/null @@ -1,13 +0,0 @@ -[description] -Provides a Jetty Logging implementation that logs to the SLF4J API. -Requires another module that provides and SLF4J implementation. - -[depend] -slf4j-api -slf4j-impl - -[provide] -logging - -[exec] --Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.Slf4jLog diff --git a/jetty-util/src/main/config/modules/log4j.mod b/jetty-util/src/main/config/modules/log4j-impl.mod similarity index 95% rename from jetty-util/src/main/config/modules/log4j.mod rename to jetty-util/src/main/config/modules/log4j-impl.mod index 437a297afaa..be7bd2c0249 100644 --- a/jetty-util/src/main/config/modules/log4j.mod +++ b/jetty-util/src/main/config/modules/log4j-impl.mod @@ -2,6 +2,11 @@ Provides a Log4j v1.2 API and implementation. To receive jetty logs enable the jetty-slf4j and slf4j-log4j modules. +[tags] +logging +log4j +internal + [depends] resources diff --git a/jetty-util/src/main/config/modules/log4j-log4j2.mod b/jetty-util/src/main/config/modules/log4j-log4j2.mod index 7a055ee07e1..b17cf60e9c6 100644 --- a/jetty-util/src/main/config/modules/log4j-log4j2.mod +++ b/jetty-util/src/main/config/modules/log4j-log4j2.mod @@ -1,7 +1,11 @@ [description] -Provides a Log4j v1.2 implementation that logs to the Log4j v2 API. -Requires another module that provides and Log4j v2 implementation. -To receive jetty logs the jetty-slf4j and slf4j-log4j must also be enabled. +Provides a Log4j v1.2 to Log4j v2 logging bridge. + +[tags] +logging +log4j2 +log4j +internal [depends] log4j2-api diff --git a/jetty-util/src/main/config/modules/log4j2-api.mod b/jetty-util/src/main/config/modules/log4j2-api.mod index 3244acf19f0..cd54e43e2b5 100644 --- a/jetty-util/src/main/config/modules/log4j2-api.mod +++ b/jetty-util/src/main/config/modules/log4j2-api.mod @@ -1,7 +1,11 @@ [description] Provides the Log4j v2 API -Requires another module that provides an Log4j v2 implementation. -To receive jetty logs enable the jetty-slf4j, slf4j-log4j and log4j-log4j2 modules. + +[tags] +logging +log4j2 +log4j +internal [files] maven://org.apache.logging.log4j/log4j-api/${log4j2.version}|lib/log4j/log4j-api-${log4j2.version}.jar diff --git a/jetty-util/src/main/config/modules/log4j2-core.mod b/jetty-util/src/main/config/modules/log4j2-impl.mod similarity index 91% rename from jetty-util/src/main/config/modules/log4j2-core.mod rename to jetty-util/src/main/config/modules/log4j2-impl.mod index 9b04f2013ad..767c40cee57 100644 --- a/jetty-util/src/main/config/modules/log4j2-core.mod +++ b/jetty-util/src/main/config/modules/log4j2-impl.mod @@ -2,6 +2,12 @@ Provides a Log4j v2 implementation. To receive jetty logs enable the jetty-slf4j, slf4j-log4j and log4j-log4j2 modules. +[tags] +logging +log4j2 +log4j +internal + [depends] log4j2-api resources diff --git a/jetty-util/src/main/config/modules/log4j2-slf4j.mod b/jetty-util/src/main/config/modules/log4j2-slf4j.mod index 6324c0d37d4..20ea8bb72b6 100644 --- a/jetty-util/src/main/config/modules/log4j2-slf4j.mod +++ b/jetty-util/src/main/config/modules/log4j2-slf4j.mod @@ -1,7 +1,12 @@ [description] -Provides a Log4j v2 implementation that logs to the SLF4J API. -Requires another module that provides and SLF4J implementation. -To receive jetty logs enable the jetty-slf4j module. +Provides a Log4j v2 to SLF4J logging bridge. + +[tags] +logging +log4j2 +log4j +slf4j +internal [depends] log4j2-api diff --git a/jetty-util/src/main/config/modules/logback-core.mod b/jetty-util/src/main/config/modules/logback-impl.mod similarity index 93% rename from jetty-util/src/main/config/modules/logback-core.mod rename to jetty-util/src/main/config/modules/logback-impl.mod index fa2832bd52c..a6d3db96d36 100644 --- a/jetty-util/src/main/config/modules/logback-core.mod +++ b/jetty-util/src/main/config/modules/logback-impl.mod @@ -1,7 +1,11 @@ [description] -Provides the logback core implementation, used by slf4j-logback +Provides the logback core implementation and logback-access +[tags] +logging +internal + [files] maven://ch.qos.logback/logback-core/${logback.version}|lib/logback/logback-core-${logback.version}.jar diff --git a/jetty-util/src/main/config/modules/logging-jcl.mod b/jetty-util/src/main/config/modules/logging-jcl.mod new file mode 100644 index 00000000000..718affe557f --- /dev/null +++ b/jetty-util/src/main/config/modules/logging-jcl.mod @@ -0,0 +1,20 @@ +[description] +Configure jetty logging to use Java Commons Logging (jcl) +Uses SLF4j as a logging bridge. + +[tags] +logging + +[depends] +slf4j-jcl +jcl-impl + +[provide] +logging + +[exec] +-Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.Slf4jLog + +[ini-template] +## Hide logging classes from deployed webapps +jetty.webapp.addServerClasses,=file:${jetty.base}/lib/slf4j/,file:${jetty.base}/lib/jul diff --git a/jetty-util/src/main/config/modules/logging-jetty.mod b/jetty-util/src/main/config/modules/logging-jetty.mod new file mode 100644 index 00000000000..c7ad54ec27e --- /dev/null +++ b/jetty-util/src/main/config/modules/logging-jetty.mod @@ -0,0 +1,15 @@ +[description] +Configure jetty logging mechanism. +Provides a ${jetty.base}/resources/jetty-logging.properties. + +[tags] +logging + +[depends] +resources + +[provide] +logging + +[files] +basehome:modules/logging-jetty/jetty-logging.properties|resources/jetty-logging.properties diff --git a/jetty-util/src/main/config/modules/jetty-logging/jetty-logging.properties b/jetty-util/src/main/config/modules/logging-jetty/jetty-logging.properties similarity index 100% rename from jetty-util/src/main/config/modules/jetty-logging/jetty-logging.properties rename to jetty-util/src/main/config/modules/logging-jetty/jetty-logging.properties diff --git a/jetty-util/src/main/config/modules/logging-jul.mod b/jetty-util/src/main/config/modules/logging-jul.mod new file mode 100644 index 00000000000..7c7323c8a90 --- /dev/null +++ b/jetty-util/src/main/config/modules/logging-jul.mod @@ -0,0 +1,19 @@ +[description] +Configure jetty logging to use Java Util Logging (jul) +Uses SLF4j as a logging bridge. + +[tags] +logging + +[depends] +slf4j-jul + +[provide] +logging + +[exec] +-Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.Slf4jLog + +[ini-template] +## Hide logging classes from deployed webapps +jetty.webapp.addServerClasses,=file:${jetty.base}/lib/slf4j/ diff --git a/jetty-util/src/main/config/modules/logging-log4j.mod b/jetty-util/src/main/config/modules/logging-log4j.mod new file mode 100644 index 00000000000..ce81ca8ae23 --- /dev/null +++ b/jetty-util/src/main/config/modules/logging-log4j.mod @@ -0,0 +1,20 @@ +[description] +Configure jetty logging to use Log4j Logging +Uses SLF4j as a logging bridge. + +[tags] +logging + +[depends] +slf4j-log4j +log4j-impl + +[provide] +logging + +[exec] +-Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.Slf4jLog + +[ini-template] +## Hide logging classes from deployed webapps +jetty.webapp.addServerClasses,=file:${jetty.base}/lib/slf4j/,file:${jetty.base}/lib/log4j/ diff --git a/jetty-util/src/main/config/modules/logging-log4j2.mod b/jetty-util/src/main/config/modules/logging-log4j2.mod new file mode 100644 index 00000000000..81bbcf056df --- /dev/null +++ b/jetty-util/src/main/config/modules/logging-log4j2.mod @@ -0,0 +1,20 @@ +[description] +Configure jetty logging to use log4j version 2 +Uses SLF4j as a logging bridge. + +[tags] +logging + +[depends] +slf4j-log4j2 +log4j2-impl + +[provide] +logging + +[exec] +-Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.Slf4jLog + +[ini-template] +## Hide logging classes from deployed webapps +jetty.webapp.addServerClasses,=file:${jetty.base}/lib/slf4j/,file:${jetty.base}/lib/log4j/ diff --git a/jetty-util/src/main/config/modules/logging-logback.mod b/jetty-util/src/main/config/modules/logging-logback.mod new file mode 100644 index 00000000000..8223bce022a --- /dev/null +++ b/jetty-util/src/main/config/modules/logging-logback.mod @@ -0,0 +1,20 @@ +[description] +Configure jetty logging to use Logback Logging. +Uses SLF4j as a logging bridge. + +[tags] +logging + +[depends] +slf4j-logback +logback-impl + +[provide] +logging + +[exec] +-Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.Slf4jLog + +[ini-template] +## Hide logging classes from deployed webapps +jetty.webapp.addServerClasses,=file:${jetty.base}/lib/slf4j/,file:${jetty.base}/lib/logback diff --git a/jetty-util/src/main/config/modules/logging-slf4j.mod b/jetty-util/src/main/config/modules/logging-slf4j.mod new file mode 100644 index 00000000000..24b5f367cc7 --- /dev/null +++ b/jetty-util/src/main/config/modules/logging-slf4j.mod @@ -0,0 +1,19 @@ +[description] +Configure jetty logging to use slf4j. +Any slf4j-impl implementation is used + +[tags] +logging + +[depends] +slf4j-impl + +[provide] +logging + +[exec] +-Dorg.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.Slf4jLog + +[ini-template] +## Hide logging classes from deployed webapps +jetty.webapp.addServerClasses,=file:${jetty.base}/lib/slf4j/ diff --git a/jetty-util/src/main/config/modules/logging/logging-classpath.xml b/jetty-util/src/main/config/modules/logging/logging-classpath.xml new file mode 100644 index 00000000000..1f8e737e9bf --- /dev/null +++ b/jetty-util/src/main/config/modules/logging/logging-classpath.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jetty-util/src/main/config/modules/slf4j-api.mod b/jetty-util/src/main/config/modules/slf4j-api.mod index b4eda7f19f8..e2e787f8c4f 100644 --- a/jetty-util/src/main/config/modules/slf4j-api.mod +++ b/jetty-util/src/main/config/modules/slf4j-api.mod @@ -2,6 +2,11 @@ Provides SLF4J API. Requires a slf4j implementation (eg slf4j-simple) otherwise a noop implementation is used. +[tags] +logging +slf4j +internal + [files] maven://org.slf4j/slf4j-api/${slf4j.version}|lib/slf4j/slf4j-api-${slf4j.version}.jar diff --git a/jetty-util/src/main/config/modules/slf4j-simple.mod b/jetty-util/src/main/config/modules/slf4j-impl.mod similarity index 90% rename from jetty-util/src/main/config/modules/slf4j-simple.mod rename to jetty-util/src/main/config/modules/slf4j-impl.mod index 804cde01a03..c44b8bd739c 100644 --- a/jetty-util/src/main/config/modules/slf4j-simple.mod +++ b/jetty-util/src/main/config/modules/slf4j-impl.mod @@ -2,6 +2,11 @@ Provides SLF4J simple logging implementation. To receive jetty logs enable the jetty-slf4j module. +[tags] +logging +slf4j +internal + [depend] slf4j-api diff --git a/jetty-util/src/main/config/modules/slf4j-jcl.mod b/jetty-util/src/main/config/modules/slf4j-jcl.mod index 6a9773a048c..d1819515258 100644 --- a/jetty-util/src/main/config/modules/slf4j-jcl.mod +++ b/jetty-util/src/main/config/modules/slf4j-jcl.mod @@ -1,7 +1,11 @@ [description] -Provides a SLF4J implementation that logs to the Java Commons Logging API. -Requires another module that provides an JCL implementation. -To receive jetty logs enable the jetty-slf4j module. +Provides a SLF4J to Java Commons Logging (JCL) logging bridge. + +[tags] +logging +jcl +slf4j +internal [depend] slf4j-api diff --git a/jetty-util/src/main/config/modules/slf4j-jul.mod b/jetty-util/src/main/config/modules/slf4j-jul.mod index fc858778d2f..f308147e021 100644 --- a/jetty-util/src/main/config/modules/slf4j-jul.mod +++ b/jetty-util/src/main/config/modules/slf4j-jul.mod @@ -1,6 +1,10 @@ [description] -Provides a SLF4J implementation that logs to the Java Util Logging API. -To receive jetty logs enable the jetty-slf4j module. +Provides a SLF4J to Java Util Logging (JUL) logging bridge. + +[tags] +logging +slf4j +internal [depend] slf4j-api diff --git a/jetty-util/src/main/config/modules/slf4j-log4j.mod b/jetty-util/src/main/config/modules/slf4j-log4j.mod index 75c98577d02..e248480ec28 100644 --- a/jetty-util/src/main/config/modules/slf4j-log4j.mod +++ b/jetty-util/src/main/config/modules/slf4j-log4j.mod @@ -1,7 +1,11 @@ [description] -Provides a SLF4J implementation that logs to the Log4j v1.2 API. -Requires another module that provides a Log4j implementation. -To receive jetty logs enable the jetty-slf4j module. +Provides a SLF4J to the Log4j v1.2 API logging bridge. + +[tags] +logging +log4j +slf4j +internal [depend] slf4j-api diff --git a/jetty-util/src/main/config/modules/slf4j-log4j2.mod b/jetty-util/src/main/config/modules/slf4j-log4j2.mod index 2f9d023059e..445d38017f1 100644 --- a/jetty-util/src/main/config/modules/slf4j-log4j2.mod +++ b/jetty-util/src/main/config/modules/slf4j-log4j2.mod @@ -1,7 +1,12 @@ [description] -Provides a SLF4J implementation that logs to the Log4j v2 API. -Requires another module that provides a Log4j2 implementation. -To receive jetty logs enable the jetty-slf4j2 module. +Provides a SLF4J to Log4j v2 logging bridge. + +[tags] +logging +log4j2 +log4j +slf4j +internal [depend] slf4j-api diff --git a/jetty-util/src/main/config/modules/slf4j-logback.mod b/jetty-util/src/main/config/modules/slf4j-logback.mod index 0a23efdad13..6d33a89ced5 100644 --- a/jetty-util/src/main/config/modules/slf4j-logback.mod +++ b/jetty-util/src/main/config/modules/slf4j-logback.mod @@ -1,10 +1,14 @@ [description] -Provides a SLF4J implementation that logs to Logback classic -To receive jetty logs enable the jetty-slf4j module. +Provides a SLF4J to Logback logging bridge. + +[tags] +logging +slf4j +internal [depend] slf4j-api -logback-core +logback-impl resources [provide] diff --git a/jetty-util/src/main/config/modules/stderrout-logging.mod b/jetty-util/src/main/config/modules/stderrout-logging.mod index 846f2dabd84..b1dc2af91e6 100644 --- a/jetty-util/src/main/config/modules/stderrout-logging.mod +++ b/jetty-util/src/main/config/modules/stderrout-logging.mod @@ -2,6 +2,9 @@ Redirects JVMs stderr and stdout to a log file, including output from Jetty's default StdErrLog logging. +[tags] +logging + [xml] etc/stderrout-logging.xml @@ -9,7 +12,6 @@ etc/stderrout-logging.xml logs/ [lib] -lib/logging/**.jar resources/ [ini-template] diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTernaryTrie.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTernaryTrie.java index 710444d353a..8d095f19a06 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTernaryTrie.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTernaryTrie.java @@ -19,8 +19,10 @@ package org.eclipse.jetty.util; import java.nio.ByteBuffer; +import java.util.AbstractMap; import java.util.Arrays; import java.util.HashSet; +import java.util.Map; import java.util.Set; @@ -495,6 +497,39 @@ public class ArrayTernaryTrie extends AbstractTrie return keys; } + public int size() + { + int s=0; + for (int r=0;r<=_rows;r++) + { + if (_key[r]!=null && _value[r]!=null) + s++; + } + return s; + } + + public boolean isEmpty() + { + for (int r=0;r<=_rows;r++) + { + if (_key[r]!=null && _value[r]!=null) + return false; + } + return true; + } + + + public Set> entrySet() + { + Set> entries = new HashSet<>(); + for (int r=0;r<=_rows;r++) + { + if (_key[r]!=null && _value[r]!=null) + entries.add(new AbstractMap.SimpleEntry<>(_key[r],_value[r])); + } + return entries; + } + @Override public boolean isFull() { @@ -524,4 +559,143 @@ public class ArrayTernaryTrie extends AbstractTrie } } + + public static class Growing implements Trie + { + private final int _growby; + private ArrayTernaryTrie _trie; + + public Growing() + { + this(1024,1024); + } + + public Growing(int capacity, int growby) + { + _growby=growby; + _trie = new ArrayTernaryTrie<>(capacity); + } + + public Growing(boolean insensitive, int capacity, int growby) + { + _growby=growby; + _trie = new ArrayTernaryTrie<>(insensitive,capacity); + } + + public boolean put(V v) + { + return put(v.toString(),v); + } + + public int hashCode() + { + return _trie.hashCode(); + } + + public V remove(String s) + { + return _trie.remove(s); + } + + public V get(String s) + { + return _trie.get(s); + } + + public V get(ByteBuffer b) + { + return _trie.get(b); + } + + public V getBest(byte[] b, int offset, int len) + { + return _trie.getBest(b,offset,len); + } + + public boolean isCaseInsensitive() + { + return _trie.isCaseInsensitive(); + } + + public boolean equals(Object obj) + { + return _trie.equals(obj); + } + + public void clear() + { + _trie.clear(); + } + + public boolean put(String s, V v) + { + boolean added = _trie.put(s,v); + while (!added) + { + ArrayTernaryTrie bigger = new ArrayTernaryTrie<>(_trie._key.length+_growby); + for (Map.Entry entry : _trie.entrySet()) + bigger.put(entry.getKey(),entry.getValue()); + added = _trie.put(s,v); + } + + return true; + } + + public V get(String s, int offset, int len) + { + return _trie.get(s,offset,len); + } + + public V get(ByteBuffer b, int offset, int len) + { + return _trie.get(b,offset,len); + } + + public V getBest(String s) + { + return _trie.getBest(s); + } + + public V getBest(String s, int offset, int length) + { + return _trie.getBest(s,offset,length); + } + + public V getBest(ByteBuffer b, int offset, int len) + { + return _trie.getBest(b,offset,len); + } + + public String toString() + { + return _trie.toString(); + } + + public Set keySet() + { + return _trie.keySet(); + } + + public boolean isFull() + { + return false; + } + + public void dump() + { + _trie.dump(); + } + + public boolean isEmpty() + { + return _trie.isEmpty(); + } + + public int size() + { + return _trie.size(); + } + + } + } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ConcurrentArrayQueue.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ConcurrentArrayQueue.java deleted file mode 100644 index efa685168f1..00000000000 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/ConcurrentArrayQueue.java +++ /dev/null @@ -1,577 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.util; - -import java.util.AbstractQueue; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.NoSuchElementException; -import java.util.Objects; -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.atomic.AtomicIntegerArray; -import java.util.concurrent.atomic.AtomicReference; -import java.util.concurrent.atomic.AtomicReferenceArray; - -/** - * A concurrent, unbounded implementation of {@link Queue} that uses singly-linked array blocks - * to store elements. - *

    - * This class is a drop-in replacement for {@link ConcurrentLinkedQueue}, with similar performance - * but producing less garbage because arrays are used to store elements rather than nodes. - *

    - *

    - * The algorithm used is a variation of the algorithm from Gidenstam, Sundell and Tsigas - * (http://www.adm.hb.se/~AGD/Presentations/CacheAwareQueue_OPODIS.pdf). - *

    - * - * @param the Array entry type - */ -public class ConcurrentArrayQueue extends AbstractQueue -{ - public static final int DEFAULT_BLOCK_SIZE = 512; - public static final Object REMOVED_ELEMENT = new Object() - { - @Override - public String toString() - { - return "X"; - } - }; - - private static final int HEAD_OFFSET = MemoryUtils.getIntegersPerCacheLine() - 1; - private static final int TAIL_OFFSET = MemoryUtils.getIntegersPerCacheLine()*2 -1; - - private final AtomicReferenceArray> _blocks = new AtomicReferenceArray<>(TAIL_OFFSET + 1); - private final int _blockSize; - - public ConcurrentArrayQueue() - { - this(DEFAULT_BLOCK_SIZE); - } - - public ConcurrentArrayQueue(int blockSize) - { - _blockSize = blockSize; - Block block = newBlock(); - _blocks.set(HEAD_OFFSET,block); - _blocks.set(TAIL_OFFSET,block); - } - - public int getBlockSize() - { - return _blockSize; - } - - protected Block getHeadBlock() - { - return _blocks.get(HEAD_OFFSET); - } - - protected Block getTailBlock() - { - return _blocks.get(TAIL_OFFSET); - } - - @Override - public boolean offer(T item) - { - item = Objects.requireNonNull(item); - - final Block initialTailBlock = getTailBlock(); - Block currentTailBlock = initialTailBlock; - int tail = currentTailBlock.tail(); - while (true) - { - if (tail == getBlockSize()) - { - Block nextTailBlock = currentTailBlock.next(); - if (nextTailBlock == null) - { - nextTailBlock = newBlock(); - if (currentTailBlock.link(nextTailBlock)) - { - // Linking succeeded, loop - currentTailBlock = nextTailBlock; - } - else - { - // Concurrent linking, use other block and loop - currentTailBlock = currentTailBlock.next(); - } - } - else - { - // Not at last block, loop - currentTailBlock = nextTailBlock; - } - tail = currentTailBlock.tail(); - } - else - { - if (currentTailBlock.peek(tail) == null) - { - if (currentTailBlock.store(tail, item)) - { - // Item stored - break; - } - else - { - // Concurrent store, try next index - ++tail; - } - } - else - { - // Not free, try next index - ++tail; - } - } - } - - updateTailBlock(initialTailBlock, currentTailBlock); - - return true; - } - - private void updateTailBlock(Block oldTailBlock, Block newTailBlock) - { - // Update the tail block pointer if needs to - if (oldTailBlock != newTailBlock) - { - // The tail block pointer is allowed to lag behind. - // If this update fails, it means that other threads - // have filled this block and installed a new one. - casTailBlock(oldTailBlock, newTailBlock); - } - } - - protected boolean casTailBlock(Block current, Block update) - { - return _blocks.compareAndSet(TAIL_OFFSET,current,update); - } - - @SuppressWarnings("unchecked") - @Override - public T poll() - { - final Block initialHeadBlock = getHeadBlock(); - Block currentHeadBlock = initialHeadBlock; - int head = currentHeadBlock.head(); - T result = null; - while (true) - { - if (head == getBlockSize()) - { - Block nextHeadBlock = currentHeadBlock.next(); - if (nextHeadBlock == null) - { - // We could have read that the next head block was null - // but another thread allocated a new block and stored a - // new item. This thread could not detect this, but that - // is ok, otherwise we would not be able to exit this loop. - - // Queue is empty - break; - } - else - { - // Use next block and loop - currentHeadBlock = nextHeadBlock; - head = currentHeadBlock.head(); - } - } - else - { - Object element = currentHeadBlock.peek(head); - if (element == REMOVED_ELEMENT) - { - // Already removed, try next index - ++head; - } - else - { - result = (T)element; - if (result != null) - { - if (currentHeadBlock.remove(head, result, true)) - { - // Item removed - break; - } - else - { - // Concurrent remove, try next index - ++head; - } - } - else - { - // Queue is empty - break; - } - } - } - } - - updateHeadBlock(initialHeadBlock, currentHeadBlock); - - return result; - } - - private void updateHeadBlock(Block oldHeadBlock, Block newHeadBlock) - { - // Update the head block pointer if needs to - if (oldHeadBlock != newHeadBlock) - { - // The head block pointer lagged behind. - // If this update fails, it means that other threads - // have emptied this block and pointed to a new one. - casHeadBlock(oldHeadBlock, newHeadBlock); - } - } - - protected boolean casHeadBlock(Block current, Block update) - { - return _blocks.compareAndSet(HEAD_OFFSET,current,update); - } - - @Override - public T peek() - { - Block currentHeadBlock = getHeadBlock(); - int head = currentHeadBlock.head(); - while (true) - { - if (head == getBlockSize()) - { - Block nextHeadBlock = currentHeadBlock.next(); - if (nextHeadBlock == null) - { - // Queue is empty - return null; - } - else - { - // Use next block and loop - currentHeadBlock = nextHeadBlock; - head = currentHeadBlock.head(); - } - } - else - { - T element = currentHeadBlock.peek(head); - if (element == REMOVED_ELEMENT) - { - // Already removed, try next index - ++head; - } - else - { - return element; - } - } - } - } - - @Override - public boolean remove(Object o) - { - Block currentHeadBlock = getHeadBlock(); - int head = currentHeadBlock.head(); - boolean result = false; - while (true) - { - if (head == getBlockSize()) - { - Block nextHeadBlock = currentHeadBlock.next(); - if (nextHeadBlock == null) - { - // Not found - break; - } - else - { - // Use next block and loop - currentHeadBlock = nextHeadBlock; - head = currentHeadBlock.head(); - } - } - else - { - Object element = currentHeadBlock.peek(head); - if (element == REMOVED_ELEMENT) - { - // Removed, try next index - ++head; - } - else - { - if (element == null) - { - // Not found - break; - } - else - { - if (element.equals(o)) - { - // Found - if (currentHeadBlock.remove(head, o, false)) - { - result = true; - break; - } - else - { - ++head; - } - } - else - { - // Not the one we're looking for - ++head; - } - } - } - } - } - - return result; - } - - @Override - public boolean removeAll(Collection c) - { - // TODO: super invocations are based on iterator.remove(), which throws - return super.removeAll(c); - } - - @Override - public boolean retainAll(Collection c) - { - // TODO: super invocations are based on iterator.remove(), which throws - return super.retainAll(c); - } - - @Override - public Iterator iterator() - { - final List blocks = new ArrayList<>(); - Block currentHeadBlock = getHeadBlock(); - while (currentHeadBlock != null) - { - Object[] elements = currentHeadBlock.arrayCopy(); - blocks.add(elements); - currentHeadBlock = currentHeadBlock.next(); - } - return new Iterator() - { - private int blockIndex; - private int index; - - @Override - public boolean hasNext() - { - while (true) - { - if (blockIndex == blocks.size()) - return false; - - Object element = blocks.get(blockIndex)[index]; - - if (element == null) - return false; - - if (element != REMOVED_ELEMENT) - return true; - - advance(); - } - } - - @Override - public T next() - { - while (true) - { - if (blockIndex == blocks.size()) - throw new NoSuchElementException(); - - Object element = blocks.get(blockIndex)[index]; - - if (element == null) - throw new NoSuchElementException(); - - advance(); - - if (element != REMOVED_ELEMENT) { - @SuppressWarnings("unchecked") - T e = (T)element; - return e; - } - } - } - - private void advance() - { - if (++index == getBlockSize()) - { - index = 0; - ++blockIndex; - } - } - - @Override - public void remove() - { - throw new UnsupportedOperationException(); - } - }; - } - - @Override - public int size() - { - Block currentHeadBlock = getHeadBlock(); - int head = currentHeadBlock.head(); - int size = 0; - while (true) - { - if (head == getBlockSize()) - { - Block nextHeadBlock = currentHeadBlock.next(); - if (nextHeadBlock == null) - { - break; - } - else - { - // Use next block and loop - currentHeadBlock = nextHeadBlock; - head = currentHeadBlock.head(); - } - } - else - { - Object element = currentHeadBlock.peek(head); - if (element == REMOVED_ELEMENT) - { - // Already removed, try next index - ++head; - } - else if (element != null) - { - ++size; - ++head; - } - else - { - break; - } - } - } - return size; - } - - protected Block newBlock() - { - return new Block<>(getBlockSize()); - } - - protected int getBlockCount() - { - int result = 0; - Block headBlock = getHeadBlock(); - while (headBlock != null) - { - ++result; - headBlock = headBlock.next(); - } - return result; - } - - protected static final class Block - { - private static final int headOffset = MemoryUtils.getIntegersPerCacheLine()-1; - private static final int tailOffset = MemoryUtils.getIntegersPerCacheLine()*2-1; - - private final AtomicReferenceArray elements; - private final AtomicReference> next = new AtomicReference<>(); - private final AtomicIntegerArray indexes = new AtomicIntegerArray(TAIL_OFFSET+1); - - protected Block(int blockSize) - { - elements = new AtomicReferenceArray<>(blockSize); - } - - @SuppressWarnings("unchecked") - public E peek(int index) - { - return (E)elements.get(index); - } - - public boolean store(int index, E item) - { - boolean result = elements.compareAndSet(index, null, item); - if (result) - indexes.incrementAndGet(tailOffset); - return result; - } - - public boolean remove(int index, Object item, boolean updateHead) - { - boolean result = elements.compareAndSet(index, item, REMOVED_ELEMENT); - if (result && updateHead) - indexes.incrementAndGet(headOffset); - return result; - } - - public Block next() - { - return next.get(); - } - - public boolean link(Block nextBlock) - { - return next.compareAndSet(null, nextBlock); - } - - public int head() - { - return indexes.get(headOffset); - } - - public int tail() - { - return indexes.get(tailOffset); - } - - public Object[] arrayCopy() - { - Object[] result = new Object[elements.length()]; - for (int i = 0; i < result.length; ++i) - result[i] = elements.get(i); - return result; - } - } -} diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ClassNameResolver.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ConstantThrowable.java similarity index 55% rename from jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ClassNameResolver.java rename to jetty-util/src/main/java/org/eclipse/jetty/util/ConstantThrowable.java index 84905cb5d28..a0c693eb76a 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ClassNameResolver.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ConstantThrowable.java @@ -16,27 +16,27 @@ // ======================================================================== // -package org.eclipse.jetty.annotations; +package org.eclipse.jetty.util; - - -public interface ClassNameResolver +/** + * A {@link Throwable} that may be used in static contexts. It uses Java 7 + * constructor that prevents setting stackTrace inside exception object. + */ +public class ConstantThrowable extends Throwable { - /** - * Based on the execution context, should the class represented - * by "name" be excluded from consideration? - * @param name the name to test - * @return true if classname is excluded - */ - public boolean isExcluded (String name); - - - /** - * Based on the execution context, if a duplicate class - * represented by "name" is detected, should the existing - * one be overridden or not? - * @param name the name to test - * @return true if name should be overridden - */ - public boolean shouldOverride (String name); + public ConstantThrowable() + { + this(null); + } + + public ConstantThrowable(String name) + { + super(name, null, false, false); + } + + @Override + public String toString() + { + return String.valueOf(getMessage()); + } } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/FutureCallback.java b/jetty-util/src/main/java/org/eclipse/jetty/util/FutureCallback.java index 247535cb284..72ea4828a53 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/FutureCallback.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/FutureCallback.java @@ -29,7 +29,7 @@ import java.util.concurrent.atomic.AtomicBoolean; public class FutureCallback implements Future,Callback { - private static Throwable COMPLETED=new Throwable(); + private static Throwable COMPLETED=new ConstantThrowable(); private final AtomicBoolean _done=new AtomicBoolean(false); private final CountDownLatch _latch=new CountDownLatch(1); private Throwable _cause; diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/FuturePromise.java b/jetty-util/src/main/java/org/eclipse/jetty/util/FuturePromise.java index 09a770b2a0a..a471407f86c 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/FuturePromise.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/FuturePromise.java @@ -29,7 +29,7 @@ import java.util.concurrent.atomic.AtomicBoolean; public class FuturePromise implements Future,Promise { - private static Throwable COMPLETED=new Throwable(); + private static Throwable COMPLETED=new ConstantThrowable(); private final AtomicBoolean _done=new AtomicBoolean(false); private final CountDownLatch _latch=new CountDownLatch(1); private Throwable _cause; diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/HostPort.java b/jetty-util/src/main/java/org/eclipse/jetty/util/HostPort.java new file mode 100644 index 00000000000..62da04b5dfd --- /dev/null +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/HostPort.java @@ -0,0 +1,129 @@ +// +// ======================================================================== +// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.util; + +/** + * Parse an authority string into Host and Port + *

    Parse a string in the form "host:port", handling IPv4 an IPv6 hosts

    + * + */ +public class HostPort +{ + private final String _host; + private final int _port; + + public HostPort(String authority) throws IllegalArgumentException + { + if (authority==null || authority.length()==0) + throw new IllegalArgumentException("No Authority"); + try + { + if (authority.charAt(0)=='[') + { + // ipv6reference + int close=authority.lastIndexOf(']'); + if (close<0) + throw new IllegalArgumentException("Bad IPv6 host"); + _host=authority.substring(0,close+1); + + if (authority.length()>close+1) + { + if (authority.charAt(close+1)!=':') + throw new IllegalArgumentException("Bad IPv6 port"); + _port=StringUtil.toInt(authority,close+2); + } + else + _port=0; + } + else + { + // ipv4address or hostname + int c = authority.lastIndexOf(':'); + if (c>=0) + { + _host=authority.substring(0,c); + _port=StringUtil.toInt(authority,c+1); + } + else + { + _host=authority; + _port=0; + } + } + } + catch (IllegalArgumentException iae) + { + throw iae; + } + catch(final Exception ex) + { + throw new IllegalArgumentException("Bad HostPort") + { + {initCause(ex);} + }; + } + if(_host.isEmpty()) + throw new IllegalArgumentException("Bad host"); + if(_port<0) + throw new IllegalArgumentException("Bad port"); + } + + /* ------------------------------------------------------------ */ + /** Get the host. + * @return the host + */ + public String getHost() + { + return _host; + } + + /* ------------------------------------------------------------ */ + /** Get the port. + * @return the port + */ + public int getPort() + { + return _port; + } + + /* ------------------------------------------------------------ */ + /** Get the port. + * @param defaultPort, the default port to return if a port is not specified + * @return the port + */ + public int getPort(int defaultPort) + { + return _port>0?_port:defaultPort; + } + + /* ------------------------------------------------------------ */ + /** Normalize IPv6 address as per https://www.ietf.org/rfc/rfc2732.txt + * @param host A host name + * @return Host name surrounded by '[' and ']' as needed. + */ + public static String normalizeHost(String host) + { + // if it is normalized IPv6 or could not be IPv6, return + if (host.isEmpty() || host.charAt(0)=='[' || host.indexOf(':')<0) + return host; + + // normalize with [ ] + return "["+host+"]"; + } +} diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/IPAddressMap.java b/jetty-util/src/main/java/org/eclipse/jetty/util/IPAddressMap.java index e1292b192d5..fa784390894 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/IPAddressMap.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/IPAddressMap.java @@ -41,6 +41,7 @@ import java.util.StringTokenizer; * a,b,... - a list of wildcard specifications * * @param the Map Entry value type + * @deprecated */ @SuppressWarnings("serial") public class IPAddressMap extends HashMap diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/IncludeExclude.java b/jetty-util/src/main/java/org/eclipse/jetty/util/IncludeExclude.java index 31cb2801177..3899232dbb1 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/IncludeExclude.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/IncludeExclude.java @@ -18,162 +18,32 @@ package org.eclipse.jetty.util; -import java.util.HashSet; -import java.util.Objects; import java.util.Set; import java.util.function.Predicate; /** Utility class to maintain a set of inclusions and exclusions. - *

    Maintains a set of included and excluded elements. The method {@link #matches(Object)} - * will return true IFF the passed object is not in the excluded set AND ( either the - * included set is empty OR the object is in the included set) - *

    The type of the underlying {@link Set} used may be passed into the - * constructor, so special sets like Servlet PathMap may be used. + *

    This extension of the {@link IncludeExcludeSet} class is used + * when the type of the set elements is the same as the type of + * the predicate test. *

    * @param The type of element */ -public class IncludeExclude +public class IncludeExclude extends IncludeExcludeSet { - private final Set _includes; - private final Predicate _includePredicate; - private final Set _excludes; - private final Predicate _excludePredicate; - - private static class SetContainsPredicate implements Predicate - { - private final Set set; - - public SetContainsPredicate(Set set) - { - this.set = set; - } - - @Override - public boolean test(ITEM item) - { - return set.contains(item); - } - } - - /** - * Default constructor over {@link HashSet} - */ - @SuppressWarnings("unchecked") public IncludeExclude() { - this(HashSet.class); + super(); } - - /** - * Construct an IncludeExclude. - *

    - * If the {@link Set} class also implements {@link Predicate}, then that Predicate is - * used to match against the set, otherwise a simple {@link Set#contains(Object)} test is used. - * @param setClass The type of {@link Set} to using internally - * @param the {@link Set} type - */ - @SuppressWarnings("unchecked") + public > IncludeExclude(Class setClass) { - try - { - _includes = setClass.newInstance(); - _excludes = setClass.newInstance(); - - if(_includes instanceof Predicate) { - _includePredicate = (Predicate)_includes; - } else { - _includePredicate = new SetContainsPredicate<>(_includes); - } - - if(_excludes instanceof Predicate) { - _excludePredicate = (Predicate)_excludes; - } else { - _excludePredicate = new SetContainsPredicate<>(_excludes); - } - } - catch (InstantiationException | IllegalAccessException e) - { - throw new RuntimeException(e); - } - } - - /** - * Construct an IncludeExclude - * - * @param includeSet the Set of items that represent the included space - * @param includePredicate the Predicate for included item testing - * @param excludeSet the Set of items that represent the excluded space - * @param excludePredicate the Predicate for excluded item testing - * @param the {@link Set} type - */ - public > IncludeExclude(Set includeSet, Predicate includePredicate, Set excludeSet, Predicate excludePredicate) - { - Objects.requireNonNull(includeSet,"Include Set"); - Objects.requireNonNull(includePredicate,"Include Predicate"); - Objects.requireNonNull(excludeSet,"Exclude Set"); - Objects.requireNonNull(excludePredicate,"Exclude Predicate"); - - _includes = includeSet; - _includePredicate = includePredicate; - _excludes = excludeSet; - _excludePredicate = excludePredicate; - } - - public void include(ITEM element) - { - _includes.add(element); - } - - public void include(@SuppressWarnings("unchecked") ITEM... element) - { - for (ITEM e: element) - _includes.add(e); + super(setClass); } - public void exclude(ITEM element) + public > IncludeExclude(Set includeSet, Predicate includePredicate, Set excludeSet, + Predicate excludePredicate) { - _excludes.add(element); - } - - public void exclude(@SuppressWarnings("unchecked") ITEM... element) - { - for (ITEM e: element) - _excludes.add(e); - } - - public boolean matches(ITEM e) - { - if (!_includes.isEmpty() && !_includePredicate.test(e)) - return false; - return !_excludePredicate.test(e); - } - - public int size() - { - return _includes.size()+_excludes.size(); - } - - public Set getIncluded() - { - return _includes; - } - - public Set getExcluded() - { - return _excludes; - } - - public void clear() - { - _includes.clear(); - _excludes.clear(); - } - - @Override - public String toString() - { - return String.format("%s@%x{i=%s,ip=%s,e=%s,ep=%s}",this.getClass().getSimpleName(),hashCode(),_includes,_includePredicate,_excludes,_excludePredicate); + super(includeSet,includePredicate,excludeSet,excludePredicate); } } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/IncludeExcludeSet.java b/jetty-util/src/main/java/org/eclipse/jetty/util/IncludeExcludeSet.java new file mode 100644 index 00000000000..656b434d03e --- /dev/null +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/IncludeExcludeSet.java @@ -0,0 +1,216 @@ +// +// ======================================================================== +// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.util; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.function.Predicate; + + +/** Utility class to maintain a set of inclusions and exclusions. + *

    Maintains a set of included and excluded elements. The method {@link #test(Object)} + * will return true IFF the passed object is not in the excluded set AND ( either the + * included set is empty OR the object is in the included set) + *

    The type of the underlying {@link Set} used may be passed into the + * constructor, so special sets like Servlet PathMap may be used. + *

    + * @param The type of element of the set (often a pattern) + * @param

    The type of the instance passed to the predicate + */ +public class IncludeExcludeSet implements Predicate

    +{ + private final Set _includes; + private final Predicate

    _includePredicate; + private final Set _excludes; + private final Predicate

    _excludePredicate; + + private static class SetContainsPredicate implements Predicate + { + private final Set set; + + public SetContainsPredicate(Set set) + { + this.set = set; + } + + @Override + public boolean test(T item) + { + return set.contains(item); + } + } + + /** + * Default constructor over {@link HashSet} + */ + public IncludeExcludeSet() + { + this(HashSet.class); + } + + /** + * Construct an IncludeExclude. + * @param setClass The type of {@link Set} to using internally to hold patterns. Two instances will be created. + * one for include patterns and one for exclude patters. If the class is also a {@link Predicate}, + * then it is also used as the item test for the set, otherwise a {@link SetContainsPredicate} instance + * is created. + * @param The type of a set to use as the backing store + */ + public > IncludeExcludeSet(Class setClass) + { + try + { + _includes = setClass.newInstance(); + _excludes = setClass.newInstance(); + + if(_includes instanceof Predicate) + { + _includePredicate = (Predicate

    )_includes; + } + else + { + _includePredicate = new SetContainsPredicate(_includes); + } + + if(_excludes instanceof Predicate) + { + _excludePredicate = (Predicate

    )_excludes; + } + else + { + _excludePredicate = new SetContainsPredicate(_excludes); + } + } + catch (InstantiationException | IllegalAccessException e) + { + throw new RuntimeException(e); + } + } + + /** + * Construct an IncludeExclude + * + * @param includeSet the Set of items that represent the included space + * @param includePredicate the Predicate for included item testing (null for simple {@link Set#contains(Object)} test) + * @param excludeSet the Set of items that represent the excluded space + * @param excludePredicate the Predicate for excluded item testing (null for simple {@link Set#contains(Object)} test) + * @param The type of a set to use as the backing store + */ + public > IncludeExcludeSet(Set includeSet, Predicate

    includePredicate, Set excludeSet, Predicate

    excludePredicate) + { + Objects.requireNonNull(includeSet,"Include Set"); + Objects.requireNonNull(includePredicate,"Include Predicate"); + Objects.requireNonNull(excludeSet,"Exclude Set"); + Objects.requireNonNull(excludePredicate,"Exclude Predicate"); + + _includes = includeSet; + _includePredicate = includePredicate; + _excludes = excludeSet; + _excludePredicate = excludePredicate; + } + + public void include(T element) + { + _includes.add(element); + } + + public void include(T... element) + { + for (T e: element) + _includes.add(e); + } + + public void exclude(T element) + { + _excludes.add(element); + } + + public void exclude(T... element) + { + for (T e: element) + _excludes.add(e); + } + + @Deprecated + public boolean matches(P t) + { + return test(t); + } + + @Override + public boolean test(P t) + { + if (!_includes.isEmpty() && !_includePredicate.test(t)) + return false; + return !_excludePredicate.test(t); + } + + /** + * Test Included and not Excluded + * @param t The item to test + * @return Boolean.TRUE if t is included, Boolean.FALSE if t is excluded and null if neither + */ + public Boolean isIncludedAndNotExcluded(P t) + { + if (_excludePredicate.test(t)) + return Boolean.FALSE; + if (_includePredicate.test(t)) + return Boolean.TRUE; + + return null; + } + + public boolean hasIncludes() + { + return !_includes.isEmpty(); + } + + public int size() + { + return _includes.size()+_excludes.size(); + } + + public Set getIncluded() + { + return _includes; + } + + public Set getExcluded() + { + return _excludes; + } + + public void clear() + { + _includes.clear(); + _excludes.clear(); + } + + @Override + public String toString() + { + return String.format("%s@%x{i=%s,ip=%s,e=%s,ep=%s}",this.getClass().getSimpleName(),hashCode(),_includes,_includePredicate,_excludes,_excludePredicate); + } + + public boolean isEmpty() + { + return _includes.isEmpty() && _excludes.isEmpty(); + } +} diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/InetAddressSet.java b/jetty-util/src/main/java/org/eclipse/jetty/util/InetAddressSet.java new file mode 100644 index 00000000000..2df0fd40d65 --- /dev/null +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/InetAddressSet.java @@ -0,0 +1,318 @@ +// +// ======================================================================== +// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.util; + +import java.net.InetAddress; +import java.util.AbstractSet; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.function.Predicate; + +/** + * A set of InetAddress patterns. + *

    This is a {@link Set} of String patterns that are used to match + * a {@link Predicate} over InetAddress for containment semantics. + * The patterns that may be set are: + *

    + *
    + *
    InetAddress
    A single InetAddress either in hostname or address format. + * All formats supported by {@link InetAddress} are accepted. Not ethat using hostname + * matches may force domain lookups. eg. "[::1]", "1.2.3.4", "::ffff:127.0.0.1"
    + *
    InetAddress/CIDR
    An InetAddress with a integer number of bits to indicate + * the significant prefix. eg. "192.168.0.0/16" will match from "192.168.0.0" to + * "192.168.255.255"
    + *
    InetAddress-InetAddress
    An inclusive range of InetAddresses. + * eg. "[a000::1]-[afff::]", "192.168.128.0-192.168.128.255"
    + *
    Legacy format
    The legacy format used by {@link IPAddressMap} for IPv4 only. + * eg. "10.10.10-14.0-128"
    + *
    + *

    This class is designed to work with {@link IncludeExcludeSet}

    + * @see IncludeExcludeSet + */ +public class InetAddressSet extends AbstractSet implements Set, Predicate +{ + private Map _patterns = new HashMap<>(); + + @Override + public boolean add(String pattern) + { + return _patterns.put(pattern,newInetRange(pattern))==null; + } + + protected InetPattern newInetRange(String pattern) + { + if (pattern==null) + return null; + + int slash = pattern.lastIndexOf('/'); + int dash = pattern.lastIndexOf('-'); + try + { + if (slash>=0) + return new CidrInetRange(pattern,InetAddress.getByName(pattern.substring(0,slash).trim()),StringUtil.toInt(pattern,slash+1)); + + if (dash>=0) + return new MinMaxInetRange(pattern,InetAddress.getByName(pattern.substring(0,dash).trim()),InetAddress.getByName(pattern.substring(dash+1).trim())); + + return new SingletonInetRange(pattern,InetAddress.getByName(pattern)); + } + catch(Exception e) + { + try + { + if (slash<0 && dash>0) + return new LegacyInetRange(pattern); + } + catch(Exception e2) + { + e.addSuppressed(e2); + } + throw new IllegalArgumentException("Bad pattern: "+pattern,e); + } + } + + @Override + public boolean remove(Object pattern) + { + return _patterns.remove(pattern)!=null; + } + + @Override + public Iterator iterator() + { + return _patterns.keySet().iterator(); + } + + @Override + public int size() + { + return _patterns.size(); + } + + + @Override + public boolean test(InetAddress address) + { + if (address==null) + return false; + byte[] raw = address.getAddress(); + for (InetPattern pattern : _patterns.values()) + if (pattern.test(address,raw)) + return true; + return false; + } + + abstract static class InetPattern + { + final String _pattern; + + InetPattern(String pattern) + { + _pattern=pattern; + } + + abstract boolean test(InetAddress address, byte[] raw); + + @Override + public String toString() + { + return _pattern; + } + } + + static class SingletonInetRange extends InetPattern + { + final InetAddress _address; + public SingletonInetRange(String pattern, InetAddress address) + { + super(pattern); + _address=address; + } + + public boolean test(InetAddress address, byte[] raw) + { + return _address.equals(address); + } + } + + + static class MinMaxInetRange extends InetPattern + { + final int[] _min; + final int[] _max; + + public MinMaxInetRange(String pattern, InetAddress min, InetAddress max) + { + super(pattern); + + byte[] raw_min = min.getAddress(); + byte[] raw_max = max.getAddress(); + if (raw_min.length!=raw_max.length) + throw new IllegalArgumentException("Cannot mix IPv4 and IPv6: "+pattern); + + if (raw_min.length==4) + { + // there must be 6 '.' or this is likely to be a legacy pattern + int count=0; + for (char c:pattern.toCharArray()) + if (c=='.') + count++; + if (count!=6) + throw new IllegalArgumentException("Legacy pattern: "+pattern); + } + + _min = new int[raw_min.length]; + _max = new int[raw_min.length]; + + for (int i=0;i<_min.length;i++) + { + _min[i]=0xff&raw_min[i]; + _max[i]=0xff&raw_max[i]; + } + + for (int i=0;i<_min.length;i++) + { + if (_min[i]>_max[i]) + throw new IllegalArgumentException("min is greater than max: "+pattern); + if (_min[i]<_max[i]) + break; + } + } + + public boolean test(InetAddress item, byte[] raw) + { + if (raw.length!=_min.length) + return false; + + boolean min_ok = false; + boolean max_ok = false; + + for (int i=0;i<_min.length;i++) + { + int r = 0xff&raw[i]; + if (!min_ok) + { + if (r<_min[i]) + return false; + if (r>_min[i]) + min_ok=true; + } + if (!max_ok) + { + if (r>_max[i]) + return false; + if (r<_max[i]) + max_ok=true; + } + + if (min_ok && max_ok) + break; + } + + return true; + } + } + + + static class CidrInetRange extends InetPattern + { + final byte[] _raw; + final int _octets; + final int _mask; + final int _masked; + + public CidrInetRange(String pattern, InetAddress address, int cidr) + { + super(pattern); + _raw = address.getAddress(); + _octets = cidr/8; + _mask = 0xff&(0xff<<(8-cidr%8)); + _masked = _mask==0?0:_raw[_octets]&_mask; + + if (cidr>(_raw.length*8)) + throw new IllegalArgumentException("CIDR too large: "+pattern); + + if (_mask!=0 && _raw[_octets]!=_masked) + throw new IllegalArgumentException("CIDR bits non zero: "+pattern); + + for (int o=_octets+(_mask==0?0:1);o<_raw.length;o++) + if (_raw[o]!=0) + throw new IllegalArgumentException("CIDR bits non zero: "+pattern); + } + + public boolean test(InetAddress item, byte[] raw) + { + if (raw.length!=_raw.length) + return false; + + for (int o=0;o<_octets;o++) + if (_raw[o]!=raw[o]) + return false; + + if (_mask!=0 && (raw[_octets]&_mask)!=_masked) + return false; + return true; + } + } + + static class LegacyInetRange extends InetPattern + { + int[] _min = new int[4]; + int[] _max = new int[4]; + + public LegacyInetRange(String pattern) + { + super(pattern); + + String[] parts = pattern.split("\\."); + if (parts.length!=4) + throw new IllegalArgumentException("Bad legacy pattern: "+pattern); + + for (int i=0;i<4;i++) + { + String part=parts[i].trim(); + int dash = part.indexOf('-'); + if (dash<0) + _min[i]=_max[i]=Integer.parseInt(part); + else + { + _min[i] = (dash==0)?0:StringUtil.toInt(part,0); + _max[i] = (dash==part.length()-1)?255:StringUtil.toInt(part,dash+1); + } + + if (_min[i]<0 || _min[i]>_max[i] || _max[i]>255) + throw new IllegalArgumentException("Bad legacy pattern: "+pattern); + } + } + + public boolean test(InetAddress item, byte[] raw) + { + if (raw.length!=4) + return false; + + for (int i=0;i<4;i++) + if ((0xff&raw[i])<_min[i] || (0xff&raw[i])>_max[i]) + return false; + + return true; + } + } +} diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Promise.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Promise.java index c8f247e6d3b..62243e0c283 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/Promise.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Promise.java @@ -18,6 +18,7 @@ package org.eclipse.jetty.util; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import org.eclipse.jetty.util.log.Log; @@ -55,11 +56,6 @@ public interface Promise */ class Adapter implements Promise { - @Override - public void succeeded(U result) - { - } - @Override public void failed(Throwable x) { @@ -119,13 +115,25 @@ public interface Promise } } - public static abstract class Wrapper implements Promise + class Wrapper implements Promise { private final Promise promise; public Wrapper(Promise promise) { - this.promise = promise; + this.promise = Objects.requireNonNull(promise); + } + + @Override + public void succeeded(W result) + { + promise.succeeded(result); + } + + @Override + public void failed(Throwable x) + { + promise.failed(x); } public Promise getPromise() diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/SharedBlockingCallback.java b/jetty-util/src/main/java/org/eclipse/jetty/util/SharedBlockingCallback.java index 27daefd7f17..ac2e89238c7 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/SharedBlockingCallback.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/SharedBlockingCallback.java @@ -50,45 +50,26 @@ import org.eclipse.jetty.util.thread.Invocable.InvocationType; public class SharedBlockingCallback { static final Logger LOG = Log.getLogger(SharedBlockingCallback.class); - private static Throwable IDLE = new Throwable() - { - @Override - public String toString() - { - return "IDLE"; - } - }; - private static Throwable SUCCEEDED = new Throwable() - { - @Override - public String toString() - { - return "SUCCEEDED"; - } - }; - private static Throwable FAILED = new Throwable() - { - @Override - public String toString() - { - return "FAILED"; - } - }; + + private static Throwable IDLE = new ConstantThrowable("IDLE"); + private static Throwable SUCCEEDED = new ConstantThrowable("SUCCEEDED"); + + private static Throwable FAILED = new ConstantThrowable("FAILED"); private final ReentrantLock _lock = new ReentrantLock(); private final Condition _idle = _lock.newCondition(); private final Condition _complete = _lock.newCondition(); private Blocker _blocker = new Blocker(); - + protected long getIdleTimeout() { return -1; } - + public Blocker acquire() throws IOException { - _lock.lock(); long idle = getIdleTimeout(); + _lock.lock(); try { while (_blocker._state != IDLE) @@ -103,8 +84,9 @@ public class SharedBlockingCallback _idle.await(); } _blocker._state = null; + return _blocker; } - catch (final InterruptedException e) + catch (InterruptedException x) { throw new InterruptedIOException(); } @@ -112,7 +94,6 @@ public class SharedBlockingCallback { _lock.unlock(); } - return _blocker; } protected void notComplete(Blocker blocker) @@ -180,8 +161,15 @@ public class SharedBlockingCallback _state=cause; _complete.signalAll(); } - else + else if (_state instanceof BlockerTimeoutException) + { + // Failure arrived late, block() already + // modified the state, nothing more to do. + } + else + { throw new IllegalStateException(_state); + } } finally { @@ -198,19 +186,24 @@ public class SharedBlockingCallback */ public void block() throws IOException { - _lock.lock(); long idle = getIdleTimeout(); + _lock.lock(); try { while (_state == null) { - if (idle>0 && (idle < Long.MAX_VALUE/2)) + if (idle > 0) { - // Wait a little bit longer than expected callback idle timeout - if (!_complete.await(idle+idle/2,TimeUnit.MILLISECONDS)) - // The callback has not arrived in sufficient time. - // We will synthesize a TimeoutException - _state=new BlockerTimeoutException(); + // Waiting here may compete with the idle timeout mechanism, + // so here we wait a little bit longer to favor the normal + // idle timeout mechanism that will call failed(Throwable). + long excess = Math.min(idle / 2, 1000); + if (!_complete.await(idle + excess, TimeUnit.MILLISECONDS)) + { + // Method failed(Throwable) has not been called yet, + // so we will synthesize a special TimeoutException. + _state = new BlockerTimeoutException(); + } } else { diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java index e9692f0b95f..2a3a81a5ba9 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java @@ -682,7 +682,6 @@ public class StringUtil return sidBytes; } - /** * Convert String to an integer. Parses up to the first non-numeric character. If no number is found an IllegalArgumentException is thrown diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Trie.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Trie.java index 1655f552966..9eb355dafb9 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/Trie.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Trie.java @@ -29,7 +29,7 @@ import java.util.Set; public interface Trie { /* ------------------------------------------------------------ */ - /** Put and entry into the Trie + /** Put an entry into the Trie * @param s The key for the entry * @param v The value of the entry * @return True if the Trie had capacity to add the field. @@ -47,14 +47,14 @@ public interface Trie public V remove(String s); /* ------------------------------------------------------------ */ - /** Get and exact match from a String key + /** Get an exact match from a String key * @param s The key * @return the value for the string key */ public V get(String s); /* ------------------------------------------------------------ */ - /** Get and exact match from a String key + /** Get an exact match from a String key * @param s The key * @param offset The offset within the string of the key * @param len the length of the key @@ -63,14 +63,14 @@ public interface Trie public V get(String s,int offset,int len); /* ------------------------------------------------------------ */ - /** Get and exact match from a segment of a ByteBuufer as key + /** Get an exact match from a segment of a ByteBuufer as key * @param b The buffer * @return The value or null if not found */ public V get(ByteBuffer b); /* ------------------------------------------------------------ */ - /** Get and exact match from a segment of a ByteBuufer as key + /** Get an exact match from a segment of a ByteBuufer as key * @param b The buffer * @param offset The offset within the buffer of the key * @param len the length of the key diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java index 0173e55723d..31120dbf5e9 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/TypeUtil.java @@ -24,6 +24,9 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.net.URL; +import java.security.CodeSource; +import java.security.ProtectionDomain; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -31,9 +34,12 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import javax.servlet.ServletContainerInitializer; + import org.eclipse.jetty.util.annotation.Name; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.resource.Resource; /* ------------------------------------------------------------ */ @@ -693,4 +699,38 @@ public class TypeUtil return !((Boolean)o).booleanValue(); return "false".equalsIgnoreCase(o.toString()); } + + /* ------------------------------------------------------------ */ + public static Resource getLoadedFrom(Class clazz) + { + ProtectionDomain domain = clazz.getProtectionDomain(); + if (domain!=null) + { + CodeSource source = domain.getCodeSource(); + if (source!=null) + { + URL location = source.getLocation(); + + if (location!=null) + return Resource.newResource(location); + } + } + + String rname = clazz.getName().replace('.','/')+".class"; + ClassLoader loader = clazz.getClassLoader(); + URL url = (loader==null?ClassLoader.getSystemClassLoader():loader).getResource(rname); + if (url!=null) + { + try + { + return Resource.newResource(URIUtil.getJarSource(url.toString())); + } + catch(Exception e) + { + LOG.debug(e); + } + } + + return null; + } } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java index 8dfdf272e24..742a69d31d7 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java @@ -19,6 +19,7 @@ package org.eclipse.jetty.util; import java.net.URI; +import java.net.URISyntaxException; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.*; @@ -720,10 +721,7 @@ public class URIUtil */ public static void appendSchemeHostPort(StringBuilder url,String scheme,String server, int port) { - if (server.indexOf(':')>=0&&server.charAt(0)!='[') - url.append(scheme).append("://").append('[').append(server).append(']'); - else - url.append(scheme).append("://").append(server); + url.append(scheme).append("://").append(HostPort.normalizeHost(server)); if (port > 0) { @@ -757,10 +755,7 @@ public class URIUtil { synchronized (url) { - if (server.indexOf(':')>=0&&server.charAt(0)!='[') - url.append(scheme).append("://").append('[').append(server).append(']'); - else - url.append(scheme).append("://").append(server); + url.append(scheme).append("://").append(HostPort.normalizeHost(server)); if (port > 0) { @@ -849,4 +844,30 @@ public class URIUtil return URI.create(buf.toString()); } + + public static URI getJarSource(URI uri) + { + try + { + if (!"jar".equals(uri.getScheme())) + return uri; + String s = uri.getSchemeSpecificPart(); + int bang_slash = s.indexOf("!/"); + if (bang_slash>=0) + s=s.substring(0,bang_slash); + return new URI(s); + } + catch(URISyntaxException e) + { + throw new IllegalArgumentException(e); + } + } + + public static String getJarSource(String uri) + { + if (!uri.startsWith("jar:")) + return uri; + int bang_slash = uri.indexOf("!/"); + return (bang_slash>=0)?uri.substring(4,bang_slash):uri.substring(4); + } } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SslContextFactory.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SslContextFactory.java index 26904e71961..f911ab23244 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SslContextFactory.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SslContextFactory.java @@ -43,6 +43,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Consumer; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -77,16 +78,12 @@ import org.eclipse.jetty.util.security.CertificateUtils; import org.eclipse.jetty.util.security.CertificateValidator; import org.eclipse.jetty.util.security.Password; - /** * SslContextFactory is used to configure SSL connectors * as well as HttpClient. It holds all SSL parameters and * creates SSL context based on these parameters to be * used by the SSL connectors. */ - -/** - */ public class SslContextFactory extends AbstractLifeCycle { public final static TrustManager[] TRUST_ALL_CERTS = new X509TrustManager[]{new X509TrustManager() @@ -105,15 +102,15 @@ public class SslContextFactory extends AbstractLifeCycle } }}; - static final Logger LOG = Log.getLogger(SslContextFactory.class); + private static final Logger LOG = Log.getLogger(SslContextFactory.class); public static final String DEFAULT_KEYMANAGERFACTORY_ALGORITHM = - (Security.getProperty("ssl.KeyManagerFactory.algorithm") == null ? - KeyManagerFactory.getDefaultAlgorithm() : Security.getProperty("ssl.KeyManagerFactory.algorithm")); + (Security.getProperty("ssl.KeyManagerFactory.algorithm") == null ? + KeyManagerFactory.getDefaultAlgorithm() : Security.getProperty("ssl.KeyManagerFactory.algorithm")); public static final String DEFAULT_TRUSTMANAGERFACTORY_ALGORITHM = - (Security.getProperty("ssl.TrustManagerFactory.algorithm") == null ? - TrustManagerFactory.getDefaultAlgorithm() : Security.getProperty("ssl.TrustManagerFactory.algorithm")); + (Security.getProperty("ssl.TrustManagerFactory.algorithm") == null ? + TrustManagerFactory.getDefaultAlgorithm() : Security.getProperty("ssl.TrustManagerFactory.algorithm")); /** String name of key password property. */ public static final String KEYPASSWORD_PROPERTY = "org.eclipse.jetty.ssl.keypassword"; @@ -121,114 +118,51 @@ public class SslContextFactory extends AbstractLifeCycle /** String name of keystore password property. */ public static final String PASSWORD_PROPERTY = "org.eclipse.jetty.ssl.password"; - /** Excluded protocols. */ private final Set _excludeProtocols = new LinkedHashSet<>(); - - /** Included protocols. */ private final Set _includeProtocols = new LinkedHashSet<>(); - - /** Selected protocols. */ - private String[] _selectedProtocols; - - /** Excluded cipher suites. */ private final Set _excludeCipherSuites = new LinkedHashSet<>(); - - /** Included cipher suites. */ private final List _includeCipherSuites = new ArrayList<>(); - private boolean _useCipherSuitesOrder=true; - - /** Cipher comparator for ordering ciphers */ - Comparator _cipherComparator; - - /** Selected cipher suites. Combination of includes, excludes, available and ordering */ + private final Map _aliasX509 = new HashMap<>(); + private final Map _certHosts = new HashMap<>(); + private final Map _certWilds = new HashMap<>(); + private String[] _selectedProtocols; + private boolean _useCipherSuitesOrder = true; + private Comparator _cipherComparator; private String[] _selectedCipherSuites; - - /** Keystore path. */ private Resource _keyStoreResource; - /** Keystore provider name */ private String _keyStoreProvider; - /** Keystore type */ private String _keyStoreType = "JKS"; - - /** SSL certificate alias */ private String _certAlias; - private final Map _aliasX509 = new HashMap<>(); - private final Map _certHosts = new HashMap<>(); - private final Map _certWilds = new HashMap<>(); - - /** Truststore path */ private Resource _trustStoreResource; - /** Truststore provider name */ private String _trustStoreProvider; - /** Truststore type */ private String _trustStoreType = "JKS"; - - /** Set to true if client certificate authentication is required */ private boolean _needClientAuth = false; - /** Set to true if client certificate authentication is desired */ private boolean _wantClientAuth = false; - - /** Keystore password */ private Password _keyStorePassword; - /** Key manager password */ private Password _keyManagerPassword; - /** Truststore password */ private Password _trustStorePassword; - - /** SSL provider name */ private String _sslProvider; - /** SSL protocol name */ private String _sslProtocol = "TLS"; - - /** SecureRandom algorithm */ private String _secureRandomAlgorithm; - /** KeyManager factory algorithm */ private String _keyManagerFactoryAlgorithm = DEFAULT_KEYMANAGERFACTORY_ALGORITHM; - /** TrustManager factory algorithm */ private String _trustManagerFactoryAlgorithm = DEFAULT_TRUSTMANAGERFACTORY_ALGORITHM; - - /** Set to true if SSL certificate validation is required */ private boolean _validateCerts; - /** Set to true if SSL certificate of the peer validation is required */ private boolean _validatePeerCerts; - /** Maximum certification path length (n - number of intermediate certs, -1 for unlimited) */ private int _maxCertPathLength = -1; - /** Path to file that contains Certificate Revocation List */ private String _crlPath; - /** Set to true to enable CRL Distribution Points (CRLDP) support */ private boolean _enableCRLDP = false; - /** Set to true to enable On-Line Certificate Status Protocol (OCSP) support */ private boolean _enableOCSP = false; - /** Location of OCSP Responder */ private String _ocspResponderURL; - - /** SSL keystore */ private KeyStore _setKeyStore; - /** SSL truststore */ private KeyStore _setTrustStore; - /** Set to true to enable SSL Session caching */ private boolean _sessionCachingEnabled = true; - /** SSL session cache size */ - private int _sslSessionCacheSize=-1; - /** SSL session timeout */ - private int _sslSessionTimeout=-1; - - /** SSL context */ + private int _sslSessionCacheSize = -1; + private int _sslSessionTimeout = -1; private SSLContext _setContext; - - /** EndpointIdentificationAlgorithm - when set to "HTTPS" hostname verification will be enabled */ private String _endpointIdentificationAlgorithm = null; - - /** Whether to blindly trust certificates */ private boolean _trustAll; - - /** Whether TLS renegotiation is allowed */ private boolean _renegotiationAllowed = true; - - protected Factory _factory; - - - + private Factory _factory; /** * Construct an instance of SslContextFactory @@ -242,33 +176,185 @@ public class SslContextFactory extends AbstractLifeCycle /** * Construct an instance of SslContextFactory * Default constructor for use in XmlConfiguration files + * * @param trustAll whether to blindly trust all certificates * @see #setTrustAll(boolean) */ public SslContextFactory(boolean trustAll) { - setTrustAll(trustAll); - addExcludeProtocols("SSL", "SSLv2", "SSLv2Hello", "SSLv3"); - setExcludeCipherSuites("^.*_(MD5|SHA|SHA1)$"); + this(trustAll, null); } /** * Construct an instance of SslContextFactory + * * @param keyStorePath default keystore location */ public SslContextFactory(String keyStorePath) { - setKeyStorePath(keyStorePath); + this(false, keyStorePath); + } + + private SslContextFactory(boolean trustAll, String keyStorePath) + { + setTrustAll(trustAll); + addExcludeProtocols("SSL", "SSLv2", "SSLv2Hello", "SSLv3"); + setExcludeCipherSuites("^.*_(MD5|SHA|SHA1)$"); + if (keyStorePath != null) + setKeyStorePath(keyStorePath); + } + + /** + * Creates the SSLContext object and starts the lifecycle + */ + @Override + protected void doStart() throws Exception + { + super.doStart(); + synchronized (this) + { + load(); + } + } + + private void load() throws Exception + { + SSLContext context = _setContext; + KeyStore keyStore = _setKeyStore; + KeyStore trustStore = _setTrustStore; + + if (context == null) + { + // Is this an empty factory? + if (keyStore == null && _keyStoreResource == null && trustStore == null && _trustStoreResource == null) + { + TrustManager[] trust_managers = null; + + if (isTrustAll()) + { + if (LOG.isDebugEnabled()) + LOG.debug("No keystore or trust store configured. ACCEPTING UNTRUSTED CERTIFICATES!!!!!"); + // Create a trust manager that does not validate certificate chains + trust_managers = TRUST_ALL_CERTS; + } + + String algorithm = getSecureRandomAlgorithm(); + SecureRandom secureRandom = algorithm == null ? null : SecureRandom.getInstance(algorithm); + context = _sslProvider == null ? SSLContext.getInstance(_sslProtocol) : SSLContext.getInstance(_sslProtocol, _sslProvider); + context.init(null, trust_managers, secureRandom); + } + else + { + if (keyStore == null) + keyStore = loadKeyStore(_keyStoreResource); + if (trustStore == null) + trustStore = loadTrustStore(_trustStoreResource); + + Collection crls = loadCRL(getCrlPath()); + + // Look for X.509 certificates to create alias map + if (keyStore != null) + { + for (String alias : Collections.list(keyStore.aliases())) + { + Certificate certificate = keyStore.getCertificate(alias); + if (certificate != null && "X.509".equals(certificate.getType())) + { + X509Certificate x509C = (X509Certificate)certificate; + + // Exclude certificates with special uses + if (X509.isCertSign(x509C)) + { + if (LOG.isDebugEnabled()) + LOG.debug("Skipping " + x509C); + continue; + } + X509 x509 = new X509(alias, x509C); + _aliasX509.put(alias, x509); + + if (isValidateCerts()) + { + CertificateValidator validator = new CertificateValidator(trustStore, crls); + validator.setMaxCertPathLength(getMaxCertPathLength()); + validator.setEnableCRLDP(isEnableCRLDP()); + validator.setEnableOCSP(isEnableOCSP()); + validator.setOcspResponderURL(getOcspResponderURL()); + validator.validate(keyStore, x509C); // TODO what about truststore? + } + + LOG.info("x509={} for {}", x509, this); + + for (String h : x509.getHosts()) + _certHosts.put(h, x509); + for (String w : x509.getWilds()) + _certWilds.put(w, x509); + } + } + } + + // Instantiate key and trust managers + KeyManager[] keyManagers = getKeyManagers(keyStore); + TrustManager[] trustManagers = getTrustManagers(trustStore, crls); + + // Initialize context + SecureRandom secureRandom = (_secureRandomAlgorithm == null) ? null : SecureRandom.getInstance(_secureRandomAlgorithm); + context = _sslProvider == null ? SSLContext.getInstance(_sslProtocol) : SSLContext.getInstance(_sslProtocol, _sslProvider); + context.init(keyManagers, trustManagers, secureRandom); + } + } + + // Initialize cache + SSLSessionContext serverContext = context.getServerSessionContext(); + if (serverContext != null) + { + if (getSslSessionCacheSize() > -1) + serverContext.setSessionCacheSize(getSslSessionCacheSize()); + if (getSslSessionTimeout() > -1) + serverContext.setSessionTimeout(getSslSessionTimeout()); + } + + // select the protocols and ciphers + SSLParameters enabled = context.getDefaultSSLParameters(); + SSLParameters supported = context.getSupportedSSLParameters(); + selectCipherSuites(enabled.getCipherSuites(), supported.getCipherSuites()); + selectProtocols(enabled.getProtocols(), supported.getProtocols()); + + _factory = new Factory(keyStore, trustStore, context); + if (LOG.isDebugEnabled()) + { + LOG.debug("Selected Protocols {} of {}", Arrays.asList(_selectedProtocols), Arrays.asList(supported.getProtocols())); + LOG.debug("Selected Ciphers {} of {}", Arrays.asList(_selectedCipherSuites), Arrays.asList(supported.getCipherSuites())); + } + } + + @Override + protected void doStop() throws Exception + { + synchronized (this) + { + unload(); + } + super.doStop(); + } + + private void unload() + { + _factory = null; + _selectedProtocols = null; + _selectedCipherSuites = null; + _aliasX509.clear(); + _certHosts.clear(); + _certWilds.clear(); } public String[] getSelectedProtocols() { - return Arrays.copyOf(_selectedProtocols,_selectedProtocols.length); + return Arrays.copyOf(_selectedProtocols, _selectedProtocols.length); } public String[] getSelectedCipherSuites() { - return Arrays.copyOf(_selectedCipherSuites,_selectedCipherSuites.length); + return Arrays.copyOf(_selectedCipherSuites, _selectedCipherSuites.length); } public Comparator getCipherComparator() @@ -278,7 +364,7 @@ public class SslContextFactory extends AbstractLifeCycle public void setCipherComparator(Comparator cipherComparator) { - if (cipherComparator!=null) + if (cipherComparator != null) setUseCipherSuitesOrder(true); _cipherComparator = cipherComparator; } @@ -293,148 +379,21 @@ public class SslContextFactory extends AbstractLifeCycle return _aliasX509.get(alias); } - /** - * Create the SSLContext object and start the lifecycle - * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart() - */ - @Override - protected void doStart() throws Exception - { - SSLContext context = _setContext; - KeyStore keyStore = _setKeyStore; - KeyStore trustStore = _setTrustStore; - - if (context == null) - { - // Is this an empty factory? - if (keyStore==null && _keyStoreResource == null && trustStore==null && _trustStoreResource == null ) - { - TrustManager[] trust_managers=null; - - if (_trustAll) - { - if (LOG.isDebugEnabled()) - LOG.debug("No keystore or trust store configured. ACCEPTING UNTRUSTED CERTIFICATES!!!!!"); - // Create a trust manager that does not validate certificate chains - trust_managers = TRUST_ALL_CERTS; - } - - SecureRandom secureRandom = (_secureRandomAlgorithm == null)?null:SecureRandom.getInstance(_secureRandomAlgorithm); - context = _sslProvider == null ? SSLContext.getInstance(_sslProtocol) : SSLContext.getInstance(_sslProtocol, _sslProvider); - context.init(null, trust_managers, secureRandom); - } - else - { - if (keyStore==null) - keyStore=loadKeyStore(_keyStoreResource); - if (trustStore==null) - trustStore=loadTrustStore(_trustStoreResource); - - Collection crls = loadCRL(_crlPath); - - // Look for X.509 certificates to create alias map - _certHosts.clear(); - if (keyStore!=null) - { - for (String alias : Collections.list(keyStore.aliases())) - { - Certificate certificate = keyStore.getCertificate(alias); - if (certificate!=null && "X.509".equals(certificate.getType())) - { - X509Certificate x509C = (X509Certificate)certificate; - - // Exclude certificates with special uses - if (X509.isCertSign(x509C)) - { - if (LOG.isDebugEnabled()) - LOG.debug("Skipping "+x509C); - continue; - } - X509 x509 = new X509(alias,x509C); - _aliasX509.put(alias,x509); - - if (_validateCerts) - { - CertificateValidator validator = new CertificateValidator(trustStore, crls); - validator.setMaxCertPathLength(_maxCertPathLength); - validator.setEnableCRLDP(_enableCRLDP); - validator.setEnableOCSP(_enableOCSP); - validator.setOcspResponderURL(_ocspResponderURL); - validator.validate(keyStore, x509C); // TODO what about truststore? - } - - LOG.info("x509={} for {}",x509,this); - - for (String h:x509.getHosts()) - _certHosts.put(h,x509); - for (String w:x509.getWilds()) - _certWilds.put(w,x509); - } - } - } - - // Instantiate key and trust managers - KeyManager[] keyManagers = getKeyManagers(keyStore); - TrustManager[] trustManagers = getTrustManagers(trustStore,crls); - - // Initialize context - SecureRandom secureRandom = (_secureRandomAlgorithm == null)?null:SecureRandom.getInstance(_secureRandomAlgorithm); - context = _sslProvider == null ? SSLContext.getInstance(_sslProtocol) : SSLContext.getInstance(_sslProtocol, _sslProvider); - context.init(keyManagers,trustManagers,secureRandom); - } - } - - // Initialize cache - SSLSessionContext serverContext=context.getServerSessionContext(); - if (serverContext!=null) - { - if (getSslSessionCacheSize()>-1) - serverContext.setSessionCacheSize(getSslSessionCacheSize()); - if (getSslSessionTimeout()>-1) - serverContext.setSessionTimeout(getSslSessionTimeout()); - } - - // select the protocols and ciphers - SSLParameters enabled=context.getDefaultSSLParameters(); - SSLParameters supported=context.getSupportedSSLParameters(); - selectCipherSuites(enabled.getCipherSuites(),supported.getCipherSuites()); - selectProtocols(enabled.getProtocols(),supported.getProtocols()); - - _factory = new Factory(keyStore,trustStore,context); - if (LOG.isDebugEnabled()) - { - LOG.debug("Selected Protocols {} of {}",Arrays.asList(_selectedProtocols),Arrays.asList(supported.getProtocols())); - LOG.debug("Selected Ciphers {} of {}",Arrays.asList(_selectedCipherSuites),Arrays.asList(supported.getCipherSuites())); - } - } - - @Override - protected void doStop() throws Exception - { - _factory = null; - super.doStop(); - _certHosts.clear(); - _certWilds.clear(); - _aliasX509.clear(); - } - /** * @return The array of protocol names to exclude from * {@link SSLEngine#setEnabledProtocols(String[])} */ public String[] getExcludeProtocols() { - return _excludeProtocols.toArray(new String[_excludeProtocols.size()]); + return _excludeProtocols.toArray(new String[0]); } /** - * @param protocols - * The array of protocol names to exclude from - * {@link SSLEngine#setEnabledProtocols(String[])} + * @param protocols The array of protocol names to exclude from + * {@link SSLEngine#setEnabledProtocols(String[])} */ public void setExcludeProtocols(String... protocols) { - checkNotStarted(); _excludeProtocols.clear(); _excludeProtocols.addAll(Arrays.asList(protocols)); } @@ -444,7 +403,6 @@ public class SslContextFactory extends AbstractLifeCycle */ public void addExcludeProtocols(String... protocol) { - checkNotStarted(); _excludeProtocols.addAll(Arrays.asList(protocol)); } @@ -454,17 +412,15 @@ public class SslContextFactory extends AbstractLifeCycle */ public String[] getIncludeProtocols() { - return _includeProtocols.toArray(new String[_includeProtocols.size()]); + return _includeProtocols.toArray(new String[0]); } /** - * @param protocols - * The array of protocol names to include in - * {@link SSLEngine#setEnabledProtocols(String[])} + * @param protocols The array of protocol names to include in + * {@link SSLEngine#setEnabledProtocols(String[])} */ public void setIncludeProtocols(String... protocols) { - checkNotStarted(); _includeProtocols.clear(); _includeProtocols.addAll(Arrays.asList(protocols)); } @@ -475,18 +431,17 @@ public class SslContextFactory extends AbstractLifeCycle */ public String[] getExcludeCipherSuites() { - return _excludeCipherSuites.toArray(new String[_excludeCipherSuites.size()]); + return _excludeCipherSuites.toArray(new String[0]); } /** * You can either use the exact cipher suite name or a a regular expression. - * @param cipherSuites - * The array of cipher suite names to exclude from - * {@link SSLEngine#setEnabledCipherSuites(String[])} + * + * @param cipherSuites The array of cipher suite names to exclude from + * {@link SSLEngine#setEnabledCipherSuites(String[])} */ public void setExcludeCipherSuites(String... cipherSuites) { - checkNotStarted(); _excludeCipherSuites.clear(); _excludeCipherSuites.addAll(Arrays.asList(cipherSuites)); } @@ -496,7 +451,6 @@ public class SslContextFactory extends AbstractLifeCycle */ public void addExcludeCipherSuites(String... cipher) { - checkNotStarted(); _excludeCipherSuites.addAll(Arrays.asList(cipher)); } @@ -506,18 +460,17 @@ public class SslContextFactory extends AbstractLifeCycle */ public String[] getIncludeCipherSuites() { - return _includeCipherSuites.toArray(new String[_includeCipherSuites.size()]); + return _includeCipherSuites.toArray(new String[0]); } /** * You can either use the exact cipher suite name or a a regular expression. - * @param cipherSuites - * The array of cipher suite names to include in - * {@link SSLEngine#setEnabledCipherSuites(String[])} + * + * @param cipherSuites The array of cipher suite names to include in + * {@link SSLEngine#setEnabledCipherSuites(String[])} */ public void setIncludeCipherSuites(String... cipherSuites) { - checkNotStarted(); _includeCipherSuites.clear(); _includeCipherSuites.addAll(Arrays.asList(cipherSuites)); } @@ -541,12 +494,10 @@ public class SslContextFactory extends AbstractLifeCycle } /** - * @param keyStorePath - * The file or URL of the SSL Key store. + * @param keyStorePath The file or URL of the SSL Key store. */ public void setKeyStorePath(String keyStorePath) { - checkNotStarted(); try { _keyStoreResource = Resource.newResource(keyStorePath); @@ -566,12 +517,10 @@ public class SslContextFactory extends AbstractLifeCycle } /** - * @param keyStoreProvider - * The provider of the key store + * @param keyStoreProvider The provider of the key store */ public void setKeyStoreProvider(String keyStoreProvider) { - checkNotStarted(); _keyStoreProvider = keyStoreProvider; } @@ -584,12 +533,10 @@ public class SslContextFactory extends AbstractLifeCycle } /** - * @param keyStoreType - * The type of the key store (default "JKS") + * @param keyStoreType The type of the key store (default "JKS") */ public void setKeyStoreType(String keyStoreType) { - checkNotStarted(); _keyStoreType = keyStoreType; } @@ -607,22 +554,19 @@ public class SslContextFactory extends AbstractLifeCycle * to specify the certificate that should be used, or with SNI * certificates to set a certificate to try if no others match *

    - * @param certAlias - * Alias of SSL certificate for the connector + * + * @param certAlias Alias of SSL certificate for the connector */ public void setCertAlias(String certAlias) { - checkNotStarted(); _certAlias = certAlias; } /** - * @param trustStorePath - * The file name or URL of the trust store location + * @param trustStorePath The file name or URL of the trust store location */ public void setTrustStorePath(String trustStorePath) { - checkNotStarted(); try { _trustStoreResource = Resource.newResource(trustStorePath); @@ -642,12 +586,10 @@ public class SslContextFactory extends AbstractLifeCycle } /** - * @param trustStoreProvider - * The provider of the trust store + * @param trustStoreProvider The provider of the trust store */ public void setTrustStoreProvider(String trustStoreProvider) { - checkNotStarted(); _trustStoreProvider = trustStoreProvider; } @@ -660,12 +602,10 @@ public class SslContextFactory extends AbstractLifeCycle } /** - * @param trustStoreType - * The type of the trust store (default "JKS") + * @param trustStoreType The type of the trust store (default "JKS") */ public void setTrustStoreType(String trustStoreType) { - checkNotStarted(); _trustStoreType = trustStoreType; } @@ -679,13 +619,11 @@ public class SslContextFactory extends AbstractLifeCycle } /** - * @param needClientAuth - * True if SSL needs client authentication. + * @param needClientAuth True if SSL needs client authentication. * @see SSLEngine#getNeedClientAuth() */ public void setNeedClientAuth(boolean needClientAuth) { - checkNotStarted(); _needClientAuth = needClientAuth; } @@ -699,13 +637,11 @@ public class SslContextFactory extends AbstractLifeCycle } /** - * @param wantClientAuth - * True if SSL wants client authentication. + * @param wantClientAuth True if SSL wants client authentication. * @see SSLEngine#getWantClientAuth() */ public void setWantClientAuth(boolean wantClientAuth) { - checkNotStarted(); _wantClientAuth = wantClientAuth; } @@ -718,12 +654,10 @@ public class SslContextFactory extends AbstractLifeCycle } /** - * @param validateCerts - * true if SSL certificates have to be validated + * @param validateCerts true if SSL certificates have to be validated */ public void setValidateCerts(boolean validateCerts) { - checkNotStarted(); _validateCerts = validateCerts; } @@ -736,79 +670,76 @@ public class SslContextFactory extends AbstractLifeCycle } /** - * @param validatePeerCerts - * true if SSL certificates of the peer have to be validated + * @param validatePeerCerts true if SSL certificates of the peer have to be validated */ public void setValidatePeerCerts(boolean validatePeerCerts) { - checkNotStarted(); _validatePeerCerts = validatePeerCerts; } /** - * @param password - * The password for the key store. If null is passed and - * a keystore is set, then - * the {@link Password#getPassword(String, String, String)} is used to - * obtain a password either from the {@value #PASSWORD_PROPERTY} - * System property or by prompting for manual entry. + * @param password The password for the key store. If null is passed and + * a keystore is set, then + * the {@link #getPassword(String)} is used to + * obtain a password either from the {@value #PASSWORD_PROPERTY} + * system property or by prompting for manual entry. */ public void setKeyStorePassword(String password) { - checkNotStarted(); - if (password==null) + if (password == null) { - if (_keyStoreResource!=null) - _keyStorePassword= getPassword(PASSWORD_PROPERTY); + if (_keyStoreResource != null) + _keyStorePassword = getPassword(PASSWORD_PROPERTY); else - _keyStorePassword=null; + _keyStorePassword = null; } else + { _keyStorePassword = newPassword(password); + } } /** - * @param password - * The password (if any) for the specific key within the key store. - * If null is passed and the {@value #KEYPASSWORD_PROPERTY} system property is set, - * then the {@link Password#getPassword(String, String, String)} is used to - * obtain a password from the {@value #KEYPASSWORD_PROPERTY} system property. + * @param password The password (if any) for the specific key within the key store. + * If null is passed and the {@value #KEYPASSWORD_PROPERTY} system property is set, + * then the {@link #getPassword(String)} is used to + * obtain a password from the {@value #KEYPASSWORD_PROPERTY} system property. */ public void setKeyManagerPassword(String password) { - checkNotStarted(); - if (password==null) + if (password == null) { - if (System.getProperty(KEYPASSWORD_PROPERTY)!=null) + if (System.getProperty(KEYPASSWORD_PROPERTY) != null) _keyManagerPassword = getPassword(KEYPASSWORD_PROPERTY); else _keyManagerPassword = null; } else + { _keyManagerPassword = newPassword(password); + } } /** - * @param password - * The password for the trust store. If null is passed and a truststore is set - * that is different from the keystore, then - * the {@link Password#getPassword(String, String, String)} is used to - * obtain a password either from the {@value #PASSWORD_PROPERTY} - * System property or by prompting for manual entry. + * @param password The password for the truststore. If null is passed and a truststore is set + * that is different from the keystore, then + * the {@link #getPassword(String)} is used to + * obtain a password either from the {@value #PASSWORD_PROPERTY} + * system property or by prompting for manual entry. */ public void setTrustStorePassword(String password) { - checkNotStarted(); - if (password==null) + if (password == null) { - // Do we need a truststore password? - if (_trustStoreResource!=null && !_trustStoreResource.equals(_keyStoreResource)) + if (_trustStoreResource != null && !_trustStoreResource.equals(_keyStoreResource)) _trustStorePassword = getPassword(PASSWORD_PROPERTY); else _trustStorePassword = null; } else - _trustStorePassword=newPassword(password); + { + _trustStorePassword = newPassword(password); + } } /** @@ -821,13 +752,11 @@ public class SslContextFactory extends AbstractLifeCycle } /** - * @param provider - * The SSL provider name, which if set is passed to - * {@link SSLContext#getInstance(String, String)} + * @param provider The SSL provider name, which if set is passed to + * {@link SSLContext#getInstance(String, String)} */ public void setProvider(String provider) { - checkNotStarted(); _sslProvider = provider; } @@ -839,25 +768,13 @@ public class SslContextFactory extends AbstractLifeCycle { return _sslProtocol; } - - /** - * Get the password object for the realm - * @param realm the realm - * @return the Password object - */ - protected Password getPassword(String realm) - { - return Password.getPassword(realm, null, null); - } /** - * @param protocol - * The SSL protocol (default "TLS") passed to - * {@link SSLContext#getInstance(String, String)} + * @param protocol The SSL protocol (default "TLS") passed to + * {@link SSLContext#getInstance(String, String)} */ public void setProtocol(String protocol) { - checkNotStarted(); _sslProtocol = protocol; } @@ -872,32 +789,28 @@ public class SslContextFactory extends AbstractLifeCycle } /** - * @param algorithm - * The algorithm name, which if set is passed to - * {@link SecureRandom#getInstance(String)} to obtain the {@link SecureRandom} instance passed to - * {@link SSLContext#init(javax.net.ssl.KeyManager[], javax.net.ssl.TrustManager[], SecureRandom)} + * @param algorithm The algorithm name, which if set is passed to + * {@link SecureRandom#getInstance(String)} to obtain the {@link SecureRandom} instance passed to + * {@link SSLContext#init(javax.net.ssl.KeyManager[], javax.net.ssl.TrustManager[], SecureRandom)} */ public void setSecureRandomAlgorithm(String algorithm) { - checkNotStarted(); _secureRandomAlgorithm = algorithm; } /** * @return The algorithm name (default "SunX509") used by the {@link KeyManagerFactory} */ - public String getSslKeyManagerFactoryAlgorithm() + public String getKeyManagerFactoryAlgorithm() { - return (_keyManagerFactoryAlgorithm); + return _keyManagerFactoryAlgorithm; } /** - * @param algorithm - * The algorithm name (default "SunX509") used by the {@link KeyManagerFactory} + * @param algorithm The algorithm name (default "SunX509") used by the {@link KeyManagerFactory} */ - public void setSslKeyManagerFactoryAlgorithm(String algorithm) + public void setKeyManagerFactoryAlgorithm(String algorithm) { - checkNotStarted(); _keyManagerFactoryAlgorithm = algorithm; } @@ -906,7 +819,7 @@ public class SslContextFactory extends AbstractLifeCycle */ public String getTrustManagerFactoryAlgorithm() { - return (_trustManagerFactoryAlgorithm); + return _trustManagerFactoryAlgorithm; } /** @@ -923,18 +836,16 @@ public class SslContextFactory extends AbstractLifeCycle public void setTrustAll(boolean trustAll) { _trustAll = trustAll; - if(trustAll) + if (trustAll) setEndpointIdentificationAlgorithm(null); } /** - * @param algorithm - * The algorithm name (default "SunX509") used by the {@link TrustManagerFactory} - * Use the string "TrustAll" to install a trust manager that trusts all. + * @param algorithm The algorithm name (default "SunX509") used by the {@link TrustManagerFactory} + * Use the string "TrustAll" to install a trust manager that trusts all. */ public void setTrustManagerFactoryAlgorithm(String algorithm) { - checkNotStarted(); _trustManagerFactoryAlgorithm = algorithm; } @@ -963,12 +874,10 @@ public class SslContextFactory extends AbstractLifeCycle } /** - * @param crlPath - * Path to file that contains Certificate Revocation List + * @param crlPath Path to file that contains Certificate Revocation List */ public void setCrlPath(String crlPath) { - checkNotStarted(); _crlPath = crlPath; } @@ -982,13 +891,11 @@ public class SslContextFactory extends AbstractLifeCycle } /** - * @param maxCertPathLength - * maximum number of intermediate certificates in - * the certification path (-1 for unlimited) + * @param maxCertPathLength maximum number of intermediate certificates in + * the certification path (-1 for unlimited) */ public void setMaxCertPathLength(int maxCertPathLength) { - checkNotStarted(); _maxCertPathLength = maxCertPathLength; } @@ -997,19 +904,31 @@ public class SslContextFactory extends AbstractLifeCycle */ public SSLContext getSslContext() { - return isStarted()?_factory._context:_setContext; + if (!isStarted()) + return _setContext; + + synchronized (this) + { + return _factory._context; + } } /** - * @param sslContext - * Set a preconfigured SSLContext + * @param sslContext Set a preconfigured SSLContext */ public void setSslContext(SSLContext sslContext) { - checkNotStarted(); _setContext = sslContext; } + /** + * @return the endpoint identification algorithm + */ + public String getEndpointIdentificationAlgorithm() + { + return _endpointIdentificationAlgorithm; + } + /** * When set to "HTTPS" hostname verification will be enabled * @@ -1017,7 +936,7 @@ public class SslContextFactory extends AbstractLifeCycle */ public void setEndpointIdentificationAlgorithm(String endpointIdentificationAlgorithm) { - this._endpointIdentificationAlgorithm = endpointIdentificationAlgorithm; + _endpointIdentificationAlgorithm = endpointIdentificationAlgorithm; } /** @@ -1029,7 +948,8 @@ public class SslContextFactory extends AbstractLifeCycle */ protected KeyStore loadKeyStore(Resource resource) throws Exception { - return CertificateUtils.getKeyStore(resource, _keyStoreType, _keyStoreProvider,_keyStorePassword==null? null:_keyStorePassword.toString()); + String storePassword = _keyStorePassword == null ? null : _keyStorePassword.toString(); + return CertificateUtils.getKeyStore(resource, getKeyStoreType(), getKeyStoreProvider(), storePassword); } /** @@ -1041,26 +961,25 @@ public class SslContextFactory extends AbstractLifeCycle */ protected KeyStore loadTrustStore(Resource resource) throws Exception { - String type=_trustStoreType; - String provider= _trustStoreProvider; - String passwd=_trustStorePassword==null? null:_trustStorePassword.toString(); - if (resource==null || resource.equals(_keyStoreResource)) + String type = getTrustStoreType(); + String provider = getTrustStoreProvider(); + String passwd = _trustStorePassword == null ? null : _trustStorePassword.toString(); + if (resource == null || resource.equals(_keyStoreResource)) { - resource=_keyStoreResource; - if (type==null) - type=_keyStoreType; - if (provider==null) - provider= _keyStoreProvider; - if (passwd==null) - passwd=_keyStorePassword==null? null:_keyStorePassword.toString(); + resource = _keyStoreResource; + if (type == null) + type = _keyStoreType; + if (provider == null) + provider = _keyStoreProvider; + if (passwd == null) + passwd = _keyStorePassword == null ? null : _keyStorePassword.toString(); } - - return CertificateUtils.getKeyStore(resource,type,provider,passwd); + return CertificateUtils.getKeyStore(resource, type, provider, passwd); } /** * Loads certificate revocation list (CRL) from a file. - * + *

    * Required for integrations to be able to override the mechanism used to * load CRL in order to provide their own implementation. * @@ -1079,18 +998,19 @@ public class SslContextFactory extends AbstractLifeCycle if (keyStore != null) { - KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(_keyManagerFactoryAlgorithm); - keyManagerFactory.init(keyStore,_keyManagerPassword == null?(_keyStorePassword == null?null:_keyStorePassword.toString().toCharArray()):_keyManagerPassword.toString().toCharArray()); + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(getKeyManagerFactoryAlgorithm()); + keyManagerFactory.init(keyStore, _keyManagerPassword == null ? (_keyStorePassword == null ? null : _keyStorePassword.toString().toCharArray()) : _keyManagerPassword.toString().toCharArray()); managers = keyManagerFactory.getKeyManagers(); - if (managers!=null) + if (managers != null) { - if (_certAlias != null) + String alias = getCertAlias(); + if (alias != null) { for (int idx = 0; idx < managers.length; idx++) { if (managers[idx] instanceof X509ExtendedKeyManager) - managers[idx] = new AliasedX509ExtendedKeyManager((X509ExtendedKeyManager)managers[idx],_certAlias); + managers[idx] = new AliasedX509ExtendedKeyManager((X509ExtendedKeyManager)managers[idx], alias); } } @@ -1099,13 +1019,14 @@ public class SslContextFactory extends AbstractLifeCycle for (int idx = 0; idx < managers.length; idx++) { if (managers[idx] instanceof X509ExtendedKeyManager) - managers[idx]=new SniX509ExtendedKeyManager((X509ExtendedKeyManager)managers[idx]); + managers[idx] = new SniX509ExtendedKeyManager((X509ExtendedKeyManager)managers[idx]); } } } } - LOG.debug("managers={} for {}",managers,this); + if (LOG.isDebugEnabled()) + LOG.debug("managers={} for {}", managers, this); return managers; } @@ -1116,9 +1037,9 @@ public class SslContextFactory extends AbstractLifeCycle if (trustStore != null) { // Revocation checking is only supported for PKIX algorithm - if (_validatePeerCerts && _trustManagerFactoryAlgorithm.equalsIgnoreCase("PKIX")) + if (isValidatePeerCerts() && "PKIX".equalsIgnoreCase(getTrustManagerFactoryAlgorithm())) { - PKIXBuilderParameters pbParams = new PKIXBuilderParameters(trustStore,new X509CertSelector()); + PKIXBuilderParameters pbParams = new PKIXBuilderParameters(trustStore, new X509CertSelector()); // Set maximum certification path length pbParams.setMaxPathLength(_maxCertPathLength); @@ -1128,19 +1049,19 @@ public class SslContextFactory extends AbstractLifeCycle if (crls != null && !crls.isEmpty()) { - pbParams.addCertStore(CertStore.getInstance("Collection",new CollectionCertStoreParameters(crls))); + pbParams.addCertStore(CertStore.getInstance("Collection", new CollectionCertStoreParameters(crls))); } if (_enableCRLDP) { // Enable Certificate Revocation List Distribution Points (CRLDP) support - System.setProperty("com.sun.security.enableCRLDP","true"); + System.setProperty("com.sun.security.enableCRLDP", "true"); } if (_enableOCSP) { // Enable On-Line Certificate Status Protocol (OCSP) support - Security.setProperty("ocsp.enable","true"); + Security.setProperty("ocsp.enable", "true"); if (_ocspResponderURL != null) { @@ -1170,7 +1091,8 @@ public class SslContextFactory extends AbstractLifeCycle * Select protocols to be used by the connector * based on configured inclusion and exclusion lists * as well as enabled and supported protocols. - * @param enabledProtocols Array of enabled protocols + * + * @param enabledProtocols Array of enabled protocols * @param supportedProtocols Array of supported protocols */ public void selectProtocols(String[] enabledProtocols, String[] supportedProtocols) @@ -1183,34 +1105,30 @@ public class SslContextFactory extends AbstractLifeCycle // Use only the supported included protocols for (String protocol : _includeProtocols) { - if(Arrays.asList(supportedProtocols).contains(protocol)) + if (Arrays.asList(supportedProtocols).contains(protocol)) selected_protocols.add(protocol); else - LOG.info("Protocol {} not supported in {}",protocol,Arrays.asList(supportedProtocols)); + LOG.info("Protocol {} not supported in {}", protocol, Arrays.asList(supportedProtocols)); } } else selected_protocols.addAll(Arrays.asList(enabledProtocols)); - // Remove any excluded protocols selected_protocols.removeAll(_excludeProtocols); - if (selected_protocols.isEmpty()) - LOG.warn("No selected protocols from {}",Arrays.asList(supportedProtocols)); - - _selectedProtocols = selected_protocols.toArray(new String[selected_protocols.size()]); - - + LOG.warn("No selected protocols from {}", Arrays.asList(supportedProtocols)); + _selectedProtocols = selected_protocols.toArray(new String[0]); } /** * Select cipher suites to be used by the connector * based on configured inclusion and exclusion lists * as well as enabled and supported cipher suite lists. - * @param enabledCipherSuites Array of enabled cipher suites + * + * @param enabledCipherSuites Array of enabled cipher suites * @param supportedCipherSuites Array of supported cipher suites */ protected void selectCipherSuites(String[] enabledCipherSuites, String[] supportedCipherSuites) @@ -1226,16 +1144,17 @@ public class SslContextFactory extends AbstractLifeCycle removeExcludedCipherSuites(selected_ciphers); if (selected_ciphers.isEmpty()) - LOG.warn("No supported ciphers from {}",Arrays.asList(supportedCipherSuites)); + LOG.warn("No supported ciphers from {}", Arrays.asList(supportedCipherSuites)); - if (_cipherComparator!=null) + Comparator comparator = getCipherComparator(); + if (comparator != null) { if (LOG.isDebugEnabled()) - LOG.debug("Sorting selected ciphers with {}",_cipherComparator); - Collections.sort(selected_ciphers,_cipherComparator); + LOG.debug("Sorting selected ciphers with {}", comparator); + Collections.sort(selected_ciphers, comparator); } - _selectedCipherSuites=selected_ciphers.toArray(new String[selected_ciphers.size()]); + _selectedCipherSuites = selected_ciphers.toArray(new String[0]); } protected void processIncludeCipherSuites(String[] supportedCipherSuites, List selected_ciphers) @@ -1243,19 +1162,19 @@ public class SslContextFactory extends AbstractLifeCycle for (String cipherSuite : _includeCipherSuites) { Pattern p = Pattern.compile(cipherSuite); - boolean added=false; + boolean added = false; for (String supportedCipherSuite : supportedCipherSuites) { Matcher m = p.matcher(supportedCipherSuite); if (m.matches()) { - added=true; + added = true; selected_ciphers.add(supportedCipherSuite); } } if (!added) - LOG.info("No Cipher matching '{}' is supported",cipherSuite); + LOG.info("No Cipher matching '{}' is supported", cipherSuite); } } @@ -1264,7 +1183,7 @@ public class SslContextFactory extends AbstractLifeCycle for (String excludeCipherSuite : _excludeCipherSuites) { Pattern excludeCipherPattern = Pattern.compile(excludeCipherSuite); - for (Iterator i=selected_ciphers.iterator();i.hasNext();) + for (Iterator i = selected_ciphers.iterator(); i.hasNext(); ) { String selectedCipherSuite = i.next(); Matcher m = excludeCipherPattern.matcher(selectedCipherSuite); @@ -1277,28 +1196,10 @@ public class SslContextFactory extends AbstractLifeCycle /** * Check if the lifecycle has been started and throw runtime exception */ - protected void checkNotStarted() - { - if (isStarted()) - throw new IllegalStateException("Cannot modify configuration when "+getState()); - } - - /** - * Check if the lifecycle has been started and throw runtime exception - */ - protected void checkIsStarted() + private void checkIsStarted() { if (!isStarted()) - throw new IllegalStateException("!STARTED: "+this); - } - - /** - * Check if the lifecycle has been started and throw runtime exception - */ - protected void checkIsRunning() - { - if (!isRunning()) - throw new IllegalStateException("!RUNNING: "+this); + throw new IllegalStateException("!STARTED: " + this); } /** @@ -1309,12 +1210,13 @@ public class SslContextFactory extends AbstractLifeCycle return _enableCRLDP; } - /** Enables CRL Distribution Points Support + /** + * Enables CRL Distribution Points Support + * * @param enableCRLDP true - turn on, false - turns off */ public void setEnableCRLDP(boolean enableCRLDP) { - checkNotStarted(); _enableCRLDP = enableCRLDP; } @@ -1326,12 +1228,13 @@ public class SslContextFactory extends AbstractLifeCycle return _enableOCSP; } - /** Enables On-Line Certificate Status Protocol support + /** + * Enables On-Line Certificate Status Protocol support + * * @param enableOCSP true - turn on, false - turn off */ public void setEnableOCSP(boolean enableOCSP) { - checkNotStarted(); _enableOCSP = enableOCSP; } @@ -1343,50 +1246,66 @@ public class SslContextFactory extends AbstractLifeCycle return _ocspResponderURL; } - /** Set the location of the OCSP Responder. + /** + * Set the location of the OCSP Responder. + * * @param ocspResponderURL location of the OCSP Responder */ public void setOcspResponderURL(String ocspResponderURL) { - checkNotStarted(); _ocspResponderURL = ocspResponderURL; } - /** Set the key store. + /** + * Set the key store. + * * @param keyStore the key store to set */ public void setKeyStore(KeyStore keyStore) { - checkNotStarted(); _setKeyStore = keyStore; } public KeyStore getKeyStore() { - return isStarted()?_factory._keyStore:_setKeyStore; + if (!isStarted()) + return _setKeyStore; + + synchronized (this) + { + return _factory._keyStore; + } } - /** Set the trust store. + /** + * Set the trust store. + * * @param trustStore the trust store to set */ public void setTrustStore(KeyStore trustStore) { - checkNotStarted(); _setTrustStore = trustStore; } public KeyStore getTrustStore() { - return isStarted()?_factory._trustStore:_setTrustStore; + if (!isStarted()) + return _setTrustStore; + + synchronized (this) + { + return _factory._trustStore; + } } - /** Set the key store resource. + /** + * Set the key store resource. + * * @param resource the key store resource to set */ public void setKeyStoreResource(Resource resource) { - checkNotStarted(); - _keyStoreResource=resource; + _keyStoreResource = resource; } public Resource getKeyStoreResource() @@ -1394,13 +1313,14 @@ public class SslContextFactory extends AbstractLifeCycle return _keyStoreResource; } - /** Set the trust store resource. + /** + * Set the trust store resource. + * * @param resource the trust store resource to set */ public void setTrustStoreResource(Resource resource) { - checkNotStarted(); - _trustStoreResource=resource; + _trustStoreResource = resource; } public Resource getTrustStoreResource() @@ -1409,19 +1329,21 @@ public class SslContextFactory extends AbstractLifeCycle } /** - * @return true if SSL Session caching is enabled - */ + * @return true if SSL Session caching is enabled + */ public boolean isSessionCachingEnabled() { return _sessionCachingEnabled; } - /** Set the flag to enable SSL Session caching. + /** + * Set the flag to enable SSL Session caching. * If set to true, then the {@link SSLContext#createSSLEngine(String, int)} method is * used to pass host and port information as a hint for session reuse. Note that * this is only a hint and session may not be reused. Moreover, the hint is typically - * only used on client side implementations and setting this to false does not + * only used on client side implementations and setting this to false does not * stop a server from accepting an offered session ID to reuse. + * * @param enableSessionCaching the value of the flag */ public void setSessionCachingEnabled(boolean enableSessionCaching) @@ -1429,8 +1351,10 @@ public class SslContextFactory extends AbstractLifeCycle _sessionCachingEnabled = enableSessionCaching; } - /** Get SSL session cache size. + /** + * Get SSL session cache size. * Passed directly to {@link SSLSessionContext#setSessionCacheSize(int)} + * * @return SSL session cache size */ public int getSslSessionCacheSize() @@ -1438,18 +1362,22 @@ public class SslContextFactory extends AbstractLifeCycle return _sslSessionCacheSize; } - /** Set SSL session cache size. + /** + * Set SSL session cache size. *

    Set the max cache size to be set on {@link SSLSessionContext#setSessionCacheSize(int)} * when this factory is started.

    + * * @param sslSessionCacheSize SSL session cache size to set. A value of -1 (default) uses - * the JVM default, 0 means unlimited and positive number is a max size. + * the JVM default, 0 means unlimited and positive number is a max size. */ public void setSslSessionCacheSize(int sslSessionCacheSize) { _sslSessionCacheSize = sslSessionCacheSize; } - /** Get SSL session timeout. + /** + * Get SSL session timeout. + * * @return SSL session timeout */ public int getSslSessionTimeout() @@ -1457,19 +1385,33 @@ public class SslContextFactory extends AbstractLifeCycle return _sslSessionTimeout; } - /** Set SSL session timeout. + /** + * Set SSL session timeout. *

    Set the timeout in seconds to be set on {@link SSLSessionContext#setSessionTimeout(int)} * when this factory is started.

    + * * @param sslSessionTimeout SSL session timeout to set in seconds. A value of -1 (default) uses - * the JVM default, 0 means unlimited and positive number is a timeout in seconds. + * the JVM default, 0 means unlimited and positive number is a timeout in seconds. */ public void setSslSessionTimeout(int sslSessionTimeout) { _sslSessionTimeout = sslSessionTimeout; } - + /** - * Create a new Password object + * Returns the password object for the given realm. + * + * @param realm the realm + * @return the Password object + */ + protected Password getPassword(String realm) + { + return Password.getPassword(realm, null, null); + } + + /** + * Creates a new Password object. + * * @param password the password string * @return the new Password object */ @@ -1478,16 +1420,18 @@ public class SslContextFactory extends AbstractLifeCycle return new Password(password); } - public SSLServerSocket newSslServerSocket(String host,int port,int backlog) throws IOException + public SSLServerSocket newSslServerSocket(String host, int port, int backlog) throws IOException { checkIsStarted(); - SSLServerSocketFactory factory = _factory._context.getServerSocketFactory(); + SSLContext context = getSslContext(); + SSLServerSocketFactory factory = context.getServerSocketFactory(); SSLServerSocket socket = - (SSLServerSocket) (host==null ? - factory.createServerSocket(port,backlog): - factory.createServerSocket(port,backlog,InetAddress.getByName(host))); + (SSLServerSocket)(host == null ? + factory.createServerSocket(port, backlog) : + factory.createServerSocket(port, backlog, InetAddress.getByName(host))); socket.setSSLParameters(customize(socket.getSSLParameters())); + return socket; } @@ -1495,9 +1439,11 @@ public class SslContextFactory extends AbstractLifeCycle { checkIsStarted(); - SSLSocketFactory factory = _factory._context.getSocketFactory(); + SSLContext context = getSslContext(); + SSLSocketFactory factory = context.getSocketFactory(); SSLSocket socket = (SSLSocket)factory.createSocket(); socket.setSSLParameters(customize(socket.getSSLParameters())); + return socket; } @@ -1512,9 +1458,12 @@ public class SslContextFactory extends AbstractLifeCycle */ public SSLEngine newSSLEngine() { - checkIsRunning(); - SSLEngine sslEngine=_factory._context.createSSLEngine(); + checkIsStarted(); + + SSLContext context = getSslContext(); + SSLEngine sslEngine = context.createSSLEngine(); customize(sslEngine); + return sslEngine; } @@ -1529,10 +1478,13 @@ public class SslContextFactory extends AbstractLifeCycle public SSLEngine newSSLEngine(String host, int port) { checkIsStarted(); - SSLEngine sslEngine=isSessionCachingEnabled() - ? _factory._context.createSSLEngine(host, port) - : _factory._context.createSSLEngine(); + + SSLContext context = getSslContext(); + SSLEngine sslEngine = isSessionCachingEnabled() ? + context.createSSLEngine(host, port) : + context.createSSLEngine(); customize(sslEngine); + return sslEngine; } @@ -1567,30 +1519,32 @@ public class SslContextFactory extends AbstractLifeCycle /** * Customize an SslEngine instance with the configuration of this factory, * by calling {@link #customize(SSLParameters)} - * @param sslEngine + * + * @param sslEngine the SSLEngine to customize */ public void customize(SSLEngine sslEngine) { if (LOG.isDebugEnabled()) - LOG.debug("Customize {}",sslEngine); + LOG.debug("Customize {}", sslEngine); sslEngine.setSSLParameters(customize(sslEngine.getSSLParameters())); } - + /** * Customize an SslParameters instance with the configuration of this factory. + * * @param sslParams The parameters to customize * @return The passed instance of sslParams (returned as a convenience) */ public SSLParameters customize(SSLParameters sslParams) { - sslParams.setEndpointIdentificationAlgorithm(_endpointIdentificationAlgorithm); - sslParams.setUseCipherSuitesOrder(_useCipherSuitesOrder); + sslParams.setEndpointIdentificationAlgorithm(getEndpointIdentificationAlgorithm()); + sslParams.setUseCipherSuitesOrder(isUseCipherSuitesOrder()); if (!_certHosts.isEmpty() || !_certWilds.isEmpty()) - sslParams.setSNIMatchers(Collections.singletonList((SNIMatcher)new AliasSNIMatcher())); - if (_selectedCipherSuites!=null) + sslParams.setSNIMatchers(Collections.singletonList(new AliasSNIMatcher())); + if (_selectedCipherSuites != null) sslParams.setCipherSuites(_selectedCipherSuites); - if (_selectedProtocols!=null) + if (_selectedProtocols != null) sslParams.setProtocols(_selectedProtocols); if (getWantClientAuth()) sslParams.setWantClientAuth(true); @@ -1598,24 +1552,34 @@ public class SslContextFactory extends AbstractLifeCycle sslParams.setNeedClientAuth(true); return sslParams; } - + + public void reload(Consumer consumer) throws Exception + { + synchronized (this) + { + consumer.accept(this); + unload(); + load(); + } + } + public static X509Certificate[] getCertChain(SSLSession sslSession) { try { - Certificate[] javaxCerts=sslSession.getPeerCertificates(); - if (javaxCerts==null||javaxCerts.length==0) + Certificate[] javaxCerts = sslSession.getPeerCertificates(); + if (javaxCerts == null || javaxCerts.length == 0) return null; - int length=javaxCerts.length; - X509Certificate[] javaCerts=new X509Certificate[length]; + int length = javaxCerts.length; + X509Certificate[] javaCerts = new X509Certificate[length]; - java.security.cert.CertificateFactory cf=java.security.cert.CertificateFactory.getInstance("X.509"); - for (int i=0; i * This is based on the information on effective key lengths in RFC 2246 - The TLS Protocol * Version 1.0, Appendix C. CipherSuite definitions: - * + *

    *

          *                         Effective
          *     Cipher       Type    Key Bits
    @@ -1694,25 +1657,19 @@ public class SslContextFactory extends AbstractLifeCycle
                     _trustStoreResource);
         }
     
    -    protected class Factory
    +    class Factory
         {
    -        final KeyStore _keyStore;
    -        final KeyStore _trustStore;
    -        final SSLContext _context;
    +        private final KeyStore _keyStore;
    +        private final KeyStore _trustStore;
    +        private final SSLContext _context;
     
    -        public Factory(KeyStore keyStore, KeyStore trustStore, SSLContext context)
    +        Factory(KeyStore keyStore, KeyStore trustStore, SSLContext context)
             {
                 super();
                 _keyStore = keyStore;
                 _trustStore = trustStore;
                 _context = context;
             }
    -
    -        @Override
    -        public String toString()
    -        {
    -            return String.format("SslFactory@%x{%s}",System.identityHashCode(this),SslContextFactory.this);
    -        }
         }
     
         class AliasSNIMatcher extends SNIMatcher
    @@ -1729,35 +1686,35 @@ public class SslContextFactory extends AbstractLifeCycle
             public boolean matches(SNIServerName serverName)
             {
                 if (LOG.isDebugEnabled())
    -                LOG.debug("SNI matching for {}",serverName);
    +                LOG.debug("SNI matching for {}", serverName);
     
                 if (serverName instanceof SNIHostName)
                 {
                     String host = _host = ((SNIHostName)serverName).getAsciiName();
    -                host=StringUtil.asciiToLowerCase(host);
    +                host = StringUtil.asciiToLowerCase(host);
     
                     // Try an exact match
                     _x509 = _certHosts.get(host);
     
                     // Else try an exact wild match
    -                if (_x509==null)
    +                if (_x509 == null)
                     {
                         _x509 = _certWilds.get(host);
     
                         // Else try an 1 deep wild match
    -                    if (_x509==null)
    +                    if (_x509 == null)
                         {
    -                        int dot=host.indexOf('.');
    -                        if (dot>=0)
    +                        int dot = host.indexOf('.');
    +                        if (dot >= 0)
                             {
    -                            String domain=host.substring(dot+1);
    +                            String domain = host.substring(dot + 1);
                                 _x509 = _certWilds.get(domain);
                             }
                         }
                     }
     
                     if (LOG.isDebugEnabled())
    -                    LOG.debug("SNI matched {}->{}",host,_x509);
    +                    LOG.debug("SNI matched {}->{}", host, _x509);
                 }
                 else
                 {
    diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/Invocable.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/Invocable.java
    index 9ca30661fac..84a95106ba9 100644
    --- a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/Invocable.java
    +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/Invocable.java
    @@ -28,6 +28,12 @@ import java.util.concurrent.Callable;
      * 
  1. non-blocking, the invocation will certainly not block
  2. *
  3. either, the invocation may block
  4. * + * + *

    + * Static methods and are provided that allow the current thread to be tagged + * with a {@link ThreadLocal} to indicate if it has a blocking invocation type. + *

    + * */ public interface Invocable { @@ -45,11 +51,21 @@ public interface Invocable } }; + /** + * Test if the current thread has been tagged as non blocking + * @return True if the task the current thread is running has + * indicated that it will not block. + */ public static boolean isNonBlockingInvocation() { return __nonBlocking.get(); } + /** + * Invoke a task with the calling thread, tagged to indicate + * that it will not block. + * @param task The task to invoke. + */ public static void invokeNonBlocking(Runnable task) { // a Choice exists, so we must indicate NonBlocking @@ -65,6 +81,13 @@ public interface Invocable } } + /** + * Invoke a task with the calling thread. + * If the task is an {@link Invocable} of {@link InvocationType#EITHER} + * then it is invoked with {@link #invokeNonBlocking(Runnable)}, to + * indicate the type of invocation that has been assumed. + * @param task The task to invoke. + */ public static void invokePreferNonBlocking(Runnable task) { switch (getInvocationType(task)) @@ -81,6 +104,15 @@ public interface Invocable } } + /** + * Invoke a task with the calling thread. + * If the task is an {@link Invocable} of {@link InvocationType#EITHER} + * and the preferredInvocationType is not {@link InvocationType#BLOCKING} + * then it is invoked with {@link #invokeNonBlocking(Runnable)}. + * @param task The task to invoke. + * @param preferredInvocationType The invocation type to use if the task + * does not indicate a preference. + */ public static void invokePreferred(Runnable task, InvocationType preferredInvocationType) { switch (getInvocationType(task)) @@ -99,6 +131,17 @@ public interface Invocable } } + /** + * wrap a task with the to indicate invocation type. + * If the task is an {@link Invocable} of {@link InvocationType#EITHER} + * and the preferredInvocationType is not {@link InvocationType#BLOCKING} + * then it is wrapped with an invocation of {@link #invokeNonBlocking(Runnable)}. + * otherwise the task itself is returned. + * @param task The task to invoke. + * @param preferredInvocationType The invocation type to use if the task + * does not indicate a preference. + * @return A Runnable that invokes the task in the declared or preferred type. + */ public static Runnable asPreferred(Runnable task, InvocationType preferredInvocationType) { switch (getInvocationType(task)) @@ -116,6 +159,12 @@ public interface Invocable return task; } + /** + * Get the invocation type of an Object. + * @param o The object to check the invocation type of. + * @return If the object is a {@link Invocable}, it is coerced and the {@link #getInvocationType()} + * used, otherwise {@link InvocationType#BLOCKING} is returned. + */ public static InvocationType getInvocationType(Object o) { if (o instanceof Invocable) @@ -123,6 +172,9 @@ public interface Invocable return InvocationType.BLOCKING; } + /** + * @return The InvocationType of this object + */ default InvocationType getInvocationType() { return InvocationType.BLOCKING; diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/Locker.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/Locker.java index bdb57f5da47..12b0b48e61b 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/Locker.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/Locker.java @@ -25,9 +25,9 @@ import java.util.concurrent.locks.ReentrantLock; * Convenience Lock Wrapper. * *
    - * try(SpinLock.Lock lock = locker.lock())
    + * try(Locker.Lock lock = locker.lock())
      * {
    - *   // something very quick and non blocking
    + *   // something 
      * }
      * 
    */ diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/ConcurrentArrayQueueTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/ConcurrentArrayQueueTest.java deleted file mode 100644 index f0d103b9661..00000000000 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/ConcurrentArrayQueueTest.java +++ /dev/null @@ -1,172 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.util; - -import java.util.Iterator; -import java.util.NoSuchElementException; - -import org.junit.Assert; -import org.junit.Test; - -public class ConcurrentArrayQueueTest -{ - protected ConcurrentArrayQueue newConcurrentArrayQueue(int blockSize) - { - return new ConcurrentArrayQueue<>(blockSize); - } - - @Test - public void testOfferCreatesBlock() - { - int blockSize = 2; - ConcurrentArrayQueue queue = newConcurrentArrayQueue(blockSize); - int blocks = 3; - for (int i = 0; i < blocks * blockSize + 1; ++i) - queue.offer(i); - Assert.assertEquals(blocks + 1, queue.getBlockCount()); - } - - @Test - public void testPeekRemove() throws Exception - { - int blockSize = 2; - ConcurrentArrayQueue queue = newConcurrentArrayQueue(blockSize); - - Assert.assertNull(queue.peek()); - - queue.offer(1); - queue.remove(1); - Assert.assertNull(queue.peek()); - - int blocks = 3; - int size = blocks * blockSize + 1; - for (int i = 0; i < size; ++i) - queue.offer(i); - for (int i = 0; i < size; ++i) - { - Assert.assertEquals(i, (int)queue.peek()); - Assert.assertEquals(i, (int)queue.remove()); - } - } - - @Test - public void testRemoveObject() throws Exception - { - int blockSize = 2; - ConcurrentArrayQueue queue = newConcurrentArrayQueue(blockSize); - queue.add(1); - queue.add(2); - queue.add(3); - - Assert.assertFalse(queue.remove(4)); - - int size = queue.size(); - - Assert.assertTrue(queue.remove(2)); - --size; - Assert.assertEquals(size, queue.size()); - - Iterator iterator = queue.iterator(); - Assert.assertTrue(iterator.hasNext()); - Assert.assertEquals(1, (int)iterator.next()); - Assert.assertTrue(iterator.hasNext()); - Assert.assertEquals(3, (int)iterator.next()); - - queue.offer(4); - ++size; - - Assert.assertTrue(queue.remove(3)); - --size; - Assert.assertEquals(size, queue.size()); - - iterator = queue.iterator(); - Assert.assertTrue(iterator.hasNext()); - Assert.assertEquals(1, (int)iterator.next()); - Assert.assertTrue(iterator.hasNext()); - Assert.assertEquals(4, (int)iterator.next()); - - Assert.assertTrue(queue.remove(1)); - --size; - Assert.assertTrue(queue.remove(4)); - --size; - - iterator = queue.iterator(); - Assert.assertFalse(iterator.hasNext()); - } - - @Test - public void testSize() throws Exception - { - int blockSize = 2; - ConcurrentArrayQueue queue = newConcurrentArrayQueue(blockSize); - queue.offer(1); - Assert.assertEquals(1, queue.size()); - - queue = newConcurrentArrayQueue(blockSize); - for (int i = 0; i < 2 * blockSize; ++i) - queue.offer(i); - for (int i = 0; i < blockSize; ++i) - queue.poll(); - Assert.assertEquals(blockSize, queue.size()); - } - - @Test - public void testIterator() throws Exception - { - int blockSize = 2; - ConcurrentArrayQueue queue = newConcurrentArrayQueue(blockSize); - queue.offer(1); - Iterator iterator = queue.iterator(); - Assert.assertTrue(iterator.hasNext()); - Assert.assertEquals(1, (int)iterator.next()); - Assert.assertFalse(iterator.hasNext()); - - try - { - iterator.next(); - Assert.fail(); - } - catch (NoSuchElementException ignored) - { - } - - // Test block edge - queue = newConcurrentArrayQueue(blockSize); - for (int i = 0; i < blockSize * 2; ++i) - queue.offer(i); - queue.poll(); - iterator = queue.iterator(); - Assert.assertTrue(iterator.hasNext()); - Assert.assertEquals(1, (int)iterator.next()); - Assert.assertTrue(iterator.hasNext()); - Assert.assertEquals(2, (int)iterator.next()); - Assert.assertTrue(iterator.hasNext()); - Assert.assertEquals(3, (int)iterator.next()); - Assert.assertFalse(iterator.hasNext()); - - try - { - iterator.next(); - Assert.fail(); - } - catch (NoSuchElementException ignored) - { - } - } -} diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/HostPortTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/HostPortTest.java new file mode 100644 index 00000000000..e1a2b33f905 --- /dev/null +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/HostPortTest.java @@ -0,0 +1,92 @@ +// +// ======================================================================== +// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.util; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.*; + +import java.util.Arrays; +import java.util.List; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class HostPortTest +{ + @Parameters(name="{0}") + public static List testCases() + { + String data[][] = new String[][] { + {"host","host",null}, + {"host:80","host","80"}, + {"10.10.10.1","10.10.10.1",null}, + {"10.10.10.1:80","10.10.10.1","80"}, + {"[0::0::0::1]","[0::0::0::1]",null}, + {"[0::0::0::1]:80","[0::0::0::1]","80"}, + + {null,null,null}, + {"host:",null,null}, + {"",null,null}, + {":80",null,"80"}, + {"127.0.0.1:",null,null}, + {"[0::0::0::0::1]:",null,null}, + {"host:xxx",null,null}, + {"127.0.0.1:xxx",null,null}, + {"[0::0::0::0::1]:xxx",null,null}, + {"host:-80",null,null}, + {"127.0.0.1:-80",null,null}, + {"[0::0::0::0::1]:-80",null,null}, + }; + return Arrays.asList(data); + } + + @Parameter(0) + public String _authority; + + @Parameter(1) + public String _expectedHost; + + @Parameter(2) + public String _expectedPort; + + + @Test + public void test() + { + try + { + HostPort hostPort = new HostPort(_authority); + assertThat(hostPort.getHost(),is(_expectedHost)); + + if (_expectedPort==null) + assertThat(hostPort.getPort(),is(0)); + else + assertThat(hostPort.getPort(),is(Integer.valueOf(_expectedPort))); + } + catch (Exception e) + { + assertNull(_expectedHost); + } + } + +} diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/IncludeExcludeSetTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/IncludeExcludeSetTest.java new file mode 100644 index 00000000000..6f27efcedfc --- /dev/null +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/IncludeExcludeSetTest.java @@ -0,0 +1,58 @@ +// +// ======================================================================== +// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.util; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.net.InetAddress; + +import org.junit.Test; + +public class IncludeExcludeSetTest +{ + @Test + public void testWithInetAddressSet() throws Exception + { + IncludeExcludeSet set = new IncludeExcludeSet<>(InetAddressSet.class); + assertTrue(set.test(InetAddress.getByName("192.168.0.1"))); + + set.include("10.10.0.0/16"); + assertFalse(set.test(InetAddress.getByName("192.168.0.1"))); + assertTrue(set.test(InetAddress.getByName("10.10.128.1"))); + + set.exclude("[::ffff:10.10.128.1]"); + assertFalse(set.test(InetAddress.getByName("10.10.128.1"))); + + set.include("[ffff:ff00::]/24"); + assertTrue(set.test(InetAddress.getByName("ffff:ff00::1"))); + assertTrue(set.test(InetAddress.getByName("ffff:ff00::42"))); + + set.exclude("[ffff:ff00::42]"); + assertTrue(set.test(InetAddress.getByName("ffff:ff00::41"))); + assertFalse(set.test(InetAddress.getByName("ffff:ff00::42"))); + assertTrue(set.test(InetAddress.getByName("ffff:ff00::43"))); + + + set.include("192.168.0.0-192.168.255.128"); + assertTrue(set.test(InetAddress.getByName("192.168.0.1"))); + assertTrue(set.test(InetAddress.getByName("192.168.254.255"))); + assertFalse(set.test(InetAddress.getByName("192.168.255.255"))); + } +} diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/IncludeExcludeTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/IncludeExcludeTest.java index 5927218ab10..a7864326db0 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/IncludeExcludeTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/IncludeExcludeTest.java @@ -32,7 +32,7 @@ public class IncludeExcludeTest IncludeExclude ie = new IncludeExclude<>(); assertThat("Empty IncludeExclude", ie.size(), is(0)); - assertThat("Matches 'foo'",ie.matches("foo"),is(true)); + assertThat("Matches 'foo'",ie.test("foo"),is(true)); } @Test @@ -43,10 +43,10 @@ public class IncludeExcludeTest ie.include("bar"); assertThat("IncludeExclude.size", ie.size(), is(2)); - assertEquals(false,ie.matches("")); - assertEquals(true,ie.matches("foo")); - assertEquals(true,ie.matches("bar")); - assertEquals(false,ie.matches("foobar")); + assertEquals(false,ie.test("")); + assertEquals(true,ie.test("foo")); + assertEquals(true,ie.test("bar")); + assertEquals(false,ie.test("foobar")); } @Test @@ -58,11 +58,11 @@ public class IncludeExcludeTest assertEquals(2,ie.size()); - assertEquals(false,ie.matches("foo")); - assertEquals(false,ie.matches("bar")); - assertEquals(true,ie.matches("")); - assertEquals(true,ie.matches("foobar")); - assertEquals(true,ie.matches("wibble")); + assertEquals(false,ie.test("foo")); + assertEquals(false,ie.test("bar")); + assertEquals(true,ie.test("")); + assertEquals(true,ie.test("foobar")); + assertEquals(true,ie.test("wibble")); } @Test @@ -76,11 +76,11 @@ public class IncludeExcludeTest assertEquals(4,ie.size()); - assertEquals(true,ie.matches("foo")); - assertEquals(false,ie.matches("bar")); - assertEquals(false,ie.matches("")); - assertEquals(false,ie.matches("foobar")); - assertEquals(false,ie.matches("xxx")); + assertEquals(true,ie.test("foo")); + assertEquals(false,ie.test("bar")); + assertEquals(false,ie.test("")); + assertEquals(false,ie.test("foobar")); + assertEquals(false,ie.test("xxx")); } @@ -91,7 +91,7 @@ public class IncludeExcludeTest IncludeExclude ie = new IncludeExclude<>(RegexSet.class); assertEquals(0,ie.size()); - assertEquals(true,ie.matches("foo")); + assertEquals(true,ie.test("foo")); } @Test @@ -102,13 +102,13 @@ public class IncludeExcludeTest ie.include("b((ar)|(oo))"); assertEquals(2,ie.size()); - assertEquals(false,ie.matches("")); - assertEquals(true,ie.matches("foo")); - assertEquals(true,ie.matches("far")); - assertEquals(true,ie.matches("bar")); - assertEquals(true,ie.matches("boo")); - assertEquals(false,ie.matches("foobar")); - assertEquals(false,ie.matches("xxx")); + assertEquals(false,ie.test("")); + assertEquals(true,ie.test("foo")); + assertEquals(true,ie.test("far")); + assertEquals(true,ie.test("bar")); + assertEquals(true,ie.test("boo")); + assertEquals(false,ie.test("foobar")); + assertEquals(false,ie.test("xxx")); } @Test @@ -120,13 +120,13 @@ public class IncludeExcludeTest assertEquals(2,ie.size()); - assertEquals(false,ie.matches("foo")); - assertEquals(false,ie.matches("far")); - assertEquals(false,ie.matches("bar")); - assertEquals(false,ie.matches("boo")); - assertEquals(true,ie.matches("")); - assertEquals(true,ie.matches("foobar")); - assertEquals(true,ie.matches("xxx")); + assertEquals(false,ie.test("foo")); + assertEquals(false,ie.test("far")); + assertEquals(false,ie.test("bar")); + assertEquals(false,ie.test("boo")); + assertEquals(true,ie.test("")); + assertEquals(true,ie.test("foobar")); + assertEquals(true,ie.test("xxx")); } @Test @@ -139,14 +139,14 @@ public class IncludeExcludeTest ie.exclude("b((ar)|(oo))"); assertEquals(4,ie.size()); - assertEquals(false,ie.matches("foo")); - assertEquals(false,ie.matches("far")); - assertEquals(false,ie.matches("bar")); - assertEquals(false,ie.matches("boo")); - assertEquals(false,ie.matches("")); - assertEquals(false,ie.matches("xxx")); + assertEquals(false,ie.test("foo")); + assertEquals(false,ie.test("far")); + assertEquals(false,ie.test("bar")); + assertEquals(false,ie.test("boo")); + assertEquals(false,ie.test("")); + assertEquals(false,ie.test("xxx")); - assertEquals(true,ie.matches("foobar")); - assertEquals(true,ie.matches("Ant")); + assertEquals(true,ie.test("foobar")); + assertEquals(true,ie.test("Ant")); } } diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/InetAddressSetTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/InetAddressSetTest.java new file mode 100644 index 00000000000..a675cf47052 --- /dev/null +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/InetAddressSetTest.java @@ -0,0 +1,332 @@ +// +// ======================================================================== +// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.util; + +import static org.junit.Assert.*; + +import java.net.InetAddress; +import java.util.Iterator; + +import org.hamcrest.Matchers; +import org.junit.Assert; +import org.junit.Test; + +public class InetAddressSetTest +{ + @Test + public void testInetAddress() throws Exception + { + assertTrue(InetAddress.getByName("127.0.0.1").isLoopbackAddress()); + assertTrue(InetAddress.getByName("::1").isLoopbackAddress()); + assertTrue(InetAddress.getByName("::0.0.0.1").isLoopbackAddress()); + assertTrue(InetAddress.getByName("[::1]").isLoopbackAddress()); + assertTrue(InetAddress.getByName("[::0.0.0.1]").isLoopbackAddress()); + assertTrue(InetAddress.getByName("[::ffff:127.0.0.1]").isLoopbackAddress()); + } + + @Test + public void testSingleton() throws Exception + { + InetAddressSet set = new InetAddressSet(); + + set.add("webtide.com"); + set.add("1.2.3.4"); + set.add("::abcd"); + + assertTrue(set.test(InetAddress.getByName("webtide.com"))); + assertTrue(set.test(InetAddress.getByName(InetAddress.getByName("webtide.com").getHostAddress()))); + assertTrue(set.test(InetAddress.getByName("1.2.3.4"))); + assertTrue(set.test(InetAddress.getByAddress(new byte[]{(byte)1,(byte)2,(byte)3,(byte)4}))); + assertTrue(set.test(InetAddress.getByAddress("hostname",new byte[]{(byte)1,(byte)2,(byte)3,(byte)4}))); + assertTrue(set.test(InetAddress.getByName("::0:0:abcd"))); + assertTrue(set.test(InetAddress.getByName("::abcd"))); + assertTrue(set.test(InetAddress.getByName("[::abcd]"))); + assertTrue(set.test(InetAddress.getByName("::ffff:1.2.3.4"))); + + assertFalse(set.test(InetAddress.getByName("www.google.com"))); + assertFalse(set.test(InetAddress.getByName("1.2.3.5"))); + assertFalse(set.test(InetAddress.getByAddress(new byte[]{(byte)1,(byte)2,(byte)3,(byte)5}))); + assertFalse(set.test(InetAddress.getByAddress("webtide.com",new byte[]{(byte)1,(byte)2,(byte)3,(byte)5}))); + assertFalse(set.test(InetAddress.getByName("::1.2.3.4"))); + assertFalse(set.test(InetAddress.getByName("::1234"))); + assertFalse(set.test(InetAddress.getByName("::abce"))); + assertFalse(set.test(InetAddress.getByName("1::abcd"))); + } + + @Test + public void testBadSingleton() throws Exception + { + String[] tests = new String[] + { + "unknown", + "1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16", + "a.b.c.d", + "[::1", + "[xxx]", + "[:::1]", + }; + + InetAddressSet set = new InetAddressSet(); + + for (String t:tests) + { + try + { + set.add(t); + fail(t); + } + catch(IllegalArgumentException e) + { + Assert.assertThat(e.getMessage(),Matchers.containsString(t)); + } + } + } + + @Test + public void testCIDR() throws Exception + { + InetAddressSet set = new InetAddressSet(); + + set.add("10.10.0.0/16"); + set.add("192.0.80.0/22"); + set.add("168.0.0.80/30"); + set.add("abcd:ef00::/24"); + + assertTrue(set.test(InetAddress.getByName("10.10.0.0"))); + assertTrue(set.test(InetAddress.getByName("10.10.0.1"))); + assertTrue(set.test(InetAddress.getByName("10.10.255.255"))); + assertTrue(set.test(InetAddress.getByName("::ffff:10.10.0.1"))); + assertTrue(set.test(InetAddress.getByName("192.0.80.0"))); + assertTrue(set.test(InetAddress.getByName("192.0.83.1"))); + assertTrue(set.test(InetAddress.getByName("168.0.0.80"))); + assertTrue(set.test(InetAddress.getByName("168.0.0.83"))); + assertTrue(set.test(InetAddress.getByName("abcd:ef00::1"))); + assertTrue(set.test(InetAddress.getByName("abcd:efff::ffff"))); + + assertFalse(set.test(InetAddress.getByName("10.11.0.0"))); + assertFalse(set.test(InetAddress.getByName("1.2.3.5"))); + assertFalse(set.test(InetAddress.getByName("192.0.84.1"))); + assertFalse(set.test(InetAddress.getByName("168.0.0.84"))); + assertFalse(set.test(InetAddress.getByName("::10.10.0.1"))); + assertFalse(set.test(InetAddress.getByName("abcd:eeff::1"))); + assertFalse(set.test(InetAddress.getByName("abcd:f000::"))); + + + set.add("255.255.255.255/32"); + assertTrue(set.test(InetAddress.getByName("255.255.255.255"))); + assertFalse(set.test(InetAddress.getByName("10.11.0.0"))); + + set.add("0.0.0.0/0"); + assertTrue(set.test(InetAddress.getByName("10.11.0.0"))); + } + + @Test + public void testBadCIDR() throws Exception + { + String[] tests = new String[] + { + "unknown/8", + "1.2.3.4/-1", + "1.2.3.4/xxx", + "1.2.3.4/33", + "255.255.8.0/16", + "255.255.8.1/17", + "[::1]/129", + }; + + InetAddressSet set = new InetAddressSet(); + + for (String t:tests) + { + try + { + set.add(t); + fail(t); + } + catch(IllegalArgumentException e) + { + Assert.assertThat(e.getMessage(),Matchers.containsString(t)); + } + } + } + + @Test + public void testMinMax() throws Exception + { + InetAddressSet set = new InetAddressSet(); + + set.add("10.0.0.4-10.0.0.6"); + set.add("10.1.0.254-10.1.1.1"); + set.add("[abcd:ef::fffe]-[abcd:ef::1:1]"); + + assertFalse(set.test(InetAddress.getByName("10.0.0.3"))); + assertTrue(set.test(InetAddress.getByName("10.0.0.4"))); + assertTrue(set.test(InetAddress.getByName("10.0.0.5"))); + assertTrue(set.test(InetAddress.getByName("10.0.0.6"))); + assertFalse(set.test(InetAddress.getByName("10.0.0.7"))); + + assertFalse(set.test(InetAddress.getByName("10.1.0.253"))); + assertTrue(set.test(InetAddress.getByName("10.1.0.254"))); + assertTrue(set.test(InetAddress.getByName("10.1.0.255"))); + assertTrue(set.test(InetAddress.getByName("10.1.1.0"))); + assertTrue(set.test(InetAddress.getByName("10.1.1.1"))); + assertFalse(set.test(InetAddress.getByName("10.1.1.2"))); + + assertFalse(set.test(InetAddress.getByName("ABCD:EF::FFFD"))); + assertTrue(set.test(InetAddress.getByName("ABCD:EF::FFFE"))); + assertTrue(set.test(InetAddress.getByName("ABCD:EF::FFFF"))); + assertTrue(set.test(InetAddress.getByName("ABCD:EF::1:0"))); + assertTrue(set.test(InetAddress.getByName("ABCD:EF::1:1"))); + assertFalse(set.test(InetAddress.getByName("ABCD:EF::1:2"))); + } + + @Test + public void testBadMinMax() throws Exception + { + String[] tests = new String[] + { + "10.0.0.0-9.0.0.0", + "9.0.0.0-[::10.0.0.0]", + }; + + InetAddressSet set = new InetAddressSet(); + + for (String t:tests) + { + try + { + set.add(t); + fail(t); + } + catch(IllegalArgumentException e) + { + Assert.assertThat(e.getMessage(),Matchers.containsString(t)); + } + } + } + + @Test + public void testLegacy() throws Exception + { + InetAddressSet set = new InetAddressSet(); + + set.add("10.-.245-.-2"); + set.add("11.11.11.127-129"); + + assertFalse(set.test(InetAddress.getByName("9.0.245.0"))); + + assertTrue(set.test(InetAddress.getByName("10.0.245.0"))); + assertTrue(set.test(InetAddress.getByName("10.0.245.1"))); + assertTrue(set.test(InetAddress.getByName("10.0.245.2"))); + assertFalse(set.test(InetAddress.getByName("10.0.245.3"))); + + assertTrue(set.test(InetAddress.getByName("10.255.255.0"))); + assertTrue(set.test(InetAddress.getByName("10.255.255.1"))); + assertTrue(set.test(InetAddress.getByName("10.255.255.2"))); + assertFalse(set.test(InetAddress.getByName("10.255.255.3"))); + + assertFalse(set.test(InetAddress.getByName("10.0.244.0"))); + assertFalse(set.test(InetAddress.getByName("10.0.244.1"))); + assertFalse(set.test(InetAddress.getByName("10.0.244.2"))); + assertFalse(set.test(InetAddress.getByName("10.0.244.3"))); + } + + @Test + public void testBadLegacy() throws Exception + { + String[] tests = new String[] + { + "9.0-10.0", + "10.0.0--1.1", + "10.0.0-256.1", + }; + + InetAddressSet set = new InetAddressSet(); + + for (String t:tests) + { + try + { + set.add(t); + fail(t); + } + catch(IllegalArgumentException e) + { + Assert.assertThat(e.getMessage(),Matchers.containsString(t)); + } + } + } + + @Test + public void testRemove() throws Exception + { + InetAddressSet set = new InetAddressSet(); + + set.add("webtide.com"); + set.add("1.2.3.4"); + set.add("::abcd"); + set.add("10.0.0.4-10.0.0.6"); + + assertTrue(set.test(InetAddress.getByName("webtide.com"))); + assertTrue(set.test(InetAddress.getByName(InetAddress.getByName("webtide.com").getHostAddress()))); + assertTrue(set.test(InetAddress.getByName("1.2.3.4"))); + assertTrue(set.test(InetAddress.getByAddress(new byte[]{(byte)1,(byte)2,(byte)3,(byte)4}))); + assertTrue(set.test(InetAddress.getByAddress("hostname",new byte[]{(byte)1,(byte)2,(byte)3,(byte)4}))); + assertTrue(set.test(InetAddress.getByName("::0:0:abcd"))); + assertTrue(set.test(InetAddress.getByName("::abcd"))); + assertTrue(set.test(InetAddress.getByName("[::abcd]"))); + assertTrue(set.test(InetAddress.getByName("::ffff:1.2.3.4"))); + assertTrue(set.test(InetAddress.getByName("10.0.0.4"))); + assertTrue(set.test(InetAddress.getByName("10.0.0.5"))); + assertTrue(set.test(InetAddress.getByName("10.0.0.6"))); + + set.remove("1.2.3.4"); + assertTrue(set.test(InetAddress.getByName("webtide.com"))); + assertTrue(set.test(InetAddress.getByName(InetAddress.getByName("webtide.com").getHostAddress()))); + assertFalse(set.test(InetAddress.getByName("1.2.3.4"))); + assertFalse(set.test(InetAddress.getByAddress(new byte[]{(byte)1,(byte)2,(byte)3,(byte)4}))); + assertFalse(set.test(InetAddress.getByAddress("hostname",new byte[]{(byte)1,(byte)2,(byte)3,(byte)4}))); + assertTrue(set.test(InetAddress.getByName("::0:0:abcd"))); + assertTrue(set.test(InetAddress.getByName("::abcd"))); + assertTrue(set.test(InetAddress.getByName("[::abcd]"))); + assertFalse(set.test(InetAddress.getByName("::ffff:1.2.3.4"))); + assertTrue(set.test(InetAddress.getByName("10.0.0.4"))); + assertTrue(set.test(InetAddress.getByName("10.0.0.5"))); + assertTrue(set.test(InetAddress.getByName("10.0.0.6"))); + + for (Iterator i=set.iterator();i.hasNext();) + { + if ("::abcd".equals(i.next())) + i.remove(); + } + assertTrue(set.test(InetAddress.getByName("webtide.com"))); + assertTrue(set.test(InetAddress.getByName(InetAddress.getByName("webtide.com").getHostAddress()))); + assertFalse(set.test(InetAddress.getByName("1.2.3.4"))); + assertFalse(set.test(InetAddress.getByAddress(new byte[]{(byte)1,(byte)2,(byte)3,(byte)4}))); + assertFalse(set.test(InetAddress.getByAddress("hostname",new byte[]{(byte)1,(byte)2,(byte)3,(byte)4}))); + assertFalse(set.test(InetAddress.getByName("::0:0:abcd"))); + assertFalse(set.test(InetAddress.getByName("::abcd"))); + assertFalse(set.test(InetAddress.getByName("[::abcd]"))); + assertFalse(set.test(InetAddress.getByName("::ffff:1.2.3.4"))); + assertTrue(set.test(InetAddress.getByName("10.0.0.4"))); + assertTrue(set.test(InetAddress.getByName("10.0.0.5"))); + assertTrue(set.test(InetAddress.getByName("10.0.0.6"))); + + } +} diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/QueueBenchmarkTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/QueueBenchmarkTest.java index 8c01f7e26e4..2906931d414 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/QueueBenchmarkTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/QueueBenchmarkTest.java @@ -40,20 +40,8 @@ import org.junit.runner.RunWith; public class QueueBenchmarkTest { private static final Logger logger = Log.getLogger(QueueBenchmarkTest.class); - private static final Runnable ELEMENT = new Runnable() - { - @Override - public void run() - { - } - }; - private static final Runnable END = new Runnable() - { - @Override - public void run() - { - } - }; + private static final Runnable ELEMENT = () -> {}; + private static final Runnable END = () -> {}; @Stress("High CPU") @Test @@ -67,10 +55,9 @@ public class QueueBenchmarkTest final int iterations = 16 * 1024 * 1024; final List> queues = new ArrayList<>(); - queues.add(new ConcurrentArrayQueue()); // Jetty lock-free queue, allocating array blocks - queues.add(new ConcurrentLinkedQueue()); // JDK lock-free queue, allocating nodes - queues.add(new ArrayBlockingQueue(iterations * writers)); // JDK lock-based, circular array queue - queues.add(new BlockingArrayQueue(iterations * writers)); // Jetty lock-based, circular array queue + queues.add(new ConcurrentLinkedQueue<>()); // JDK lock-free queue, allocating nodes + queues.add(new ArrayBlockingQueue<>(iterations * writers)); // JDK lock-based, circular array queue + queues.add(new BlockingArrayQueue<>(iterations * writers)); // Jetty lock-based, circular array queue testQueues(readers, writers, iterations, queues, false); } @@ -87,9 +74,9 @@ public class QueueBenchmarkTest final int iterations = 16 * 1024 * 1024; final List> queues = new ArrayList<>(); - queues.add(new LinkedBlockingQueue()); - queues.add(new ArrayBlockingQueue(iterations * writers)); - queues.add(new BlockingArrayQueue(iterations * writers)); + queues.add(new LinkedBlockingQueue<>()); + queues.add(new ArrayBlockingQueue<>(iterations * writers)); + queues.add(new BlockingArrayQueue<>(iterations * writers)); testQueues(readers, writers, iterations, queues, true); } diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/TypeUtilTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/TypeUtilTest.java index 84ecb626480..78707bc9312 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/TypeUtilTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/TypeUtilTest.java @@ -19,6 +19,7 @@ package org.eclipse.jetty.util; +import org.hamcrest.Matchers; import org.junit.Assert; import org.junit.Test; @@ -119,4 +120,12 @@ public class TypeUtilTest Assert.assertFalse(TypeUtil.isFalse("blargle")); Assert.assertFalse(TypeUtil.isFalse(new Object(){@Override public String toString(){return "true";}})); } + + @Test + public void testLoadedFrom() throws Exception + { + Assert.assertThat(TypeUtil.getLoadedFrom(String.class).toString(),Matchers.containsString("/rt.jar")); + Assert.assertThat(TypeUtil.getLoadedFrom(Assert.class).toString(),Matchers.containsString(".jar")); + Assert.assertThat(TypeUtil.getLoadedFrom(TypeUtil.class).toString(),Matchers.containsString("/classes/")); + } } diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java index 21909584974..d0e1f66f66d 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java @@ -18,12 +18,17 @@ package org.eclipse.jetty.util; +import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import java.net.URI; import java.nio.charset.StandardCharsets; +import org.hamcrest.Matchers; +import org.junit.Assert; import org.junit.Test; @@ -286,4 +291,15 @@ public class URIUtilTest } + /* ------------------------------------------------------------ */ + @Test + public void testJarSource() throws Exception + { + assertThat(URIUtil.getJarSource("file:///tmp/"),is("file:///tmp/")); + assertThat(URIUtil.getJarSource("jar:file:///tmp/foo.jar"),is("file:///tmp/foo.jar")); + assertThat(URIUtil.getJarSource("jar:file:///tmp/foo.jar!/some/path"),is("file:///tmp/foo.jar")); + assertThat(URIUtil.getJarSource(new URI("file:///tmp/")),is(new URI("file:///tmp/"))); + assertThat(URIUtil.getJarSource(new URI("jar:file:///tmp/foo.jar")),is(new URI("file:///tmp/foo.jar"))); + assertThat(URIUtil.getJarSource(new URI("jar:file:///tmp/foo.jar!/some/path")),is(new URI("file:///tmp/foo.jar"))); + } } diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/thread/strategy/ExecuteProduceConsumeTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/thread/strategy/ExecuteProduceConsumeTest.java index 9609bc33de7..bc555c32bd8 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/thread/strategy/ExecuteProduceConsumeTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/thread/strategy/ExecuteProduceConsumeTest.java @@ -23,9 +23,8 @@ import java.util.Queue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; +import java.util.concurrent.LinkedBlockingQueue; -import org.eclipse.jetty.util.BlockingArrayQueue; -import org.eclipse.jetty.util.ConcurrentArrayQueue; import org.eclipse.jetty.util.thread.ExecutionStrategy.Producer; import org.hamcrest.Matchers; import org.junit.After; @@ -37,8 +36,8 @@ public class ExecuteProduceConsumeTest { private static final Runnable NULLTASK = () -> {}; - private final BlockingQueue _produce = new BlockingArrayQueue<>(); - private final Queue _executions = new ConcurrentArrayQueue<>(); + private final BlockingQueue _produce = new LinkedBlockingQueue<>(); + private final Queue _executions = new LinkedBlockingQueue<>(); private ExecuteProduceConsume _ewyk; private volatile Thread _producer; diff --git a/jetty-webapp/src/main/config/etc/jetty-webapp.xml b/jetty-webapp/src/main/config/etc/jetty-webapp.xml new file mode 100644 index 00000000000..1f8e737e9bf --- /dev/null +++ b/jetty-webapp/src/main/config/etc/jetty-webapp.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jetty-webapp/src/main/config/modules/webapp.mod b/jetty-webapp/src/main/config/modules/webapp.mod index c753f8d761e..83e2d839d1d 100644 --- a/jetty-webapp/src/main/config/modules/webapp.mod +++ b/jetty-webapp/src/main/config/modules/webapp.mod @@ -6,5 +6,23 @@ classpath. Without this, only Jetty specific handlers may be deployed. servlet security +[xml] +etc/jetty-webapp.xml + [lib] lib/jetty-webapp-${jetty.version}.jar + + +[ini-template] +## Add to the server wide default jars and packages protected or hidden from webapps. +## System classes are protected and cannot be overridden by a webapp. +## Server classes are hidden and cannot be seen by a webapp +## Lists of patterns are comma separated and may be either: +## + a qualified classname e.g. 'com.acme.Foo' +## + a package name e.g. 'net.example.' +## + a jar file e.g. 'file:${jetty.base}/lib/dependency.jar' +## + a directory of jars,resource or classes e.g. 'file:${jetty.base}/resources' +## + A pattern preceeded with a '-' is an exclusion, all other patterns are inclusions +## +jetty.webapp.addSystemClasses,= +jetty.webapp.addServerClasses,= diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/ClasspathPattern.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/ClasspathPattern.java index a1f564e8e4d..32ed9526aad 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/ClasspathPattern.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/ClasspathPattern.java @@ -19,13 +19,30 @@ package org.eclipse.jetty.webapp; -import java.util.AbstractList; +import static java.lang.Boolean.FALSE; +import static java.lang.Boolean.TRUE; + +import java.io.File; +import java.net.URL; +import java.nio.file.Path; +import java.util.AbstractSet; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; import java.util.List; -import java.util.ListIterator; +import java.util.Map; +import java.util.Set; +import java.util.function.Predicate; -import org.eclipse.jetty.util.StringUtil; +import org.eclipse.jetty.util.ArrayTernaryTrie; +import org.eclipse.jetty.util.IncludeExcludeSet; +import org.eclipse.jetty.util.TypeUtil; +import org.eclipse.jetty.util.URIUtil; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.resource.Resource; /* ------------------------------------------------------------ */ /** @@ -45,21 +62,59 @@ import org.eclipse.jetty.util.StringUtil; * in this string should be separated by ':' (semicolon) or ',' (comma). */ -public class ClasspathPattern extends AbstractList +public class ClasspathPattern extends AbstractSet { + private static final Logger LOG = Log.getLogger(ClasspathPattern.class); + + enum Type { PACKAGE, CLASSNAME, LOCATION } + private static class Entry { - public final String _pattern; - public final String _name; - public final boolean _inclusive; - public final boolean _package; + private final String _pattern; + private final String _name; + private final boolean _inclusive; + private final Type _type; Entry(String pattern) { _pattern=pattern; _inclusive = !pattern.startsWith("-"); - _package = pattern.endsWith("."); _name = _inclusive ? pattern : pattern.substring(1).trim(); + _type = (_name.startsWith("file:"))?Type.LOCATION:(_name.endsWith(".")?Type.PACKAGE:Type.CLASSNAME); + } + + Entry(String name, boolean include) + { + _pattern=include?name:("-"+name); + _inclusive = include; + _name = name; + _type = (_name.startsWith("file:"))?Type.LOCATION:(_name.endsWith(".")?Type.PACKAGE:Type.CLASSNAME); + } + + + public String getPattern() + { + return _pattern; + } + + public boolean isPackage() + { + return _type==Type.PACKAGE; + } + + public boolean isClassName() + { + return _type==Type.CLASSNAME; + } + + public boolean isLocation() + { + return _type==Type.LOCATION; + } + + public String getName() + { + return _name; } @Override @@ -67,86 +122,356 @@ public class ClasspathPattern extends AbstractList { return _pattern; } + + @Override + public int hashCode() + { + return _pattern.hashCode(); + } + + @Override + public boolean equals(Object o) + { + return (o instanceof Entry) + && _pattern.equals(((Entry)o)._pattern); + } + + public boolean isInclusive() + { + return _inclusive; + } } - final private List _entries = new ArrayList(); - /* ------------------------------------------------------------ */ + public static class ByPackage extends AbstractSet implements Predicate + { + private final ArrayTernaryTrie.Growing _entries = new ArrayTernaryTrie.Growing<>(false,512,512); + + @Override + public boolean test(String name) + { + return _entries.getBest(name)!=null; + } + + @Override + public Iterator iterator() + { + return _entries.keySet().stream().map(k->_entries.get(k)).iterator(); + } + + @Override + public int size() + { + return _entries.size(); + } + + @Override + public boolean isEmpty() + { + return _entries.isEmpty(); + } + + @Override + public boolean add(Entry entry) + { + String name = entry.getName(); + if (entry.isClassName()) + name+="$"; + else if (entry.isLocation()) + throw new IllegalArgumentException(entry.toString()); + else if (".".equals(name)) + name=""; + + if (_entries.get(name)!=null) + return false; + + _entries.put(name,entry); + return true; + } + + @Override + public boolean remove(Object entry) + { + if (!(entry instanceof Entry)) + return false; + + return _entries.remove(((Entry)entry).getName())!=null; + } + + @Override + public void clear() + { + _entries.clear(); + } + } + + @SuppressWarnings("serial") + public static class ByName extends HashSet implements Predicate + { + private final Map _entries = new HashMap<>(); + + @Override + public boolean test(String name) + { + return _entries.containsKey(name); + } + + @Override + public Iterator iterator() + { + return _entries.values().iterator(); + } + + @Override + public int size() + { + return _entries.size(); + } + + @Override + public boolean add(Entry entry) + { + if (!entry.isClassName()) + throw new IllegalArgumentException(entry.toString()); + return _entries.put(entry.getName(),entry)==null; + } + + @Override + public boolean remove(Object entry) + { + if (!(entry instanceof Entry)) + return false; + + return _entries.remove(((Entry)entry).getName())!=null; + } + } + + public static class ByPackageOrName extends AbstractSet implements Predicate + { + private final ByName _byName = new ByName(); + private final ByPackage _byPackage = new ByPackage(); + + @Override + public boolean test(String name) + { + return _byPackage.test(name) + || _byName.test(name) ; + } + + @Override + public Iterator iterator() + { + // by package contains all entries (classes are also $ packages). + return _byPackage.iterator(); + } + + @Override + public int size() + { + return _byPackage.size(); + } + + @Override + public boolean add(Entry e) + { + if (e.isLocation()) + throw new IllegalArgumentException(); + + if (e.isPackage()) + return _byPackage.add(e); + + // Add class name to packages also as classes act + // as packages for nested classes. + boolean added = _byPackage.add(e); + added = _byName.add(e) || added; + return added; + } + + @Override + public boolean remove(Object o) + { + if (!(o instanceof Entry)) + return false; + + boolean removed = _byPackage.remove(o); + + if (!((Entry)o).isPackage()) + removed = _byName.remove(o) || removed; + + return removed; + } + + @Override + public void clear() + { + _byPackage.clear(); + _byName.clear(); + } + } + + @SuppressWarnings("serial") + public static class ByLocation extends HashSet implements Predicate + { + @Override + public boolean test(Path path) + { + for (File file: this) + { + if (file.isDirectory()) + { + if (path.startsWith(file.toPath())) + return true; + } + else + { + if (path.equals(file.toPath())) + return true; + } + } + + return false; + } + } + + + Map _entries = new HashMap<>(); + Set _classes = new HashSet<>(); + + IncludeExcludeSet _patterns = new IncludeExcludeSet<>(ByPackageOrName.class); + IncludeExcludeSet _locations = new IncludeExcludeSet<>(ByLocation.class); + public ClasspathPattern() { } - /* ------------------------------------------------------------ */ public ClasspathPattern(String[] patterns) { setAll(patterns); } - /* ------------------------------------------------------------ */ public ClasspathPattern(String pattern) { add(pattern); } - /* ------------------------------------------------------------ */ - @Override - public String get(int index) + public boolean include(String name) { - return _entries.get(index)._pattern; - } - - /* ------------------------------------------------------------ */ - @Override - public String set(int index, String element) - { - Entry e = _entries.set(index,new Entry(element)); - return e==null?null:e._pattern; - } - - /* ------------------------------------------------------------ */ - @Override - public void add(int index, String element) - { - _entries.add(index,new Entry(element)); - } - - /* ------------------------------------------------------------ */ - @Deprecated - public void addPattern(String element) - { - add(element); + if (name==null) + return false; + return add(new Entry(name,true)); } - /* ------------------------------------------------------------ */ - @Override - public String remove(int index) + public boolean include(String... name) { - Entry e = _entries.remove(index); - return e==null?null:e._pattern; + boolean added = false; + for (String n:name) + if (n!=null) + added = add(new Entry(n,true)) || added; + return added; } - /* ------------------------------------------------------------ */ - public boolean remove(String pattern) + public boolean exclude(String name) { - for (int i=_entries.size();i-->0;) + if (name==null) + return false; + return add(new Entry(name,false)); + } + + public boolean exclude(String... name) + { + boolean added = false; + for (String n:name) + if (n!=null) + added = add(new Entry(n,false)) || added; + return added; + } + + @Override + public boolean add(String pattern) + { + if (pattern==null) + return false; + return add(new Entry(pattern)); + } + + public boolean add(String... pattern) + { + boolean added = false; + for (String p:pattern) + if (p!=null) + added = add(new Entry(p)) || added; + return added; + } + + protected boolean add(Entry entry) + { + if (_entries.containsKey(entry.getPattern())) + return false; + _entries.put(entry.getPattern(),entry); + + if (entry.isLocation()) { - if (pattern.equals(_entries.get(i)._pattern)) + try { - _entries.remove(i); - return true; + File file = Resource.newResource(entry.getName()).getFile().getAbsoluteFile().getCanonicalFile(); + if (entry.isInclusive()) + _locations.include(file); + else + _locations.exclude(file); + } + catch (Exception e) + { + throw new IllegalArgumentException(e); } } - return false; + else + { + if (entry.isInclusive()) + _patterns.include(entry); + else + _patterns.exclude(entry); + } + return true; + } + + @Override + public boolean remove(Object o) + { + if (!(o instanceof String)) + return false; + String pattern = (String)o; + + Entry entry = _entries.remove(pattern); + if (entry==null) + return false; + + List saved = new ArrayList<>(_entries.values()); + clear(); + for (Entry e:saved) + add(e); + return true; + } + + @Override + public void clear() + { + _entries.clear(); + _patterns.clear(); + _locations.clear(); + } + + @Override + public Iterator iterator() + { + return _entries.keySet().iterator(); } - /* ------------------------------------------------------------ */ @Override public int size() { return _entries.size(); } - /* ------------------------------------------------------------ */ /** * Initialize the matcher by parsing each classpath pattern in an array * @@ -158,7 +483,6 @@ public class ClasspathPattern extends AbstractList addAll(classes); } - /* ------------------------------------------------------------ */ /** * @param classes array of classpath patterns */ @@ -168,30 +492,6 @@ public class ClasspathPattern extends AbstractList addAll(Arrays.asList(classes)); } - /* ------------------------------------------------------------ */ - /** - * @param classes array of classpath patterns - */ - public void prepend(String[] classes) - { - if (classes != null) - { - int i=0; - for (String c : classes) - { - add(i,c); - i++; - } - } - } - - /* ------------------------------------------------------------ */ - public void prependPattern(String pattern) - { - add(0,pattern); - } - - /* ------------------------------------------------------------ */ /** * @return array of classpath patterns */ @@ -200,22 +500,7 @@ public class ClasspathPattern extends AbstractList return toArray(new String[_entries.size()]); } - /* ------------------------------------------------------------ */ - /** - * @return List of classes excluded class exclusions and package patterns - */ - public List getClasses() - { - List list = new ArrayList<>(); - for (Entry e:_entries) - { - if (e._inclusive && !e._package) - list.add(e._name); - } - return list; - } - /* ------------------------------------------------------------ */ /** * Match the class name against the pattern * @@ -224,65 +509,66 @@ public class ClasspathPattern extends AbstractList */ public boolean match(String name) { - name = name.replace('/','.'); - - for (Entry entry : _entries) + return _patterns.test(name); + } + + /** + * Match the class name against the pattern + * + * @param clazz A class to try to match + * @return true if class matches the pattern + */ + public boolean match(Class clazz) + { + try { - if (entry==null) - continue; - if (entry._package) - { - if (name.startsWith(entry._name) || ".".equals(entry._pattern)) - return entry._inclusive; - } - else - { - if (name.equals(entry._name)) - return entry._inclusive; - - if (name.length()>entry._name.length() && '$'==name.charAt(entry._name.length()) && name.startsWith(entry._name)) - return entry._inclusive; - } + Resource resource = TypeUtil.getLoadedFrom(clazz); + Path path = resource.getFile().toPath(); + + Boolean byName = _patterns.isIncludedAndNotExcluded(clazz.getName()); + Boolean byLocation = _locations.isIncludedAndNotExcluded(path); + + // Combine the tri-state match of both IncludeExclude Sets + boolean included = byName==TRUE || byLocation==TRUE + || (byName==null && !_patterns.hasIncludes() && byLocation==null && !_locations.hasIncludes()); + boolean excluded = byName==FALSE || byLocation==FALSE; + return included && !excluded; + } + catch (Exception e) + { + LOG.warn(e); } return false; } - public void addAfter(String afterPattern,String... patterns) + public boolean match(String name, URL url) { - if (patterns!=null && afterPattern!=null) - { - ListIterator iter = listIterator(); - while (iter.hasNext()) - { - String cc=iter.next(); - if (afterPattern.equals(cc)) - { - for (int i=0;i iter = listIterator(); - while (iter.hasNext()) - { - String cc=iter.next(); - if (beforePattern.equals(cc)) - { - iter.previous(); - for (int i=0;i clazz); /* ------------------------------------------------------------ */ /** Is the class a Server Class. @@ -122,7 +121,7 @@ public class WebAppClassLoader extends URLClassLoader * @param clazz The fully qualified name of the class. * @return True if the class is a server class. */ - boolean isServerClass(String clazz); + boolean isServerClass(Class clazz); /* ------------------------------------------------------------ */ /** @@ -135,6 +134,10 @@ public class WebAppClassLoader extends URLClassLoader /* ------------------------------------------------------------ */ String getExtraClasspath(); + + boolean isServerResource(String name, URL parent_url); + + boolean isSystemResource(String name, URL webapp_url); } @@ -142,9 +145,10 @@ public class WebAppClassLoader extends URLClassLoader /** Run an action with access to ServerClasses *

    Run the passed {@link PrivilegedExceptionAction} with the classloader * configured so as to allow server classes to be visible

    + * @param The type returned by the action * @param action The action to run * @return The return from the action - * @throws Exception + * @throws Exception if thrown by the action */ public static T runWithServerClassAccess(PrivilegedExceptionAction action) throws Exception { @@ -361,27 +365,42 @@ public class WebAppClassLoader extends URLClassLoader @Override public Enumeration getResources(String name) throws IOException { - boolean system_class=_context.isSystemClass(name); - boolean server_class=_context.isServerClass(name) && !Boolean.TRUE.equals(__loadServerClasses.get()); + List from_parent = new ArrayList<>(); + List from_webapp = new ArrayList<>(); + + Enumeration urls = _parent.getResources(name); + while (urls!=null && urls.hasMoreElements()) + { + URL url = urls.nextElement(); + if (Boolean.TRUE.equals(__loadServerClasses.get()) || !_context.isServerResource(name,url)) + from_parent.add(url); + } + + urls = this.findResources(name); + while (urls!=null && urls.hasMoreElements()) + { + URL url = urls.nextElement(); + if (!_context.isSystemResource(name,url) || from_parent.isEmpty()) + from_webapp.add(url); + } + + List resources; - List from_parent = toList(server_class?null:_parent.getResources(name)); - List from_webapp = toList((system_class&&!from_parent.isEmpty())?null:this.findResources(name)); - if (_context.isParentLoaderPriority()) { from_parent.addAll(from_webapp); - return Collections.enumeration(from_parent); + resources = from_parent; } - from_webapp.addAll(from_parent); - return Collections.enumeration(from_webapp); - } + else + { + from_webapp.addAll(from_parent); + resources = from_webapp; + } + + if (LOG.isDebugEnabled()) + LOG.debug("getResources {} {}",name,resources); - /* ------------------------------------------------------------ */ - private List toList(Enumeration e) - { - if (e==null) - return new ArrayList(); - return Collections.list(e); + return Collections.enumeration(resources); } /* ------------------------------------------------------------ */ @@ -395,59 +414,60 @@ public class WebAppClassLoader extends URLClassLoader @Override public URL getResource(String name) { - URL url= null; - boolean tried_parent= false; - - //If the resource is a class name with .class suffix, strip it off before comparison - //as the server and system patterns are specified without a .class suffix - String tmp = name; - if (tmp != null && tmp.endsWith(".class")) - tmp = tmp.substring(0, tmp.length()-6); - - boolean system_class=_context.isSystemClass(tmp); - boolean server_class=_context.isServerClass(tmp) && !Boolean.TRUE.equals(__loadServerClasses.get()); - - if (LOG.isDebugEnabled()) - LOG.debug("getResource({}) system={} server={} cl={}",name,system_class,server_class,this); - - if (system_class && server_class) - return null; - - ClassLoader source=null; - - if (_parent!=null &&(_context.isParentLoaderPriority() || system_class ) && !server_class) + URL resource=null; + if (_context.isParentLoaderPriority()) { - tried_parent= true; + URL parent_url=_parent.getResource(name); - if (_parent!=null) + // return if we have a url the webapp is allowed to see + if (parent_url!=null + && (Boolean.TRUE.equals(__loadServerClasses.get()) + || !_context.isServerResource(name,parent_url))) + resource = parent_url; + else { - source=_parent; - url=_parent.getResource(name); + URL webapp_url = this.findResource(name); + + // If found here then OK to use regardless of system or server classes + // If it is a system resource, we've already tried to load from parent, so + // would have returned it. + // If it is a server resource, doesn't matter as we have loaded it from the + // webapp + if (webapp_url!=null) + resource = webapp_url; } } - - if (url == null) + else { - url= this.findResource(name); - source=this; - if (url == null && name.startsWith("/")) - url= this.findResource(name.substring(1)); - } + URL webapp_url = this.findResource(name); - if (url == null && !tried_parent && !server_class ) - { - if (_parent!=null) + if (webapp_url!=null && !_context.isSystemResource(name,webapp_url)) + resource = webapp_url; + else { - tried_parent=true; - source=_parent; - url= _parent.getResource(name); + + // Couldn't find or see a webapp resource, so try a parent + URL parent_url=_parent.getResource(name); + if (parent_url!=null + && (Boolean.TRUE.equals(__loadServerClasses.get()) + || !_context.isServerResource(name,parent_url))) + resource = parent_url; + // We couldn't find a parent resource, so OK to return a webapp one if it exists + // and we just couldn't see it before + else if (webapp_url!=null) + resource = webapp_url; } } + + // Perhaps this failed due to leading / + if (resource==null && name.startsWith("/")) + resource = getResource(name.substring(1)); if (LOG.isDebugEnabled()) - LOG.debug("gotResource({})=={} from={} tried_parent={}",name,url,source,tried_parent); - - return url; + LOG.debug("getResource {} {}",name,resource); + + return resource; + } /* ------------------------------------------------------------ */ @@ -455,77 +475,116 @@ public class WebAppClassLoader extends URLClassLoader protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) - { - Class c= findLoadedClass(name); + { ClassNotFoundException ex= null; - boolean tried_parent= false; - - boolean system_class=_context.isSystemClass(name); - boolean server_class=_context.isServerClass(name) && !Boolean.TRUE.equals(__loadServerClasses.get()); - - if (LOG.isDebugEnabled()) - LOG.debug("loadClass({}) system={} server={} cl={}",name,system_class,server_class,this); + Class parent_class = null; + Class webapp_class = null; - ClassLoader source=null; - - if (system_class && server_class) + // Has this loader loaded the class already? + webapp_class = findLoadedClass(name); + if (webapp_class != null) { - return null; + if (LOG.isDebugEnabled()) + LOG.debug("found webapp loaded {}",webapp_class); + return webapp_class; } - - if (c == null && _parent!=null && (_context.isParentLoaderPriority() || system_class) && !server_class) + + // Should we try the parent loader first? + if (_context.isParentLoaderPriority()) { - tried_parent= true; - source=_parent; + // Try the parent loader try { - c= _parent.loadClass(name); + parent_class = _parent.loadClass(name); + + // If the webapp is allowed to see this class + if (Boolean.TRUE.equals(__loadServerClasses.get()) || !_context.isServerClass(parent_class)) + { + if (LOG.isDebugEnabled()) + LOG.debug("PLP parent loaded {}",parent_class); + return parent_class; + } + } + catch (ClassNotFoundException e) + { + // Save it for later + ex = e; + } + + // Try the webapp loader + try + { + // If found here then OK to use regardless of system or server classes + // If it is a system class, we've already tried to load from parent, so + // would have returned it. + // If it is a server class, doesn't matter as we have loaded it from the + // webapp + webapp_class = this.findClass(name); + resolveClass(webapp_class); if (LOG.isDebugEnabled()) - LOG.debug("loaded " + c); + LOG.debug("PLP webapp loaded {}",webapp_class); + return webapp_class; } catch (ClassNotFoundException e) { - ex= e; + if (ex==null) + ex = e; + else + ex.addSuppressed(e); } - } - - if (c == null) - { - try - { - source=this; - c= this.findClass(name); - } - catch (ClassNotFoundException e) - { - ex= e; - } - } - - if (c == null && _parent!=null && !tried_parent && !server_class ) - { - tried_parent=true; - source=_parent; - c= _parent.loadClass(name); - } - - if (c == null && ex!=null) - { - LOG.debug("!loadedClass({}) from={} tried_parent={}",name,this,tried_parent); + throw ex; } - - if (LOG.isDebugEnabled()) - LOG.debug("loadedClass({})=={} from={} tried_parent={}",name,c,source,tried_parent); - - if (resolve) + else { - resolveClass(c); - if (LOG.isDebugEnabled()) - LOG.debug("resolved({})=={} from={} tried_parent={}",name,c,source,tried_parent); - } + // Not parent loader priority, so... - return c; + // Try the webapp classloader first + // Look in the webapp classloader as a resource, to avoid + // loading a system class. + String path = name.replace('.', '/').concat(".class"); + URL webapp_url = findResource(path); + + if (webapp_url!=null && !_context.isSystemResource(name,webapp_url)) + { + webapp_class = this.foundClass(name,webapp_url); + resolveClass(webapp_class); + if (LOG.isDebugEnabled()) + LOG.debug("WAP webapp loaded {}",webapp_class); + return webapp_class; + } + + // Try the parent loader + try + { + parent_class = _parent.loadClass(name); + + // If the webapp is allowed to see this class + if (Boolean.TRUE.equals(__loadServerClasses.get()) || !_context.isServerClass(parent_class)) + { + if (LOG.isDebugEnabled()) + LOG.debug("WAP parent loaded {}",parent_class); + return parent_class; + } + } + catch (ClassNotFoundException e) + { + ex=e; + } + + // We couldn't find a parent class, so OK to return a webapp one if it exists + // and we just couldn't see it before + if (webapp_url!=null) + { + webapp_class = this.foundClass(name,webapp_url); + resolveClass(webapp_class); + if (LOG.isDebugEnabled()) + LOG.debug("WAP !server webapp loaded {}",webapp_class); + return webapp_class; + } + + throw ex==null?new ClassNotFoundException(name):ex; + } } } @@ -563,69 +622,71 @@ public class WebAppClassLoader extends URLClassLoader { return _transformers.remove(transformer); } - - + /* ------------------------------------------------------------ */ @Override protected Class findClass(final String name) throws ClassNotFoundException { - Class clazz=null; - if (_transformers.isEmpty()) - clazz = super.findClass(name); - else + return super.findClass(name); + + String path = name.replace('.', '/').concat(".class"); + URL url = findResource(path); + if (url==null) + throw new ClassNotFoundException(name); + return foundClass(name,url); + } + + /* ------------------------------------------------------------ */ + protected Class foundClass(final String name, URL url) throws ClassNotFoundException + { + if (_transformers.isEmpty()) + return super.findClass(name); + + InputStream content=null; + try { - String path = name.replace('.', '/').concat(".class"); - URL url = getResource(path); - if (url==null) - throw new ClassNotFoundException(name); + content = url.openStream(); + byte[] bytes = IO.readBytes(content); - InputStream content=null; - try + if (LOG.isDebugEnabled()) + LOG.debug("foundClass({}) url={} cl={}",name,url,this); + + for (ClassFileTransformer transformer : _transformers) { - content = url.openStream(); - byte[] bytes = IO.readBytes(content); + byte[] tmp = transformer.transform(this,name,null,null,bytes); + if (tmp != null) + bytes = tmp; + } - if (LOG.isDebugEnabled()) - LOG.debug("foundClass({}) url={} cl={}",name,url,this); - - for (ClassFileTransformer transformer : _transformers) + return defineClass(name,bytes,0,bytes.length); + } + catch (IOException e) + { + throw new ClassNotFoundException(name,e); + } + catch (IllegalClassFormatException e) + { + throw new ClassNotFoundException(name,e); + } + finally + { + if (content!=null) + { + try { - byte[] tmp = transformer.transform(this,name,null,null,bytes); - if (tmp != null) - bytes = tmp; + content.close(); } - - clazz=defineClass(name,bytes,0,bytes.length); - } - catch (IOException e) - { - throw new ClassNotFoundException(name,e); - } - catch (IllegalClassFormatException e) - { - throw new ClassNotFoundException(name,e); - } - finally - { - if (content!=null) + catch (IOException e) { - try - { - content.close(); - } - catch (IOException e) - { - throw new ClassNotFoundException(name,e); - } + throw new ClassNotFoundException(name,e); } } } - - return clazz; } + - + /* ------------------------------------------------------------ */ @Override public void close() throws IOException { @@ -638,4 +699,5 @@ public class WebAppClassLoader extends URLClassLoader { return "WebAppClassLoader=" + _name+"@"+Long.toHexString(hashCode()); } + } diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java index c29098d49c8..9e7447eff85 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java @@ -24,7 +24,6 @@ import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.security.PermissionCollection; -import java.security.PrivilegedExceptionAction; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -35,7 +34,6 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.Callable; import javax.servlet.ServletContext; import javax.servlet.ServletRegistration.Dynamic; @@ -63,6 +61,7 @@ import org.eclipse.jetty.servlet.ServletHandler; import org.eclipse.jetty.util.AttributesMap; import org.eclipse.jetty.util.Loader; import org.eclipse.jetty.util.MultiException; +import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; @@ -87,7 +86,7 @@ import org.eclipse.jetty.util.resource.ResourceCollection; @ManagedObject("Web Application ContextHandler") public class WebAppContext extends ServletContextHandler implements WebAppClassLoader.Context { - private static final Logger LOG = Log.getLogger(WebAppContext.class); + static final Logger LOG = Log.getLogger(WebAppContext.class); public static final String TEMPDIR = "javax.servlet.context.tempdir"; public static final String BASETEMPDIR = "org.eclipse.jetty.webapp.basetempdir"; @@ -131,12 +130,30 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL "org.eclipse.jetty.servlets.PushSessionCacheFilter" //must be loaded by container classpath } ; + // Find the location of the JVM lib directory + public final static String __jvmlib; + static + { + String lib=null; + try + { + lib=TypeUtil.getLoadedFrom(System.class).getFile().getParentFile().toURI().toString(); + } + catch(Exception e) + { + LOG.warn(e); + lib=null; + } + __jvmlib=lib; + } + // Server classes are classes that are hidden from being // loaded by the web application using system classloader, // so if web application needs to load any of such classes, // it has to include them in its distribution. // TODO This centrally managed list of features that are exposed/hidden needs to be replaced // with a more automatic distributed mechanism + // TODO should be white list rather than black list public final static String[] __dftServerClasses = { "-org.eclipse.jetty.server.session.SessionData", //don't hide SessionData for de/serialization purposes @@ -666,21 +683,25 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL } /* ------------------------------------------------------------ */ - /** Add to the list of Server classes. - * @param classOrPackage A fully qualified class name (eg com.foo.MyClass) - * or a qualified package name ending with '.' (eg com.foo.). If the class - * or package has '-' it is excluded from the server classes and order is thus - * important when added system class patterns. This argument may also be a comma - * separated list of classOrPackage patterns. - * @see #setServerClasses(String[]) - * @see Jetty Documentation: Classloading + /** + * @return The ClasspathPattern used to match Server (hidden) classes */ - public void addServerClass(String classOrPackage) + public ClasspathPattern getServerClasspathPattern() { if (_serverClasses == null) loadServerClasses(); - _serverClasses.add(classOrPackage); + return _serverClasses; + } + + /* ------------------------------------------------------------ */ + @Deprecated + public void addServerClass(String classOrPackageOrLocation) + { + if (_serverClasses == null) + loadServerClasses(); + + _serverClasses.add(classOrPackageOrLocation); } /* ------------------------------------------------------------ */ @@ -693,12 +714,13 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL * @see #setServerClasses(String[]) * @see Jetty Documentation: Classloading */ + @Deprecated public void prependServerClass(String classOrPackage) { if (_serverClasses == null) loadServerClasses(); - _serverClasses.prependPattern(classOrPackage); + _serverClasses.add(classOrPackage); } /* ------------------------------------------------------------ */ @@ -714,17 +736,21 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL return _systemClasses.getPatterns(); } + + /* ------------------------------------------------------------ */ + /** + * @return The ClasspathPattern used to match System (protected) classes + */ + public ClasspathPattern getSystemClasspathPattern() + { + if (_systemClasses == null) + loadSystemClasses(); + + return _systemClasses; + } /* ------------------------------------------------------------ */ - /** Add to the list of System classes. - * @param classOrPackage A fully qualified class name (eg com.foo.MyClass) - * or a qualified package name ending with '.' (eg com.foo.). If the class - * or package has '-' it is excluded from the system classes and order is thus - * important when added system class patterns. This argument may also be a comma - * separated list of classOrPackage patterns. - * @see #setSystemClasses(String[]) - * @see Jetty Documentation: Classloading - */ + @Deprecated public void addSystemClass(String classOrPackage) { if (_systemClasses == null) @@ -744,16 +770,17 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL * @see #setSystemClasses(String[]) * @see Jetty Documentation: Classloading */ + @Deprecated public void prependSystemClass(String classOrPackage) { if (_systemClasses == null) loadSystemClasses(); - _systemClasses.prependPattern(classOrPackage); + _systemClasses.add(classOrPackage); } /* ------------------------------------------------------------ */ - @Override + @Deprecated public boolean isServerClass(String name) { if (_serverClasses == null) @@ -763,7 +790,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL } /* ------------------------------------------------------------ */ - @Override + @Deprecated public boolean isSystemClass(String name) { if (_systemClasses == null) @@ -771,6 +798,58 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL return _systemClasses.match(name); } + + /* ------------------------------------------------------------ */ + @Override + public boolean isServerClass(Class clazz) + { + if (_serverClasses == null) + loadServerClasses(); + + boolean result = _serverClasses.match(clazz); + if (LOG.isDebugEnabled()) + LOG.debug("isServerClass=={} {}",result,clazz); + return result; + } + + /* ------------------------------------------------------------ */ + @Override + public boolean isSystemClass(Class clazz) + { + if (_systemClasses == null) + loadSystemClasses(); + + boolean result = _systemClasses.match(clazz); + if (LOG.isDebugEnabled()) + LOG.debug("isSystemClass=={} {}",result,clazz); + return result; + } + + /* ------------------------------------------------------------ */ + @Override + public boolean isServerResource(String name, URL url) + { + if (_serverClasses == null) + loadServerClasses(); + + boolean result = _serverClasses.match(name,url); + if (LOG.isDebugEnabled()) + LOG.debug("isServerResource=={} {} {}",result,name,url); + return result; + } + + /* ------------------------------------------------------------ */ + @Override + public boolean isSystemResource(String name, URL url) + { + if (_systemClasses == null) + loadSystemClasses(); + + boolean result = _systemClasses.match(name,url); + if (LOG.isDebugEnabled()) + LOG.debug("isSystemResource=={} {} {}",result,name,url); + return result; + } /* ------------------------------------------------------------ */ protected void loadSystemClasses() @@ -784,8 +863,10 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL if (server != null) { Object systemClasses = server.getAttribute(SERVER_SYS_CLASSES); - if (systemClasses != null && systemClasses instanceof String[]) + if (systemClasses instanceof String[]) _systemClasses = new ClasspathPattern((String[])systemClasses); + else if (systemClasses instanceof ClasspathPattern) + _systemClasses = new ClasspathPattern(((ClasspathPattern)systemClasses).getPatterns()); } if (_systemClasses == null) @@ -793,7 +874,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL } /* ------------------------------------------------------------ */ - private void loadServerClasses() + protected void loadServerClasses() { if (_serverClasses != null) { @@ -806,10 +887,10 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL if (server != null) { Object serverClasses = server.getAttribute(SERVER_SRV_CLASSES); - if (serverClasses != null && serverClasses instanceof String[]) - { + if (serverClasses instanceof String[]) _serverClasses = new ClasspathPattern((String[])serverClasses); - } + else if (serverClasses instanceof ClasspathPattern) + _serverClasses = new ClasspathPattern(((ClasspathPattern)serverClasses).getPatterns()); } if (_serverClasses == null) @@ -949,10 +1030,24 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL @Override public void dump(Appendable out, String indent) throws IOException { + List system_classes=null; + if (_systemClasses!=null) + { + system_classes=new ArrayList<>(_systemClasses); + Collections.sort(system_classes); + } + + List server_classes=null; + if (_serverClasses!=null) + { + server_classes=new ArrayList<>(_serverClasses); + Collections.sort(server_classes); + } + dumpBeans(out,indent, Collections.singletonList(new ClassLoaderDump(getClassLoader())), - Collections.singletonList(new DumpableCollection("Systemclasses "+this,_systemClasses)), - Collections.singletonList(new DumpableCollection("Serverclasses "+this,_serverClasses)), + Collections.singletonList(new DumpableCollection("Systemclasses "+this,system_classes)), + Collections.singletonList(new DumpableCollection("Serverclasses "+this,server_classes)), Collections.singletonList(new DumpableCollection("Configurations "+this,_configurations)), Collections.singletonList(new DumpableCollection("Handler attributes "+this,((AttributesMap)getAttributes()).getAttributeEntrySet())), Collections.singletonList(new DumpableCollection("Context attributes "+this,((Context)getServletContext()).getAttributeEntrySet())), @@ -1478,7 +1573,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL { //not one of the standard servlet listeners, check our extended session listener types boolean ok = false; - for (Class l:SessionHandler.SESSION_LISTENER_TYPES) + for (Class l:SessionHandler.SESSION_LISTENER_TYPES) { if (l.isAssignableFrom(listener)) { @@ -1506,11 +1601,11 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL for (int i=resources.length;i-->0;) { if (resources[i].getName().startsWith("jar:file")) - return resources[i].getURL(); + return resources[i].getURI().toURL(); } } - return resource.getURL(); + return resource.getURI().toURL(); } /* ------------------------------------------------------------ */ @@ -1536,7 +1631,6 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL return servletContext; } } - } /* ------------------------------------------------------------ */ @@ -1544,4 +1638,57 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL { return _metadata; } + + /* ------------------------------------------------------------ */ + public static void addServerClasses(Server server,String... pattern ) + { + if (pattern == null || pattern.length == 0) + return; + + // look for a Server attribute with the list of Server classes + // to apply to every web application. If not present, use our defaults. + Object o = server.getAttribute(SERVER_SRV_CLASSES); + if (o instanceof ClasspathPattern) + { + ((ClasspathPattern)o).add(pattern); + return; + } + + String[] server_classes; + if (o instanceof String[]) + server_classes = (String[])o; + else + server_classes = __dftServerClasses; + int l = server_classes.length; + server_classes = Arrays.copyOf(server_classes,l+pattern.length); + System.arraycopy(pattern,0,server_classes,l,pattern.length); + server.setAttribute(SERVER_SRV_CLASSES,server_classes); + } + + /* ------------------------------------------------------------ */ + public static void addSystemClasses(Server server,String... pattern ) + { + if (pattern == null || pattern.length == 0) + return; + + // look for a Server attribute with the list of System classes + // to apply to every web application. If not present, use our defaults. + Object o = server.getAttribute(SERVER_SYS_CLASSES); + if (o instanceof ClasspathPattern) + { + ((ClasspathPattern)o).add(pattern); + return; + } + + String[] system_classes; + if (o instanceof String[]) + system_classes = (String[])o; + else + system_classes = __dftSystemClasses; + int l = system_classes.length; + system_classes = Arrays.copyOf(system_classes,l+pattern.length); + System.arraycopy(pattern,0,system_classes,l,pattern.length); + server.setAttribute(SERVER_SYS_CLASSES,system_classes); + } + } diff --git a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/ClasspathPatternTest.java b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/ClasspathPatternTest.java index 2091ffc0d56..cde8c4edfc9 100644 --- a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/ClasspathPatternTest.java +++ b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/ClasspathPatternTest.java @@ -18,101 +18,214 @@ package org.eclipse.jetty.webapp; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import java.util.Arrays; +import org.eclipse.jetty.toolchain.test.JDK; +import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.TypeUtil; +import org.eclipse.jetty.util.resource.Resource; +import org.hamcrest.Matchers; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import sun.security.provider.Sun; + public class ClasspathPatternTest { - private final ClasspathPattern pattern = new ClasspathPattern(); + private final ClasspathPattern _pattern = new ClasspathPattern(); @Before public void before() { - pattern.clear(); - pattern.add("org.package."); - pattern.add("-org.excluded."); - pattern.add("org.example.FooBar"); - pattern.add("-org.example.Excluded"); - pattern.addAll(Arrays.asList(new String[]{"-org.example.Nested$Minus","org.example.Nested","org.example.Nested$Something"})); + _pattern.clear(); + _pattern.add("org.package."); + _pattern.add("-org.excluded."); + _pattern.add("org.example.FooBar"); + _pattern.add("-org.example.Excluded"); + _pattern.addAll(Arrays.asList(new String[]{ + "-org.example.Nested$Minus", + "org.example.Nested", + "org.example.Nested$Something"})); + + + assertThat(_pattern,containsInAnyOrder( + "org.package.", + "-org.excluded.", + "org.example.FooBar", + "-org.example.Excluded", + "-org.example.Nested$Minus", + "org.example.Nested", + "org.example.Nested$Something" + )); } + @Test public void testClassMatch() { - assertTrue(pattern.match("org.example.FooBar")); - assertTrue(pattern.match("org.example.Nested")); + assertTrue(_pattern.match("org.example.FooBar")); + assertTrue(_pattern.match("org.example.Nested")); - assertFalse(pattern.match("org.example.Unknown")); - assertFalse(pattern.match("org.example.FooBar.Unknown")); + assertFalse(_pattern.match("org.example.Unknown")); + assertFalse(_pattern.match("org.example.FooBar.Unknown")); } @Test public void testPackageMatch() { - assertTrue(pattern.match("org.package.Something")); - assertTrue(pattern.match("org.package.other.Something")); + assertTrue(_pattern.match("org.package.Something")); + assertTrue(_pattern.match("org.package.other.Something")); - assertFalse(pattern.match("org.example.Unknown")); - assertFalse(pattern.match("org.example.FooBar.Unknown")); - assertFalse(pattern.match("org.example.FooBarElse")); + assertFalse(_pattern.match("org.example.Unknown")); + assertFalse(_pattern.match("org.example.FooBar.Unknown")); + assertFalse(_pattern.match("org.example.FooBarElse")); } @Test public void testExplicitNestedMatch() { - assertTrue(pattern.match("org.example.Nested$Something")); - assertFalse(pattern.match("org.example.Nested$Minus")); - assertTrue(pattern.match("org.example.Nested$Other")); + assertTrue(_pattern.match("org.example.Nested$Something")); + assertFalse(_pattern.match("org.example.Nested$Minus")); + assertTrue(_pattern.match("org.example.Nested$Other")); } @Test public void testImplicitNestedMatch() { - assertTrue(pattern.match("org.example.FooBar$Other")); - assertTrue(pattern.match("org.example.Nested$Other")); + assertTrue(_pattern.match("org.example.FooBar$Other")); + assertTrue(_pattern.match("org.example.Nested$Other")); } - @Test - public void testAddBefore() - { - pattern.addBefore("-org.excluded.","org.excluded.ExceptionOne","org.excluded.ExceptionTwo"); - - assertTrue(pattern.match("org.excluded.ExceptionOne")); - assertTrue(pattern.match("org.excluded.ExceptionTwo")); - - assertFalse(pattern.match("org.example.Unknown")); - } - - @Test - public void testAddAfter() - { - pattern.addAfter("org.package.","org.excluded.ExceptionOne","org.excluded.ExceptionTwo"); - - assertTrue(pattern.match("org.excluded.ExceptionOne")); - assertTrue(pattern.match("org.excluded.ExceptionTwo")); - - assertFalse(pattern.match("org.example.Unknown")); - } - @Test public void testDoubledNested() { - assertTrue(pattern.match("org.example.Nested$Something$Else")); + assertTrue(_pattern.match("org.example.Nested$Something$Else")); - assertFalse(pattern.match("org.example.Nested$Minus$Else")); + assertFalse(_pattern.match("org.example.Nested$Minus$Else")); } @Test public void testMatchAll() { - pattern.clear(); - pattern.add("."); - assertTrue(pattern.match("org.example.Anything")); - assertTrue(pattern.match("org.example.Anything$Else")); + _pattern.clear(); + _pattern.add("."); + assertTrue(_pattern.match("org.example.Anything")); + assertTrue(_pattern.match("org.example.Anything$Else")); + } + + /** + * + */ + @SuppressWarnings("restriction") + @Test + public void testiIncludedLocations() throws Exception + { + // jar from JVM classloader + Resource loc_string = TypeUtil.getLoadedFrom(String.class); + // System.err.println(loc_string); + + // another jar from JVM classloader + Resource loc_jsse = TypeUtil.getLoadedFrom(Sun.class); + // System.err.println(loc_jsse); + + // a jar from maven repo jar + Resource loc_junit = TypeUtil.getLoadedFrom(Test.class); + // System.err.println(loc_junit); + + // a jar from another maven repo jar + Resource loc_tool = TypeUtil.getLoadedFrom(JDK.class); + // System.err.println(loc_tool); + + // class file + Resource loc_test = TypeUtil.getLoadedFrom(ClasspathPatternTest.class); + // System.err.println(loc_test); + + ClasspathPattern pattern = new ClasspathPattern(); + pattern.include("something"); + assertThat(pattern.match(String.class),is(false)); + assertThat(pattern.match(Sun.class),is(false)); + assertThat(pattern.match(Test.class),is(false)); + assertThat(pattern.match(JDK.class),is(false)); + assertThat(pattern.match(ClasspathPatternTest.class),is(false)); + + // Add directory for both JVM classes + pattern.include(loc_string.getFile().getParentFile().toURI().toString()); + + // Add jar for individual class and classes directory + pattern.include(loc_junit.toString(),loc_test.toString()); + + assertThat(pattern.match(String.class),is(true)); + assertThat(pattern.match(Sun.class),is(true)); + assertThat(pattern.match(Test.class),is(true)); + assertThat(pattern.match(JDK.class),is(false)); + assertThat(pattern.match(ClasspathPatternTest.class),is(true)); + + // exclude by package name still works + pattern.add("-sun.security.provider.Sun"); + assertThat(pattern.match(String.class),is(true)); + assertThat(pattern.match(Sun.class),is(false)); + assertThat(pattern.match(Test.class),is(true)); + assertThat(pattern.match(JDK.class),is(false)); + assertThat(pattern.match(ClasspathPatternTest.class),is(true)); + + + } + + /** + * + */ + @SuppressWarnings("restriction") + @Test + public void testExcludeLocations() throws Exception + { + // jar from JVM classloader + Resource loc_string = TypeUtil.getLoadedFrom(String.class); + // System.err.println(loc_string); + + // another jar from JVM classloader + Resource loc_jsse = TypeUtil.getLoadedFrom(Sun.class); + // System.err.println(loc_jsse); + + // a jar from maven repo jar + Resource loc_junit = TypeUtil.getLoadedFrom(Test.class); + // System.err.println(loc_junit); + + // a jar from another maven repo jar + Resource loc_tool = TypeUtil.getLoadedFrom(JDK.class); + // System.err.println(loc_tool); + + // class file + Resource loc_test = TypeUtil.getLoadedFrom(ClasspathPatternTest.class); + // System.err.println(loc_test); + + ClasspathPattern pattern = new ClasspathPattern(); + + // include everything + pattern.include("."); + + assertThat(pattern.match(String.class),is(true)); + assertThat(pattern.match(Sun.class),is(true)); + assertThat(pattern.match(Test.class),is(true)); + assertThat(pattern.match(JDK.class),is(true)); + assertThat(pattern.match(ClasspathPatternTest.class),is(true)); + + // Add directory for both JVM classes + pattern.exclude(loc_string.getFile().getParentFile().toURI().toString()); + + // Add jar for individual class and classes directory + pattern.exclude(loc_junit.toString(),loc_test.toString()); + + assertThat(pattern.match(String.class),is(false)); + assertThat(pattern.match(Sun.class),is(false)); + assertThat(pattern.match(Test.class),is(false)); + assertThat(pattern.match(JDK.class),is(true)); + assertThat(pattern.match(ClasspathPatternTest.class),is(false)); } } diff --git a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppClassLoaderTest.java b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppClassLoaderTest.java index 373c7464b4f..93e991f054c 100644 --- a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppClassLoaderTest.java +++ b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppClassLoaderTest.java @@ -56,8 +56,6 @@ public class WebAppClassLoaderTest this.testWebappDir = MavenTestingUtils.getProjectDirPath("src/test/webapp"); Resource webapp = new PathResource(testWebappDir); - System.err.printf("testWebappDir = %s%n", testWebappDir); - _context = new WebAppContext(); _context.setBaseResource(webapp); _context.setContextPath("/test"); @@ -66,6 +64,9 @@ public class WebAppClassLoaderTest _loader.addJars(webapp.addPath("WEB-INF/lib")); _loader.addClassPath(webapp.addPath("WEB-INF/classes")); _loader.setName("test"); + + _context.loadSystemClasses(); + _context.loadServerClasses(); } public void assertCanLoadClass(String clazz) throws ClassNotFoundException @@ -250,7 +251,7 @@ public class WebAppClassLoaderTest URL targetTestClasses = this.getClass().getClassLoader().getResource("org/acme/resource.txt"); _context.setParentLoaderPriority(false); - dump(_context); + resources =Collections.list(_loader.getResources("org/acme/resource.txt")); expected.clear(); @@ -260,12 +261,6 @@ public class WebAppClassLoaderTest assertThat("Resources Found (Parent Loader Priority == false)",resources,ordered(expected)); -// dump(resources); -// assertEquals(3,resources.size()); -// assertEquals(0,resources.get(0).toString().indexOf("jar:file:")); -// assertEquals(-1,resources.get(1).toString().indexOf("test-classes")); -// assertEquals(0,resources.get(2).toString().indexOf("file:")); - _context.setParentLoaderPriority(true); // dump(_context); resources =Collections.list(_loader.getResources("org/acme/resource.txt")); @@ -320,49 +315,6 @@ public class WebAppClassLoaderTest assertThat("Resources Found (Parent Loader Priority == true) (with systemClasses filtering)",resources,ordered(expected)); -// dump(resources); -// assertEquals(1,resources.size()); -// assertEquals(0,resources.get(0).toString().indexOf("file:")); } - private void dump(WebAppContext wac) - { - System.err.println("--Dump WebAppContext - " + wac); - System.err.printf(" context.getClass().getClassLoader() = %s%n",wac.getClass().getClassLoader()); - dumpClassLoaderHierarchy(" ",wac.getClass().getClassLoader()); - System.err.printf(" context.getClassLoader() = %s%n",wac.getClassLoader()); - dumpClassLoaderHierarchy(" ",wac.getClassLoader()); - } - - private void dumpClassLoaderHierarchy(String indent, ClassLoader classLoader) - { - if (classLoader != null) - { - if(classLoader instanceof URLClassLoader) - { - URLClassLoader urlCL = (URLClassLoader)classLoader; - URL urls[] = urlCL.getURLs(); - for (URL url : urls) - { - System.err.printf("%s url[] = %s%n",indent,url); - } - } - - ClassLoader parent = classLoader.getParent(); - if (parent != null) - { - System.err.printf("%s .parent = %s%n",indent,parent); - dumpClassLoaderHierarchy(indent + " ",parent); - } - } - } - - private void dump(List resources) - { - System.err.println("--Dump--"); - for(URL url: resources) - { - System.err.printf(" \"%s\"%n",url); - } - } } diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/ExtensionStack.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/ExtensionStack.java index 2cde3a5ab35..e25da23f0d0 100644 --- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/ExtensionStack.java +++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/ExtensionStack.java @@ -19,12 +19,12 @@ package org.eclipse.jetty.websocket.common.extensions; import java.io.IOException; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; import java.util.Queue; -import org.eclipse.jetty.util.ConcurrentArrayQueue; import org.eclipse.jetty.util.IteratingCallback; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; @@ -52,7 +52,7 @@ public class ExtensionStack extends ContainerLifeCycle implements IncomingFrames { private static final Logger LOG = Log.getLogger(ExtensionStack.class); - private final Queue entries = new ConcurrentArrayQueue<>(); + private final Queue entries = new ArrayDeque<>(); private final IteratingCallback flusher = new Flusher(); private final ExtensionFactory factory; private List extensions; @@ -292,7 +292,7 @@ public class ExtensionStack extends ContainerLifeCycle implements IncomingFrames FrameEntry entry = new FrameEntry(frame,callback,batchMode); if (LOG.isDebugEnabled()) LOG.debug("Queuing {}",entry); - entries.offer(entry); + offerEntry(entry); flusher.iterate(); } @@ -317,12 +317,36 @@ public class ExtensionStack extends ContainerLifeCycle implements IncomingFrames } } + private void offerEntry(FrameEntry entry) + { + synchronized (this) + { + entries.offer(entry); + } + } + + private FrameEntry pollEntry() + { + synchronized (this) + { + return entries.poll(); + } + } + + private int getQueueSize() + { + synchronized (this) + { + return entries.size(); + } + } + @Override public String toString() { StringBuilder s = new StringBuilder(); s.append("ExtensionStack["); - s.append("queueSize=").append(entries.size()); + s.append("queueSize=").append(getQueueSize()); s.append(",extensions="); if (extensions == null) { @@ -383,7 +407,7 @@ public class ExtensionStack extends ContainerLifeCycle implements IncomingFrames @Override protected Action process() throws Exception { - current = entries.poll(); + current = pollEntry(); if (current == null) { if (LOG.isDebugEnabled()) diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/compress/CompressExtension.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/compress/CompressExtension.java index 517f7142038..12c80dd2c72 100644 --- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/compress/CompressExtension.java +++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/compress/CompressExtension.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.websocket.common.extensions.compress; import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; +import java.util.ArrayDeque; import java.util.Queue; import java.util.concurrent.atomic.AtomicInteger; import java.util.zip.DataFormatException; @@ -28,7 +29,6 @@ import java.util.zip.Inflater; import java.util.zip.ZipException; import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.ConcurrentArrayQueue; import org.eclipse.jetty.util.IteratingCallback; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -72,7 +72,7 @@ public abstract class CompressExtension extends AbstractExtension private final static boolean NOWRAP = true; - private final Queue entries = new ConcurrentArrayQueue<>(); + private final Queue entries = new ArrayDeque<>(); private final IteratingCallback flusher = new Flusher(); private Deflater deflaterImpl; private Inflater inflaterImpl; @@ -171,7 +171,7 @@ public abstract class CompressExtension extends AbstractExtension return; } - int read = 0; + int read; while ((read = inflater.inflate(output)) >= 0) { if (read == 0) @@ -214,10 +214,26 @@ public abstract class CompressExtension extends AbstractExtension FrameEntry entry = new FrameEntry(frame,callback,batchMode); if (LOG.isDebugEnabled()) LOG.debug("Queuing {}",entry); - entries.offer(entry); + offerEntry(entry); flusher.iterate(); } + private void offerEntry(FrameEntry entry) + { + synchronized (this) + { + entries.offer(entry); + } + } + + private FrameEntry pollEntry() + { + synchronized (this) + { + return entries.poll(); + } + } + protected void notifyCallbackSuccess(WriteCallback callback) { try @@ -258,7 +274,7 @@ public abstract class CompressExtension extends AbstractExtension } byte input[]; - int inputOffset = 0; + int inputOffset; int len; if (buf.hasArray()) @@ -298,7 +314,7 @@ public abstract class CompressExtension extends AbstractExtension } byte input[]; - int inputOffset = 0; + int inputOffset; int len; if (buf.hasArray()) @@ -408,7 +424,7 @@ public abstract class CompressExtension extends AbstractExtension { if (finished) { - current = entries.poll(); + current = pollEntry(); LOG.debug("Processing {}",current); if (current == null) return Action.IDLE; @@ -545,7 +561,7 @@ public abstract class CompressExtension extends AbstractExtension { // Fail all the frames in the queue. FrameEntry entry; - while ((entry = entries.poll()) != null) + while ((entry = pollEntry()) != null) notifyCallbackFailure(entry.callback,x); } diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/fragment/FragmentExtension.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/fragment/FragmentExtension.java index 1d29c13d9de..292493c715c 100644 --- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/fragment/FragmentExtension.java +++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/fragment/FragmentExtension.java @@ -20,9 +20,9 @@ package org.eclipse.jetty.websocket.common.extensions.fragment; import java.nio.ByteBuffer; +import java.util.ArrayDeque; import java.util.Queue; -import org.eclipse.jetty.util.ConcurrentArrayQueue; import org.eclipse.jetty.util.IteratingCallback; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -41,7 +41,7 @@ public class FragmentExtension extends AbstractExtension { private static final Logger LOG = Log.getLogger(FragmentExtension.class); - private final Queue entries = new ConcurrentArrayQueue<>(); + private final Queue entries = new ArrayDeque<>(); private final IteratingCallback flusher = new Flusher(); private int maxLength; @@ -71,7 +71,7 @@ public class FragmentExtension extends AbstractExtension FrameEntry entry = new FrameEntry(frame, callback, batchMode); if (LOG.isDebugEnabled()) LOG.debug("Queuing {}", entry); - entries.offer(entry); + offerEntry(entry); flusher.iterate(); } @@ -82,6 +82,22 @@ public class FragmentExtension extends AbstractExtension maxLength = config.getParameter("maxLength", -1); } + private void offerEntry(FrameEntry entry) + { + synchronized (this) + { + entries.offer(entry); + } + } + + private FrameEntry pollEntry() + { + synchronized (this) + { + return entries.poll(); + } + } + private static class FrameEntry { private final Frame frame; @@ -112,7 +128,7 @@ public class FragmentExtension extends AbstractExtension { if (finished) { - current = entries.poll(); + current = pollEntry(); LOG.debug("Processing {}", current); if (current == null) return Action.IDLE; diff --git a/pom.xml b/pom.xml index 4551370784a..84a80da05a9 100644 --- a/pom.xml +++ b/pom.xml @@ -39,7 +39,7 @@ scm:git:https://github.com/eclipse/jetty.project.git scm:git:git@github.com:eclipse/jetty.project.git https://github.com/eclipse/jetty.project - HEAD + jetty-9.3.13.M0 @@ -317,7 +317,7 @@ org.eclipse.jetty.toolchain jetty-version-maven-plugin - 2.1 + 2.2 org.apache.maven.plugins diff --git a/tests/test-http-client-transport/pom.xml b/tests/test-http-client-transport/pom.xml index ca0ea2a2225..5f79cb73e66 100644 --- a/tests/test-http-client-transport/pom.xml +++ b/tests/test-http-client-transport/pom.xml @@ -75,7 +75,7 @@ org.eclipse.jetty - jetty-server + jetty-servlet ${project.version} test diff --git a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AbstractTest.java b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AbstractTest.java index 32b52e3c44b..1fb649238df 100644 --- a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AbstractTest.java +++ b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AbstractTest.java @@ -21,6 +21,8 @@ package org.eclipse.jetty.http.client; import java.util.ArrayList; import java.util.List; +import javax.servlet.http.HttpServlet; + import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpClientTransport; @@ -40,11 +42,14 @@ import org.eclipse.jetty.server.SecureRequestCustomizer; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.SslConnectionFactory; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.toolchain.test.TestTracker; import org.eclipse.jetty.util.SocketAddressResolver; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.junit.After; +import org.junit.Assume; import org.junit.Rule; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -61,14 +66,18 @@ public abstract class AbstractTest @Rule public final TestTracker tracker = new TestTracker(); + protected final HttpConfiguration httpConfig = new HttpConfiguration(); protected final Transport transport; protected SslContextFactory sslContextFactory; protected Server server; protected ServerConnector connector; + protected ServletContextHandler context; + protected String servletPath = "/servlet"; protected HttpClient client; public AbstractTest(Transport transport) { + Assume.assumeNotNull(transport); this.transport = transport; } @@ -78,6 +87,22 @@ public abstract class AbstractTest startClient(); } + public void start(HttpServlet servlet) throws Exception + { + startServer(servlet); + startClient(); + } + + protected void startServer(HttpServlet servlet) throws Exception + { + context = new ServletContextHandler(); + context.setContextPath("/"); + ServletHolder holder = new ServletHolder(servlet); + holder.setAsyncSupported(true); + context.addServlet(holder, servletPath); + startServer(context); + } + protected void startServer(Handler handler) throws Exception { sslContextFactory = new SslContextFactory(); @@ -101,7 +126,7 @@ public abstract class AbstractTest return new ServerConnector(server, provideServerConnectionFactory(transport)); } - private void startClient() throws Exception + protected void startClient() throws Exception { QueuedThreadPool clientThreads = new QueuedThreadPool(); clientThreads.setName("client"); @@ -118,14 +143,13 @@ public abstract class AbstractTest { case HTTP: { - result.add(new HttpConnectionFactory(new HttpConfiguration())); + result.add(new HttpConnectionFactory(httpConfig)); break; } case HTTPS: { - HttpConfiguration configuration = new HttpConfiguration(); - configuration.addCustomizer(new SecureRequestCustomizer()); - HttpConnectionFactory http = new HttpConnectionFactory(configuration); + httpConfig.addCustomizer(new SecureRequestCustomizer()); + HttpConnectionFactory http = new HttpConnectionFactory(httpConfig); SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory, http.getProtocol()); result.add(ssl); result.add(http); @@ -133,14 +157,13 @@ public abstract class AbstractTest } case H2C: { - result.add(new HTTP2CServerConnectionFactory(new HttpConfiguration())); + result.add(new HTTP2CServerConnectionFactory(httpConfig)); break; } case H2: { - HttpConfiguration configuration = new HttpConfiguration(); - configuration.addCustomizer(new SecureRequestCustomizer()); - HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(configuration); + httpConfig.addCustomizer(new SecureRequestCustomizer()); + HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(httpConfig); ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory("h2"); SslConnectionFactory ssl = new SslConnectionFactory(sslContextFactory, alpn.getProtocol()); result.add(ssl); @@ -150,7 +173,7 @@ public abstract class AbstractTest } case FCGI: { - result.add(new ServerFCGIConnectionFactory(new HttpConfiguration())); + result.add(new ServerFCGIConnectionFactory(httpConfig)); break; } default: @@ -227,9 +250,19 @@ public abstract class AbstractTest @After public void stop() throws Exception + { + stopClient(); + stopServer(); + } + + protected void stopClient() throws Exception { if (client != null) client.stop(); + } + + protected void stopServer() throws Exception + { if (server != null) server.stop(); } diff --git a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AsyncIOServletTest.java b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AsyncIOServletTest.java new file mode 100644 index 00000000000..1110eac8f64 --- /dev/null +++ b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AsyncIOServletTest.java @@ -0,0 +1,1217 @@ +// +// ======================================================================== +// Copyright (c) 1995-2016 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.http.client; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InterruptedIOException; +import java.io.UncheckedIOException; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.servlet.AsyncContext; +import javax.servlet.DispatcherType; +import javax.servlet.ReadListener; +import javax.servlet.ServletException; +import javax.servlet.ServletInputStream; +import javax.servlet.ServletOutputStream; +import javax.servlet.WriteListener; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.client.api.Destination; +import org.eclipse.jetty.client.api.Response; +import org.eclipse.jetty.client.api.Result; +import org.eclipse.jetty.client.http.HttpConnectionOverHTTP; +import org.eclipse.jetty.client.util.BufferingResponseListener; +import org.eclipse.jetty.client.util.DeferredContentProvider; +import org.eclipse.jetty.client.util.StringContentProvider; +import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.http2.HTTP2Session; +import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.client.http.HttpConnectionOverHTTP2; +import org.eclipse.jetty.io.Connection; +import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.HttpChannel; +import org.eclipse.jetty.server.HttpInput; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.HttpInput.Content; +import org.eclipse.jetty.server.handler.ContextHandler; +import org.eclipse.jetty.server.handler.ContextHandler.Context; +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.FuturePromise; +import org.eclipse.jetty.util.log.StacklessLogging; +import org.hamcrest.Matchers; +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Test; + +import static java.nio.ByteBuffer.wrap; +import static org.eclipse.jetty.util.BufferUtil.toArray; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +public class AsyncIOServletTest extends AbstractTest +{ + private static final ThreadLocal scope = new ThreadLocal<>(); + + public AsyncIOServletTest(Transport transport) + { + super(transport == Transport.FCGI ? null : transport); + } + + @Override + protected void startServer(Handler handler) throws Exception + { + if (handler == context) + { + // Add this listener before the context is started, so it's durable. + context.addEventListener(new ContextHandler.ContextScopeListener() + { + @Override + public void enterScope(Context context, Request request, Object reason) + { + checkScope(); + scope.set(new RuntimeException()); + } + + @Override + public void exitScope(Context context, Request request) + { + assertScope(); + scope.set(null); + } + }); + } + super.startServer(handler); + } + + private void assertScope() + { + Assert.assertNotNull("Not in scope", scope.get()); + } + + private void checkScope() + { + RuntimeException callScope = scope.get(); + if (callScope != null) + throw callScope; + } + + protected void stopServer() throws Exception + { + super.stopServer(); + checkScope(); + scope.set(null); + } + + private void sleep(long ms) throws IOException + { + try + { + Thread.sleep(ms); + } + catch (InterruptedException e) + { + throw new InterruptedIOException(); + } + } + + @Test + public void testAsyncReadThrowsException() throws Exception + { + testAsyncReadThrows(new NullPointerException("explicitly_thrown_by_test")); + } + + @Test + public void testAsyncReadThrowsError() throws Exception + { + testAsyncReadThrows(new Error("explicitly_thrown_by_test")); + } + + private void testAsyncReadThrows(Throwable throwable) throws Exception + { + CountDownLatch latch = new CountDownLatch(1); + start(new HttpServlet() + { + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + assertScope(); + AsyncContext asyncContext = request.startAsync(request, response); + request.getInputStream().setReadListener(new ReadListener() + { + @Override + public void onDataAvailable() throws IOException + { + assertScope(); + if (throwable instanceof RuntimeException) + throw (RuntimeException)throwable; + if (throwable instanceof Error) + throw (Error)throwable; + throw new IOException(throwable); + } + + @Override + public void onAllDataRead() throws IOException + { + assertScope(); + } + + @Override + public void onError(Throwable t) + { + assertScope(); + Assert.assertThat("onError type", t, instanceOf(throwable.getClass())); + Assert.assertThat("onError message", t.getMessage(), is(throwable.getMessage())); + latch.countDown(); + response.setStatus(500); + asyncContext.complete(); + } + }); + } + }); + + ContentResponse response = client.newRequest(newURI()) + .method(HttpMethod.POST) + .path(servletPath) + .content(new StringContentProvider("0123456789")) + .timeout(5, TimeUnit.SECONDS) + .send(); + + assertTrue(latch.await(5, TimeUnit.SECONDS)); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR_500, response.getStatus()); + } + + @Test + public void testAsyncReadIdleTimeout() throws Exception + { + int status = 567; + start(new HttpServlet() + { + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + assertScope(); + AsyncContext asyncContext = request.startAsync(request, response); + asyncContext.setTimeout(0); + ServletInputStream inputStream = request.getInputStream(); + inputStream.setReadListener(new ReadListener() + { + @Override + public void onDataAvailable() throws IOException + { + assertScope(); + while (inputStream.isReady() && !inputStream.isFinished()) + inputStream.read(); + } + + @Override + public void onAllDataRead() throws IOException + { + assertScope(); + } + + @Override + public void onError(Throwable t) + { + assertScope(); + response.setStatus(status); + // Do not put Connection: close header here, the test + // verifies that the server closes no matter what. + asyncContext.complete(); + } + }); + } + }); + connector.setIdleTimeout(1000); + CountDownLatch closeLatch = new CountDownLatch(1); + connector.addBean(new Connection.Listener() + { + @Override + public void onOpened(Connection connection) + { + } + + @Override + public void onClosed(Connection connection) + { + closeLatch.countDown(); + } + }); + + String data = "0123456789"; + DeferredContentProvider content = new DeferredContentProvider(); + content.offer(ByteBuffer.wrap(data.getBytes(StandardCharsets.UTF_8))); + CountDownLatch responseLatch = new CountDownLatch(1); + CountDownLatch clientLatch = new CountDownLatch(1); + client.newRequest(newURI()) + .method(HttpMethod.POST) + .path(servletPath) + .content(content) + .onResponseSuccess(r -> responseLatch.countDown()) + .timeout(5, TimeUnit.SECONDS) + .send(result -> + { + assertEquals(status, result.getResponse().getStatus()); + clientLatch.countDown(); + }); + + assertTrue(closeLatch.await(5, TimeUnit.SECONDS)); + assertTrue(responseLatch.await(5, TimeUnit.SECONDS)); + content.close(); + assertTrue(clientLatch.await(5, TimeUnit.SECONDS)); + } + + @Test + public void testOnErrorThrows() throws Exception + { + AtomicInteger errors = new AtomicInteger(); + start(new HttpServlet() + { + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + assertScope(); + if (request.getDispatcherType() == DispatcherType.ERROR) + { + response.flushBuffer(); + return; + } + + request.startAsync(request, response); + request.getInputStream().setReadListener(new ReadListener() + { + @Override + public void onDataAvailable() throws IOException + { + assertScope(); + throw new NullPointerException("explicitly_thrown_by_test_1"); + } + + @Override + public void onAllDataRead() throws IOException + { + assertScope(); + } + + @Override + public void onError(Throwable t) + { + assertScope(); + errors.incrementAndGet(); + throw new NullPointerException("explicitly_thrown_by_test_2") + {{ + this.initCause(t); + }}; + } + }); + } + }); + + try (StacklessLogging stackless = new StacklessLogging(HttpChannel.class)) + { + ContentResponse response = client.newRequest(newURI()) + .path(servletPath) + .content(new StringContentProvider("0123456789")) + .timeout(5, TimeUnit.SECONDS) + .send(); + + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR_500, response.getStatus()); + Assert.assertEquals(1, errors.get()); + } + } + + @Test + public void testAsyncWriteThrowsException() throws Exception + { + testAsyncWriteThrows(new NullPointerException("explicitly_thrown_by_test")); + } + + @Test + public void testAsyncWriteThrowsError() throws Exception + { + testAsyncWriteThrows(new Error("explicitly_thrown_by_test")); + } + + private void testAsyncWriteThrows(Throwable throwable) throws Exception + { + CountDownLatch latch = new CountDownLatch(1); + start(new HttpServlet() + { + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + assertScope(); + AsyncContext asyncContext = request.startAsync(request, response); + response.getOutputStream().setWriteListener(new WriteListener() + { + @Override + public void onWritePossible() throws IOException + { + assertScope(); + if (throwable instanceof RuntimeException) + throw (RuntimeException)throwable; + if (throwable instanceof Error) + throw (Error)throwable; + throw new IOException(throwable); + } + + @Override + public void onError(Throwable t) + { + assertScope(); + latch.countDown(); + response.setStatus(500); + asyncContext.complete(); + Assert.assertSame(throwable, t); + } + }); + } + }); + + ContentResponse response = client.newRequest(newURI()) + .path(servletPath) + .timeout(5, TimeUnit.SECONDS) + .send(); + + assertTrue(latch.await(5, TimeUnit.SECONDS)); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR_500, response.getStatus()); + } + + @Test + public void testAsyncWriteClosed() throws Exception + { + String text = "Now is the winter of our discontent. How Now Brown Cow. The quick brown fox jumped over the lazy dog.\n"; + for (int i = 0; i < 10; i++) + text = text + text; + byte[] data = text.getBytes(StandardCharsets.UTF_8); + + CountDownLatch errorLatch = new CountDownLatch(1); + start(new HttpServlet() + { + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + assertScope(); + response.flushBuffer(); + + AsyncContext async = request.startAsync(); + ServletOutputStream out = response.getOutputStream(); + out.setWriteListener(new WriteListener() + { + @Override + public void onWritePossible() throws IOException + { + assertScope(); + + // Wait for the failure to arrive to + // the server while we are about to write. + sleep(1000); + + out.write(data); + } + + @Override + public void onError(Throwable t) + { + assertScope(); + async.complete(); + errorLatch.countDown(); + } + }); + } + }); + + CountDownLatch clientLatch = new CountDownLatch(1); + client.newRequest(newURI()) + .path(servletPath) + .onResponseHeaders(response -> + { + if (response.getStatus() == HttpStatus.OK_200) + response.abort(new IOException("explicitly_closed_by_test")); + }) + .send(result -> + { + if (result.isFailed()) + clientLatch.countDown(); + }); + + assertTrue(errorLatch.await(5, TimeUnit.SECONDS)); + assertTrue(clientLatch.await(5, TimeUnit.SECONDS)); + } + + @Test + public void testIsReadyAtEOF() throws Exception + { + String text = "TEST\n"; + byte[] data = text.getBytes(StandardCharsets.UTF_8); + + start(new HttpServlet() + { + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + assertScope(); + response.flushBuffer(); + + AsyncContext async = request.startAsync(); + ServletInputStream input = request.getInputStream(); + ServletOutputStream output = response.getOutputStream(); + + input.setReadListener(new ReadListener() + { + transient int _i = 0; + transient boolean _minusOne = false; + transient boolean _finished = false; + + @Override + public void onDataAvailable() throws IOException + { + assertScope(); + while (input.isReady() && !input.isFinished()) + { + int b = input.read(); + if (b == -1) + _minusOne = true; + else if (data[_i++] != b) + throw new IllegalStateException(); + } + + if (input.isFinished()) + _finished = true; + } + + @Override + public void onAllDataRead() throws IOException + { + assertScope(); + output.write(String.format("i=%d eof=%b finished=%b", _i, _minusOne, _finished).getBytes(StandardCharsets.UTF_8)); + async.complete(); + } + + @Override + public void onError(Throwable t) + { + assertScope(); + t.printStackTrace(); + async.complete(); + } + }); + } + }); + + ContentResponse response = client.newRequest(newURI()) + .method(HttpMethod.POST) + .path(servletPath) + .header(HttpHeader.CONNECTION, "close") + .content(new StringContentProvider(text)) + .timeout(5, TimeUnit.SECONDS) + .send(); + + String responseContent = response.getContentAsString(); + assertThat(responseContent, containsString("i=" + data.length + " eof=true finished=true")); + } + + @Test + public void testOnAllDataRead() throws Exception + { + String success = "SUCCESS"; + start(new HttpServlet() + { + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + assertScope(); + response.flushBuffer(); + + AsyncContext async = request.startAsync(); + async.setTimeout(5000); + ServletInputStream in = request.getInputStream(); + ServletOutputStream out = response.getOutputStream(); + + in.setReadListener(new ReadListener() + { + @Override + public void onDataAvailable() throws IOException + { + assertScope(); + try + { + sleep(1000); + if (!in.isReady()) + throw new IllegalStateException(); + if (in.read() != 'X') + throw new IllegalStateException(); + if (!in.isReady()) + throw new IllegalStateException(); + if (in.read() != -1) + throw new IllegalStateException(); + } + catch (IOException x) + { + throw new UncheckedIOException(x); + } + } + + @Override + public void onAllDataRead() throws IOException + { + assertScope(); + out.write(success.getBytes(StandardCharsets.UTF_8)); + async.complete(); + } + + @Override + public void onError(Throwable t) + { + assertScope(); + t.printStackTrace(); + async.complete(); + } + }); + } + }); + + byte[] data = "X".getBytes(StandardCharsets.UTF_8); + CountDownLatch clientLatch = new CountDownLatch(1); + DeferredContentProvider content = new DeferredContentProvider() + { + @Override + public long getLength() + { + return data.length; + } + }; + client.newRequest(newURI()) + .method(HttpMethod.POST) + .path(servletPath) + .content(content) + .timeout(5, TimeUnit.SECONDS) + .send(new BufferingResponseListener() + { + @Override + public void onComplete(Result result) + { + if (result.isSucceeded()) + { + Response response = result.getResponse(); + String content = getContentAsString(); + if (response.getStatus() == HttpStatus.OK_200 && success.equals(content)) + clientLatch.countDown(); + } + } + }); + + sleep(100); + content.offer(ByteBuffer.wrap(data)); + content.close(); + + assertTrue(clientLatch.await(5, TimeUnit.SECONDS)); + } + + @Test + public void testOtherThreadOnAllDataRead() throws Exception + { + String success = "SUCCESS"; + start(new HttpServlet() + { + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + assertScope(); + response.flushBuffer(); + + AsyncContext async = request.startAsync(); + async.setTimeout(0); + ServletInputStream input = request.getInputStream(); + ServletOutputStream output = response.getOutputStream(); + + if (request.getDispatcherType() == DispatcherType.ERROR) + throw new IllegalStateException(); + + input.setReadListener(new ReadListener() + { + @Override + public void onDataAvailable() throws IOException + { + assertScope(); + async.start(() -> + { + assertScope(); + try + { + sleep(1000); + if (!input.isReady()) + throw new IllegalStateException(); + if (input.read() != 'X') + throw new IllegalStateException(); + if (!input.isReady()) + throw new IllegalStateException(); + if (input.read() != -1) + throw new IllegalStateException(); + } + catch (IOException x) + { + throw new UncheckedIOException(x); + } + }); + } + + @Override + public void onAllDataRead() throws IOException + { + output.write(success.getBytes(StandardCharsets.UTF_8)); + async.complete(); + } + + @Override + public void onError(Throwable t) + { + assertScope(); + t.printStackTrace(); + async.complete(); + } + }); + } + }); + + byte[] data = "X".getBytes(StandardCharsets.UTF_8); + CountDownLatch clientLatch = new CountDownLatch(1); + DeferredContentProvider content = new DeferredContentProvider(); + client.newRequest(newURI()) + .method(HttpMethod.POST) + .path(servletPath) + .content(content) + .timeout(5, TimeUnit.SECONDS) + .send(new BufferingResponseListener() + { + @Override + public void onComplete(Result result) + { + if (result.isSucceeded()) + { + Response response = result.getResponse(); + String content = getContentAsString(); + if (response.getStatus() == HttpStatus.OK_200 && success.equals(content)) + clientLatch.countDown(); + } + } + }); + + sleep(100); + content.offer(ByteBuffer.wrap(data)); + content.close(); + + assertTrue(clientLatch.await(5, TimeUnit.SECONDS)); + } + + @Test + public void testCompleteBeforeOnAllDataRead() throws Exception + { + String success = "SUCCESS"; + AtomicBoolean allDataRead = new AtomicBoolean(false); + + start(new HttpServlet() + { + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + assertScope(); + response.flushBuffer(); + + AsyncContext async = request.startAsync(); + ServletInputStream input = request.getInputStream(); + ServletOutputStream output = response.getOutputStream(); + + input.setReadListener(new ReadListener() + { + @Override + public void onDataAvailable() throws IOException + { + assertScope(); + while (input.isReady()) + { + int b = input.read(); + if (b < 0) + { + output.write(success.getBytes(StandardCharsets.UTF_8)); + async.complete(); + return; + } + } + } + + @Override + public void onAllDataRead() throws IOException + { + assertScope(); + output.write("FAILURE".getBytes(StandardCharsets.UTF_8)); + allDataRead.set(true); + throw new IllegalStateException(); + } + + @Override + public void onError(Throwable t) + { + assertScope(); + t.printStackTrace(); + } + }); + } + }); + + ContentResponse response = client.newRequest(newURI()) + .method(HttpMethod.POST) + .path(servletPath) + .header(HttpHeader.CONNECTION, "close") + .content(new StringContentProvider("XYZ")) + .timeout(5, TimeUnit.SECONDS) + .send(); + + assertThat(response.getStatus(), Matchers.equalTo(HttpStatus.OK_200)); + assertThat(response.getContentAsString(), Matchers.equalTo(success)); + } + + @Test + public void testEmptyAsyncRead() throws Exception + { + AtomicBoolean oda = new AtomicBoolean(); + CountDownLatch latch = new CountDownLatch(1); + + start(new HttpServlet() + { + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + assertScope(); + AsyncContext asyncContext = request.startAsync(request, response); + response.setStatus(200); + response.getOutputStream().close(); + request.getInputStream().setReadListener(new ReadListener() + { + @Override + public void onDataAvailable() throws IOException + { + assertScope(); + oda.set(true); + } + + @Override + public void onAllDataRead() throws IOException + { + assertScope(); + asyncContext.complete(); + latch.countDown(); + } + + @Override + public void onError(Throwable t) + { + assertScope(); + t.printStackTrace(); + asyncContext.complete(); + } + }); + } + }); + + ContentResponse response = client.newRequest(newURI()) + .path(servletPath) + .header(HttpHeader.CONNECTION, "close") + .timeout(5, TimeUnit.SECONDS) + .send(); + + assertThat(response.getStatus(), Matchers.equalTo(HttpStatus.OK_200)); + assertTrue(latch.await(5, TimeUnit.SECONDS)); + // onDataAvailable must not be called. + Assert.assertFalse(oda.get()); + } + + @Test + public void testWriteFromOnDataAvailable() throws Exception + { + Queue errors = new ConcurrentLinkedQueue<>(); + CountDownLatch writeLatch = new CountDownLatch(1); + start(new HttpServlet() + { + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + AsyncContext asyncContext = request.startAsync(); + request.getInputStream().setReadListener(new ReadListener() + { + @Override + public void onDataAvailable() throws IOException + { + ServletInputStream input = request.getInputStream(); + ServletOutputStream output = response.getOutputStream(); + while (input.isReady()) + { + byte[] buffer = new byte[512]; + int read = input.read(buffer); + if (read < 0) + { + asyncContext.complete(); + break; + } + if (output.isReady()) + output.write(buffer, 0, read); + else + Assert.fail(); + } + } + + @Override + public void onAllDataRead() throws IOException + { + } + + @Override + public void onError(Throwable t) + { + errors.offer(t); + } + }); + response.getOutputStream().setWriteListener(new WriteListener() + { + @Override + public void onWritePossible() throws IOException + { + writeLatch.countDown(); + } + + @Override + public void onError(Throwable t) + { + errors.offer(t); + } + }); + } + }); + + String content = "0123456789ABCDEF"; + DeferredContentProvider contentProvider = new DeferredContentProvider(); + contentProvider.offer(ByteBuffer.wrap(content.getBytes(StandardCharsets.UTF_8))); + CountDownLatch clientLatch = new CountDownLatch(1); + client.newRequest(newURI()) + .method(HttpMethod.POST) + .path(servletPath) + .content(contentProvider) + .send(new BufferingResponseListener() + { + @Override + public void onComplete(Result result) + { + if (result.isSucceeded()) + { + Response response = result.getResponse(); + assertThat(response.getStatus(), Matchers.equalTo(HttpStatus.OK_200)); + assertThat(getContentAsString(), Matchers.equalTo(content)); + assertThat(errors, Matchers.hasSize(0)); + clientLatch.countDown(); + } + } + }); + + assertTrue(writeLatch.await(5, TimeUnit.SECONDS)); + + contentProvider.close(); + + assertTrue(clientLatch.await(5, TimeUnit.SECONDS)); + } + + @Test + public void testAsyncReadEarlyEOF() throws Exception + { + // SSLEngine receives the close alert from the client, and when + // the server passes the response to encrypt and write, SSLEngine + // only generates the close alert back, without encrypting the + // response, so we need to skip the transports over TLS. + Assume.assumeThat(transport, Matchers.not(Matchers.isOneOf(Transport.HTTPS, Transport.H2))); + + String content = "jetty"; + int responseCode = HttpStatus.NO_CONTENT_204; + CountDownLatch readLatch = new CountDownLatch(content.length()); + CountDownLatch errorLatch = new CountDownLatch(1); + start(new HttpServlet() + { + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + AsyncContext asyncContext = request.startAsync(); + ServletInputStream input = request.getInputStream(); + input.setReadListener(new ReadListener() + { + @Override + public void onDataAvailable() throws IOException + { + while (input.isReady() && !input.isFinished()) + { + int read = input.read(); + System.err.printf("%x%n", read); + readLatch.countDown(); + } + } + + @Override + public void onAllDataRead() throws IOException + { + } + + @Override + public void onError(Throwable x) + { + response.setStatus(responseCode); + asyncContext.complete(); + errorLatch.countDown(); + } + }); + } + }); + + CountDownLatch responseLatch = new CountDownLatch(1); + DeferredContentProvider contentProvider = new DeferredContentProvider(); + contentProvider.offer(ByteBuffer.wrap(content.getBytes(StandardCharsets.UTF_8))); + org.eclipse.jetty.client.api.Request request = client.newRequest(newURI()) + .method(HttpMethod.POST) + .path(servletPath) + .content(contentProvider) + .onResponseSuccess(response -> responseLatch.countDown()); + + Destination destination = client.getDestination(getScheme(), "localhost", connector.getLocalPort()); + FuturePromise promise = new FuturePromise<>(); + destination.newConnection(promise); + org.eclipse.jetty.client.api.Connection connection = promise.get(5, TimeUnit.SECONDS); + CountDownLatch clientLatch = new CountDownLatch(1); + connection.send(request, result -> + { + assertThat(result.getResponse().getStatus(), Matchers.equalTo(responseCode)); + clientLatch.countDown(); + }); + + assertTrue(readLatch.await(5, TimeUnit.SECONDS)); + + switch (transport) + { + case HTTP: + case HTTPS: + ((HttpConnectionOverHTTP)connection).getEndPoint().shutdownOutput(); + break; + case H2C: + case H2: + Session session = ((HttpConnectionOverHTTP2)connection).getSession(); + ((HTTP2Session)session).getEndPoint().shutdownOutput(); + break; + default: + Assert.fail(); + } + + // Wait for the response to arrive before finishing the request. + assertTrue(responseLatch.await(5, TimeUnit.SECONDS)); + contentProvider.close(); + + assertTrue(errorLatch.await(5, TimeUnit.SECONDS)); + assertTrue(clientLatch.await(5, TimeUnit.SECONDS)); + } + + + @Test + public void testAsyncIntercepted() throws Exception + { + start(new HttpServlet() + { + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + System.err.println("Service "+request); + + final HttpInput httpInput = ((Request)request).getHttpInput(); + httpInput.addInterceptor(new HttpInput.Interceptor() + { + int state = 0; + Content saved; + + @Override + public Content readFrom(Content content) + { + // System.err.printf("readFrom s=%d saved=%b %s%n",state,saved!=null,content); + switch(state) + { + case 0: + // null transform + if (content.isEmpty()) + state++; + return null; + + case 1: + { + // copy transform + if (content.isEmpty()) + { + state++; + return content; + } + ByteBuffer copy = wrap(toArray(content.getByteBuffer())); + content.skip(copy.remaining()); + return new Content(copy); + } + + case 2: + // byte by byte + if (content.isEmpty()) + { + state++; + return content; + } + byte[] b = new byte[1]; + int l = content.get(b,0,1); + return new Content(wrap(b,0,l)); + + case 3: + { + // double vision + if (content.isEmpty()) + { + if (saved==null) + { + state++; + return content; + } + Content copy = saved; + saved=null; + return copy; + } + + byte[] data = toArray(content.getByteBuffer()); + content.skip(data.length); + saved = new Content(wrap(data)); + return new Content(wrap(data)); + } + + default: + return null; + } + } + }); + + AsyncContext asyncContext = request.startAsync(); + ServletInputStream input = request.getInputStream(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + + input.setReadListener(new ReadListener() + { + @Override + public void onDataAvailable() throws IOException + { + while (input.isReady() && !input.isFinished()) + { + int b = input.read(); + if (b>0) + { + // System.err.printf("0x%2x %s %n", b, Character.isISOControl(b)?"?":(""+(char)b)); + out.write(b); + } + else + onAllDataRead(); + } + } + + @Override + public void onAllDataRead() throws IOException + { + response.getOutputStream().write(out.toByteArray()); + asyncContext.complete(); + } + + @Override + public void onError(Throwable x) + { + } + }); + } + }); + + DeferredContentProvider contentProvider = new DeferredContentProvider(); + CountDownLatch clientLatch = new CountDownLatch(1); + + String expected = + "S0" + + "S1" + + "S2" + + "S3S3" + + "S4" + + "S5" + + "S6"; + + client.newRequest(newURI()) + .method(HttpMethod.POST) + .path(servletPath) + .content(contentProvider) + .send(new BufferingResponseListener() + { + @Override + public void onComplete(Result result) + { + if (result.isSucceeded()) + { + Response response = result.getResponse(); + assertThat(response.getStatus(), Matchers.equalTo(HttpStatus.OK_200)); + assertThat(getContentAsString(), Matchers.equalTo(expected)); + clientLatch.countDown(); + } + } + }); + + contentProvider.offer(BufferUtil.toBuffer("S0")); + contentProvider.flush(); + contentProvider.offer(BufferUtil.toBuffer("S1")); + contentProvider.flush(); + contentProvider.offer(BufferUtil.toBuffer("S2")); + contentProvider.flush(); + contentProvider.offer(BufferUtil.toBuffer("S3")); + contentProvider.flush(); + contentProvider.offer(BufferUtil.toBuffer("S4")); + contentProvider.flush(); + contentProvider.offer(BufferUtil.toBuffer("S5")); + contentProvider.flush(); + contentProvider.offer(BufferUtil.toBuffer("S6")); + contentProvider.close(); + + + Assert.assertTrue(clientLatch.await(10,TimeUnit.SECONDS)); + + + } + +} diff --git a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/ConnectionStatisticsTest.java b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/ConnectionStatisticsTest.java new file mode 100644 index 00000000000..37597b66a30 --- /dev/null +++ b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/ConnectionStatisticsTest.java @@ -0,0 +1,98 @@ +// +// ======================================================================== +// Copyright (c) 1995-2016 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.http.client; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.client.util.BytesContentProvider; +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.io.ConnectionStatistics; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.util.IO; +import org.hamcrest.Matchers; +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Test; + +public class ConnectionStatisticsTest extends AbstractTest +{ + public ConnectionStatisticsTest(Transport transport) + { + super(transport); + } + + @Test + public void testConnectionStatistics() throws Exception + { + Assume.assumeThat(transport, Matchers.isOneOf(Transport.H2C, Transport.H2)); + + start(new AbstractHandler() + { + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + baseRequest.setHandled(true); + IO.copy(request.getInputStream(), response.getOutputStream()); + } + }); + + ConnectionStatistics serverStats = new ConnectionStatistics(); + connector.addBean(serverStats); + serverStats.start(); + + ConnectionStatistics clientStats = new ConnectionStatistics(); + client.addBean(clientStats); + clientStats.start(); + + byte[] content = new byte[3072]; + long contentLength = content.length; + ContentResponse response = client.newRequest(newURI()) + .content(new BytesContentProvider(content)) + .timeout(5, TimeUnit.SECONDS) + .send(); + + Assert.assertThat(response.getStatus(), Matchers.equalTo(HttpStatus.OK_200)); + + // The bytes have already arrived, but give time to + // the server to finish to run the response logic. + Thread.sleep(1000); + + // Close all connections. + stop(); + + Assert.assertThat(serverStats.getConnectionsMax(), Matchers.greaterThan(0L)); + Assert.assertThat(serverStats.getReceivedBytes(), Matchers.greaterThan(contentLength)); + Assert.assertThat(serverStats.getSentBytes(), Matchers.greaterThan(contentLength)); + Assert.assertThat(serverStats.getReceivedMessages(), Matchers.greaterThan(0L)); + Assert.assertThat(serverStats.getSentMessages(), Matchers.greaterThan(0L)); + + Assert.assertThat(clientStats.getConnectionsMax(), Matchers.greaterThan(0L)); + Assert.assertThat(clientStats.getReceivedBytes(), Matchers.greaterThan(contentLength)); + Assert.assertThat(clientStats.getSentBytes(), Matchers.greaterThan(contentLength)); + Assert.assertThat(clientStats.getReceivedMessages(), Matchers.greaterThan(0L)); + Assert.assertThat(clientStats.getSentMessages(), Matchers.greaterThan(0L)); + } +} diff --git a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientConnectTimeoutTest.java b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientConnectTimeoutTest.java index 2774e9fd523..5e8b8b6b81f 100644 --- a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientConnectTimeoutTest.java +++ b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientConnectTimeoutTest.java @@ -27,8 +27,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.eclipse.jetty.client.api.Request; -import org.eclipse.jetty.client.api.Response; -import org.eclipse.jetty.client.api.Result; import org.junit.Assert; import org.junit.Assume; import org.junit.Ignore; @@ -51,21 +49,17 @@ public class HttpClientConnectTimeoutTest extends AbstractTest int connectTimeout = 1000; assumeConnectTimeout(host, port, connectTimeout); - start(null); + start(new EmptyServerHandler()); client.stop(); client.setConnectTimeout(connectTimeout); client.start(); final CountDownLatch latch = new CountDownLatch(1); Request request = client.newRequest(host, port); - request.send(new Response.CompleteListener() + request.send(result -> { - @Override - public void onComplete(Result result) - { - if (result.isFailed()) - latch.countDown(); - } + if (result.isFailed()) + latch.countDown(); }); Assert.assertTrue(latch.await(2 * connectTimeout, TimeUnit.MILLISECONDS)); @@ -80,7 +74,7 @@ public class HttpClientConnectTimeoutTest extends AbstractTest int connectTimeout = 2000; assumeConnectTimeout(host, port, connectTimeout); - start(null); + start(new EmptyServerHandler()); client.stop(); client.setConnectTimeout(connectTimeout); client.start(); @@ -89,14 +83,10 @@ public class HttpClientConnectTimeoutTest extends AbstractTest final CountDownLatch latch = new CountDownLatch(2); Request request = client.newRequest(host, port); request.timeout(connectTimeout / 2, TimeUnit.MILLISECONDS) - .send(new Response.CompleteListener() + .send(result -> { - @Override - public void onComplete(Result result) - { - completes.incrementAndGet(); - latch.countDown(); - } + completes.incrementAndGet(); + latch.countDown(); }); Assert.assertFalse(latch.await(2 * connectTimeout, TimeUnit.MILLISECONDS)); @@ -112,31 +102,23 @@ public class HttpClientConnectTimeoutTest extends AbstractTest int connectTimeout = 1000; assumeConnectTimeout(host, port, connectTimeout); - start(null); + start(new EmptyServerHandler()); client.stop(); client.setConnectTimeout(connectTimeout); client.start(); final CountDownLatch latch = new CountDownLatch(1); Request request = client.newRequest(host, port); - request.send(new Response.CompleteListener() + request.send(result1 -> { - @Override - public void onComplete(Result result) + if (result1.isFailed()) { - if (result.isFailed()) + // Retry + client.newRequest(host, port).send(result2 -> { - // Retry - client.newRequest(host, port).send(new Response.CompleteListener() - { - @Override - public void onComplete(Result result) - { - if (result.isFailed()) - latch.countDown(); - } - }); - } + if (result2.isFailed()) + latch.countDown(); + }); } }); diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientContinueTest.java b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientContinueTest.java similarity index 91% rename from jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientContinueTest.java rename to tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientContinueTest.java index d654ba03e51..3961c029987 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientContinueTest.java +++ b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientContinueTest.java @@ -16,7 +16,7 @@ // ======================================================================== // -package org.eclipse.jetty.client; +package org.eclipse.jetty.http.client; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -29,11 +29,13 @@ import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; + import javax.servlet.ServletException; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.client.ContinueProtocolHandler; import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.api.Result; @@ -47,15 +49,17 @@ import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.toolchain.test.annotation.Slow; import org.eclipse.jetty.util.IO; -import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.hamcrest.Matchers; import org.junit.Assert; +import org.junit.Assume; import org.junit.Test; -public class HttpClientContinueTest extends AbstractHttpClientServerTest +public class HttpClientContinueTest extends AbstractTest { - public HttpClientContinueTest(SslContextFactory sslContextFactory) + public HttpClientContinueTest(Transport transport) { - super(sslContextFactory); + // Skip FCGI for now. + super(transport == Transport.FCGI ? null : transport); } @Test @@ -83,8 +87,7 @@ public class HttpClientContinueTest extends AbstractHttpClientServerTest } }); - ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) + ContentResponse response = client.newRequest(newURI()) .header(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString()) .content(new BytesContentProvider(contents)) .timeout(5, TimeUnit.SECONDS) @@ -123,8 +126,7 @@ public class HttpClientContinueTest extends AbstractHttpClientServerTest byte[] content1 = new byte[10240]; byte[] content2 = new byte[16384]; - ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) + ContentResponse response = client.newRequest(newURI()) .header(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString()) .content(new BytesContentProvider(content1, content2) { @@ -175,8 +177,7 @@ public class HttpClientContinueTest extends AbstractHttpClientServerTest byte[] content1 = new byte[10240]; byte[] content2 = new byte[16384]; final CountDownLatch latch = new CountDownLatch(1); - client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) + client.newRequest(newURI()) .header(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString()) .content(new BytesContentProvider(content1, content2)) .send(new BufferingResponseListener() @@ -224,8 +225,7 @@ public class HttpClientContinueTest extends AbstractHttpClientServerTest byte[] content = new byte[10240]; final CountDownLatch latch = new CountDownLatch(1); - client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) + client.newRequest(newURI()) .method(HttpMethod.POST) .path("/continue") .header(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString()) @@ -273,8 +273,7 @@ public class HttpClientContinueTest extends AbstractHttpClientServerTest byte[] content = new byte[10240]; final CountDownLatch latch = new CountDownLatch(1); - client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) + client.newRequest(newURI()) .method(HttpMethod.POST) .path("/redirect") .header(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString()) @@ -321,8 +320,7 @@ public class HttpClientContinueTest extends AbstractHttpClientServerTest byte[] content = new byte[1024]; final CountDownLatch latch = new CountDownLatch(1); - client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) + client.newRequest(newURI()) .header(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString()) .content(new BytesContentProvider(content)) .send(new BufferingResponseListener() @@ -368,8 +366,7 @@ public class HttpClientContinueTest extends AbstractHttpClientServerTest byte[] content = new byte[1024]; final CountDownLatch latch = new CountDownLatch(1); - client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) + client.newRequest(newURI()) .header(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString()) .content(new BytesContentProvider(content)) .send(new BufferingResponseListener() @@ -427,8 +424,7 @@ public class HttpClientContinueTest extends AbstractHttpClientServerTest byte[] content = new byte[1024]; final CountDownLatch latch = new CountDownLatch(1); - client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) + client.newRequest(newURI()) .header(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString()) .content(new BytesContentProvider(content)) .send(new BufferingResponseListener() @@ -469,8 +465,7 @@ public class HttpClientContinueTest extends AbstractHttpClientServerTest final CountDownLatch latch = new CountDownLatch(1); DeferredContentProvider content = new DeferredContentProvider(); - client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) + client.newRequest(newURI()) .header(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString()) .content(content) .send(new BufferingResponseListener() @@ -518,8 +513,7 @@ public class HttpClientContinueTest extends AbstractHttpClientServerTest final CountDownLatch latch = new CountDownLatch(1); DeferredContentProvider content = new DeferredContentProvider(ByteBuffer.wrap(chunk1)); - client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) + client.newRequest(newURI()) .header(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString()) .content(content) .send(new BufferingResponseListener() @@ -558,17 +552,12 @@ public class HttpClientContinueTest extends AbstractHttpClientServerTest final DeferredContentProvider content = new DeferredContentProvider(); final CountDownLatch latch = new CountDownLatch(1); - client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) + client.newRequest(newURI()) .header(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString()) - .onRequestHeaders(new org.eclipse.jetty.client.api.Request.HeadersListener() + .onRequestHeaders(request -> { - @Override - public void onHeaders(org.eclipse.jetty.client.api.Request request) - { - content.offer(ByteBuffer.wrap(data)); - content.close(); - } + content.offer(ByteBuffer.wrap(data)); + content.close(); }) .content(content) .send(new BufferingResponseListener() @@ -625,8 +614,7 @@ public class HttpClientContinueTest extends AbstractHttpClientServerTest }); final CountDownLatch latch = new CountDownLatch(1); - client.newRequest("localhost", connector.getLocalPort()) - .scheme(scheme) + client.newRequest(newURI()) .header(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString()) .content(content) .send(new BufferingResponseListener() @@ -645,6 +633,8 @@ public class HttpClientContinueTest extends AbstractHttpClientServerTest @Test public void test_Expect100Continue_WithTwoResponsesInOneRead() throws Exception { + Assume.assumeThat(transport, Matchers.isOneOf(Transport.HTTP, Transport.HTTPS)); + // There is a chance that the server replies with the 100 Continue response // and immediately after with the "normal" response, say a 200 OK. // These may be read by the client in a single read, and must be handled correctly. @@ -659,15 +649,11 @@ public class HttpClientContinueTest extends AbstractHttpClientServerTest client.newRequest("localhost", server.getLocalPort()) .header(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString()) .content(new BytesContentProvider(new byte[]{0})) - .send(new Response.CompleteListener() + .send(result -> { - @Override - public void onComplete(Result result) - { - Assert.assertTrue(result.toString(), result.isSucceeded()); - Assert.assertEquals(200, result.getResponse().getStatus()); - latch.countDown(); - } + Assert.assertTrue(result.toString(), result.isSucceeded()); + Assert.assertEquals(200, result.getResponse().getStatus()); + latch.countDown(); }); try (Socket socket = server.accept()) diff --git a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientTest.java b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientTest.java index 5567ed81f7d..67b38b3c344 100644 --- a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientTest.java +++ b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientTest.java @@ -488,6 +488,28 @@ public class HttpClientTest extends AbstractTest Assert.assertTrue(completeLatch.await(5, TimeUnit.SECONDS)); } + @Test + public void testResponseWithContentCompleteListenerInvokedOnce() throws Exception + { + start(new EmptyServerHandler() + { + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + super.handle(target, baseRequest, request, response); + response.getWriter().write("Jetty"); + } + }); + + AtomicInteger completes = new AtomicInteger(); + client.newRequest(newURI()) + .send(result -> completes.incrementAndGet()); + + sleep(1000); + + Assert.assertEquals(1, completes.get()); + } + private void sleep(long time) throws IOException { try diff --git a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/ServerTimeoutsTest.java b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/ServerTimeoutsTest.java new file mode 100644 index 00000000000..eaa4b74bd86 --- /dev/null +++ b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/ServerTimeoutsTest.java @@ -0,0 +1,732 @@ +// +// ======================================================================== +// Copyright (c) 1995-2016 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.http.client; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import javax.servlet.AsyncContext; +import javax.servlet.ReadListener; +import javax.servlet.ServletException; +import javax.servlet.ServletInputStream; +import javax.servlet.ServletOutputStream; +import javax.servlet.WriteListener; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.client.util.DeferredContentProvider; +import org.eclipse.jetty.http.BadMessageException; +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.http2.server.AbstractHTTP2ServerConnectionFactory; +import org.eclipse.jetty.server.HttpChannel; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.log.StacklessLogging; +import org.junit.Assert; +import org.junit.Test; + +public class ServerTimeoutsTest extends AbstractTest +{ + public ServerTimeoutsTest(Transport transport) + { + // Skip FCGI for now, not much interested in its server-side behavior. + super(transport == Transport.FCGI ? null : transport); + } + + private void setServerIdleTimeout(long idleTimeout) + { + AbstractHTTP2ServerConnectionFactory h2 = connector.getConnectionFactory(AbstractHTTP2ServerConnectionFactory.class); + if (h2 != null) + h2.setStreamIdleTimeout(idleTimeout); + else + connector.setIdleTimeout(idleTimeout); + } + + @Test + public void testDelayedDispatchRequestWithDelayedFirstContentIdleTimeoutFires() throws Exception + { + httpConfig.setDelayDispatchUntilContent(true); + CountDownLatch handlerLatch = new CountDownLatch(1); + start(new AbstractHandler() + { + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + baseRequest.setHandled(true); + handlerLatch.countDown(); + } + }); + long idleTimeout = 1000; + setServerIdleTimeout(idleTimeout); + + CountDownLatch resultLatch = new CountDownLatch(1); + client.POST(newURI()) + .content(new DeferredContentProvider()) + .send(result -> + { + if (result.isFailed()) + resultLatch.countDown(); + }); + + // We did not send the content, the request was not + // dispatched, the server should have idle timed out. + Assert.assertFalse(handlerLatch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); + Assert.assertTrue(resultLatch.await(5, TimeUnit.SECONDS)); + } + + @Test + public void testNoBlockingTimeoutBlockingReadIdleTimeoutFires() throws Exception + { + httpConfig.setBlockingTimeout(-1); + CountDownLatch handlerLatch = new CountDownLatch(1); + start(new BlockingReadHandler(handlerLatch)); + long idleTimeout = 1000; + setServerIdleTimeout(idleTimeout); + + try (StacklessLogging stackless = new StacklessLogging(HttpChannel.class)) + { + DeferredContentProvider contentProvider = new DeferredContentProvider(ByteBuffer.allocate(1)); + CountDownLatch resultLatch = new CountDownLatch(1); + client.POST(newURI()) + .content(contentProvider) + .send(result -> + { + if (result.getResponse().getStatus() == HttpStatus.INTERNAL_SERVER_ERROR_500) + resultLatch.countDown(); + }); + + // Blocking read should timeout. + Assert.assertTrue(handlerLatch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); + // Complete the request. + contentProvider.close(); + Assert.assertTrue(resultLatch.await(5, TimeUnit.SECONDS)); + } + } + + @Test + public void testBlockingTimeoutSmallerThanIdleTimeoutBlockingReadBlockingTimeoutFires() throws Exception + { + long blockingTimeout = 1000; + httpConfig.setBlockingTimeout(blockingTimeout); + CountDownLatch handlerLatch = new CountDownLatch(1); + start(new BlockingReadHandler(handlerLatch)); + long idleTimeout = 3 * blockingTimeout; + setServerIdleTimeout(idleTimeout); + + try (StacklessLogging stackless = new StacklessLogging(HttpChannel.class)) + { + DeferredContentProvider contentProvider = new DeferredContentProvider(ByteBuffer.allocate(1)); + CountDownLatch resultLatch = new CountDownLatch(1); + client.POST(newURI()) + .content(contentProvider) + .send(result -> + { + if (result.getResponse().getStatus() == HttpStatus.INTERNAL_SERVER_ERROR_500) + resultLatch.countDown(); + }); + + // Blocking read should timeout. + Assert.assertTrue(handlerLatch.await(2 * blockingTimeout, TimeUnit.MILLISECONDS)); + // Complete the request. + contentProvider.close(); + Assert.assertTrue(resultLatch.await(5, TimeUnit.SECONDS)); + } + } + + @Test + public void testBlockingTimeoutLargerThanIdleTimeoutBlockingReadIdleTimeoutFires() throws Exception + { + long idleTimeout = 1000; + long blockingTimeout = 3 * idleTimeout; + httpConfig.setBlockingTimeout(blockingTimeout); + CountDownLatch handlerLatch = new CountDownLatch(1); + start(new BlockingReadHandler(handlerLatch)); + setServerIdleTimeout(idleTimeout); + + try (StacklessLogging stackless = new StacklessLogging(HttpChannel.class)) + { + DeferredContentProvider contentProvider = new DeferredContentProvider(ByteBuffer.allocate(1)); + CountDownLatch resultLatch = new CountDownLatch(1); + client.POST(newURI()) + .content(contentProvider) + .send(result -> + { + if (result.getResponse().getStatus() == HttpStatus.INTERNAL_SERVER_ERROR_500) + resultLatch.countDown(); + }); + + // Blocking read should timeout. + Assert.assertTrue(handlerLatch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); + // Complete the request. + contentProvider.close(); + Assert.assertTrue(resultLatch.await(5, TimeUnit.SECONDS)); + } + } + + @Test + public void testNoBlockingTimeoutBlockingWriteIdleTimeoutFires() throws Exception + { + httpConfig.setBlockingTimeout(-1); + CountDownLatch handlerLatch = new CountDownLatch(1); + start(new BlockingWriteHandler(handlerLatch)); + long idleTimeout = 1000; + setServerIdleTimeout(idleTimeout); + + try (StacklessLogging stackless = new StacklessLogging(HttpChannel.class)) + { + BlockingQueue callbacks = new LinkedBlockingQueue<>(); + CountDownLatch resultLatch = new CountDownLatch(1); + client.newRequest(newURI()) + .onResponseContentAsync((response, content, callback) -> + { + // Do not succeed the callback so the server will block writing. + callbacks.offer(callback); + }) + .send(result -> + { + if (result.isFailed()) + resultLatch.countDown(); + }); + + // Blocking write should timeout. + Assert.assertTrue(handlerLatch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); + // After the server stopped sending, consume on the client to read the early EOF. + while (true) + { + Callback callback = callbacks.poll(1, TimeUnit.SECONDS); + if (callback == null) + break; + callback.succeeded(); + } + Assert.assertTrue(resultLatch.await(5, TimeUnit.SECONDS)); + } + } + + @Test + public void testBlockingTimeoutSmallerThanIdleTimeoutBlockingWriteBlockingTimeoutFires() throws Exception + { + long blockingTimeout = 1000; + httpConfig.setBlockingTimeout(blockingTimeout); + CountDownLatch handlerLatch = new CountDownLatch(1); + start(new BlockingWriteHandler(handlerLatch)); + long idleTimeout = 3 * blockingTimeout; + setServerIdleTimeout(idleTimeout); + + try (StacklessLogging stackless = new StacklessLogging(HttpChannel.class)) + { + BlockingQueue callbacks = new LinkedBlockingQueue<>(); + CountDownLatch resultLatch = new CountDownLatch(1); + client.newRequest(newURI()) + .onResponseContentAsync((response, content, callback) -> + { + // Do not succeed the callback so the server will block writing. + callbacks.offer(callback); + }) + .send(result -> + { + if (result.isFailed()) + resultLatch.countDown(); + }); + + // Blocking write should timeout. + Assert.assertTrue(handlerLatch.await(2 * blockingTimeout, TimeUnit.MILLISECONDS)); + // After the server stopped sending, consume on the client to read the early EOF. + while (true) + { + Callback callback = callbacks.poll(1, TimeUnit.SECONDS); + if (callback == null) + break; + callback.succeeded(); + } + Assert.assertTrue(resultLatch.await(5, TimeUnit.SECONDS)); + } + } + + @Test + public void testBlockingTimeoutLargerThanIdleTimeoutBlockingWriteIdleTimeoutFires() throws Exception + { + long idleTimeout = 1000; + long blockingTimeout = 3 * idleTimeout; + httpConfig.setBlockingTimeout(blockingTimeout); + CountDownLatch handlerLatch = new CountDownLatch(1); + start(new BlockingWriteHandler(handlerLatch)); + setServerIdleTimeout(idleTimeout); + + try (StacklessLogging stackless = new StacklessLogging(HttpChannel.class)) + { + BlockingQueue callbacks = new LinkedBlockingQueue<>(); + CountDownLatch resultLatch = new CountDownLatch(1); + client.newRequest(newURI()) + .onResponseContentAsync((response, content, callback) -> + { + // Do not succeed the callback so the server will block writing. + callbacks.offer(callback); + }) + .send(result -> + { + if (result.isFailed()) + resultLatch.countDown(); + }); + + // Blocking read should timeout. + Assert.assertTrue(handlerLatch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); + // After the server stopped sending, consume on the client to read the early EOF. + while (true) + { + Callback callback = callbacks.poll(1, TimeUnit.SECONDS); + if (callback == null) + break; + callback.succeeded(); + } + Assert.assertTrue(resultLatch.await(5, TimeUnit.SECONDS)); + } + } + + @Test + public void testBlockingTimeoutWithSlowRead() throws Exception + { + long idleTimeout = 1000; + long blockingTimeout = 2 * idleTimeout; + httpConfig.setBlockingTimeout(blockingTimeout); + CountDownLatch handlerLatch = new CountDownLatch(1); + start(new AbstractHandler() + { + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + try + { + baseRequest.setHandled(true); + ServletInputStream input = request.getInputStream(); + while (true) + { + int read = input.read(); + if (read < 0) + break; + } + } + catch (IOException x) + { + handlerLatch.countDown(); + throw x; + } + } + }); + setServerIdleTimeout(idleTimeout); + + try (StacklessLogging stackless = new StacklessLogging(HttpChannel.class)) + { + DeferredContentProvider contentProvider = new DeferredContentProvider(); + CountDownLatch resultLatch = new CountDownLatch(1); + client.newRequest(newURI()) + .content(contentProvider) + .send(result -> + { + // Result may fail to send the whole request body, + // but the response has arrived successfully. + if (result.getResponse().getStatus() == HttpStatus.INTERNAL_SERVER_ERROR_500) + resultLatch.countDown(); + }); + + // The writes should be slow but not trigger the idle timeout. + long period = idleTimeout / 2; + long writes = 2 * (blockingTimeout / period); + for (long i = 0; i < writes; ++i) + { + contentProvider.offer(ByteBuffer.allocate(1)); + Thread.sleep(period); + } + contentProvider.close(); + + // Blocking read should timeout. + Assert.assertTrue(handlerLatch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); + Assert.assertTrue(resultLatch.await(5, TimeUnit.SECONDS)); + } + } + + @Test + public void testAsyncReadIdleTimeoutFires() throws Exception + { + CountDownLatch handlerLatch = new CountDownLatch(1); + start(new AbstractHandler() + { + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + baseRequest.setHandled(true); + AsyncContext asyncContext = request.startAsync(); + asyncContext.setTimeout(0); + ServletInputStream input = request.getInputStream(); + input.setReadListener(new ReadListener() + { + @Override + public void onDataAvailable() throws IOException + { + Assert.assertEquals(0, input.read()); + Assert.assertFalse(input.isReady()); + } + + @Override + public void onAllDataRead() throws IOException + { + } + + @Override + public void onError(Throwable failure) + { + if (failure instanceof TimeoutException) + { + response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR_500); + asyncContext.complete(); + handlerLatch.countDown(); + } + } + }); + } + }); + long idleTimeout = 1000; + setServerIdleTimeout(idleTimeout); + + DeferredContentProvider contentProvider = new DeferredContentProvider(ByteBuffer.allocate(1)); + CountDownLatch resultLatch = new CountDownLatch(1); + client.POST(newURI()) + .content(contentProvider) + .send(result -> + { + if (result.getResponse().getStatus() == HttpStatus.INTERNAL_SERVER_ERROR_500) + resultLatch.countDown(); + }); + + // Async read should timeout. + Assert.assertTrue(handlerLatch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); + // Complete the request. + contentProvider.close(); + Assert.assertTrue(resultLatch.await(5, TimeUnit.SECONDS)); + } + + @Test + public void testAsyncWriteIdleTimeoutFires() throws Exception + { + CountDownLatch handlerLatch = new CountDownLatch(1); + start(new AbstractHandler() + { + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + baseRequest.setHandled(true); + AsyncContext asyncContext = request.startAsync(); + asyncContext.setTimeout(0); + ServletOutputStream output = response.getOutputStream(); + output.setWriteListener(new WriteListener() + { + @Override + public void onWritePossible() throws IOException + { + output.write(new byte[64 * 1024 * 1024]); + } + + @Override + public void onError(Throwable failure) + { + if (failure instanceof TimeoutException) + { + asyncContext.complete(); + handlerLatch.countDown(); + } + } + }); + } + }); + long idleTimeout = 1000; + setServerIdleTimeout(idleTimeout); + + BlockingQueue callbacks = new LinkedBlockingQueue<>(); + CountDownLatch resultLatch = new CountDownLatch(1); + client.newRequest(newURI()) + .onResponseContentAsync((response, content, callback) -> + { + // Do not succeed the callback so the server will block writing. + callbacks.offer(callback); + }) + .send(result -> + { + if (result.isFailed()) + resultLatch.countDown(); + }); + + // Async write should timeout. + Assert.assertTrue(handlerLatch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); + // After the server stopped sending, consume on the client to read the early EOF. + while (true) + { + Callback callback = callbacks.poll(1, TimeUnit.SECONDS); + if (callback == null) + break; + callback.succeeded(); + } + Assert.assertTrue(resultLatch.await(5, TimeUnit.SECONDS)); + } + + @Test + public void testBlockingReadWithMinimumDataRateBelowLimit() throws Exception + { + int bytesPerSecond = 20; + httpConfig.setMinRequestDataRate(bytesPerSecond); + CountDownLatch handlerLatch = new CountDownLatch(1); + start(new AbstractHandler() + { + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + try + { + baseRequest.setHandled(true); + ServletInputStream input = request.getInputStream(); + while (true) + { + int read = input.read(); + if (read < 0) + break; + } + } + catch (BadMessageException x) + { + handlerLatch.countDown(); + throw x; + } + } + }); + + DeferredContentProvider contentProvider = new DeferredContentProvider(); + CountDownLatch resultLatch = new CountDownLatch(1); + client.newRequest(newURI()) + .content(contentProvider) + .send(result -> + { + if (result.getResponse().getStatus() == HttpStatus.REQUEST_TIMEOUT_408) + resultLatch.countDown(); + }); + + for (int i = 0; i < 3; ++i) + { + contentProvider.offer(ByteBuffer.allocate(bytesPerSecond / 2)); + Thread.sleep(1000); + } + contentProvider.close(); + + // Request should timeout. + Assert.assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); + Assert.assertTrue(resultLatch.await(5, TimeUnit.SECONDS)); + } + + @Test + public void testBlockingReadWithMinimumDataRateAboveLimit() throws Exception + { + int bytesPerSecond = 20; + httpConfig.setMinRequestDataRate(bytesPerSecond); + CountDownLatch handlerLatch = new CountDownLatch(1); + start(new AbstractHandler() + { + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + baseRequest.setHandled(true); + ServletInputStream input = request.getInputStream(); + while (true) + { + int read = input.read(); + if (read < 0) + break; + } + handlerLatch.countDown(); + } + }); + + DeferredContentProvider contentProvider = new DeferredContentProvider(); + CountDownLatch resultLatch = new CountDownLatch(1); + client.newRequest(newURI()) + .content(contentProvider) + .send(result -> + { + if (result.getResponse().getStatus() == HttpStatus.OK_200) + resultLatch.countDown(); + }); + + for (int i = 0; i < 3; ++i) + { + contentProvider.offer(ByteBuffer.allocate(bytesPerSecond * 2)); + Thread.sleep(1000); + } + contentProvider.close(); + + Assert.assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); + Assert.assertTrue(resultLatch.await(5, TimeUnit.SECONDS)); + } + + @Test + public void testBlockingReadHttpIdleTimeoutOverridesIdleTimeout() throws Exception + { + long httpIdleTimeout = 1000; + long idleTimeout = 3 * httpIdleTimeout; + httpConfig.setIdleTimeout(httpIdleTimeout); + CountDownLatch handlerLatch = new CountDownLatch(1); + start(new BlockingReadHandler(handlerLatch)); + setServerIdleTimeout(idleTimeout); + + try (StacklessLogging stackless = new StacklessLogging(HttpChannel.class)) + { + DeferredContentProvider contentProvider = new DeferredContentProvider(ByteBuffer.allocate(1)); + CountDownLatch resultLatch = new CountDownLatch(1); + client.POST(newURI()) + .content(contentProvider) + .send(result -> + { + if (result.getResponse().getStatus() == HttpStatus.INTERNAL_SERVER_ERROR_500) + resultLatch.countDown(); + }); + + // Blocking read should timeout. + Assert.assertTrue(handlerLatch.await(2 * httpIdleTimeout, TimeUnit.MILLISECONDS)); + // Complete the request. + contentProvider.close(); + Assert.assertTrue(resultLatch.await(5, TimeUnit.SECONDS)); + } + } + + @Test + public void testAsyncReadHttpIdleTimeoutOverridesIdleTimeout() throws Exception + { + long httpIdleTimeout = 1000; + long idleTimeout = 3 * httpIdleTimeout; + httpConfig.setIdleTimeout(httpIdleTimeout); + CountDownLatch handlerLatch = new CountDownLatch(1); + start(new AbstractHandler() + { + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + baseRequest.setHandled(true); + AsyncContext asyncContext = request.startAsync(); + asyncContext.setTimeout(0); + ServletInputStream input = request.getInputStream(); + input.setReadListener(new ReadListener() + { + @Override + public void onDataAvailable() throws IOException + { + Assert.assertEquals(0, input.read()); + Assert.assertFalse(input.isReady()); + } + + @Override + public void onAllDataRead() throws IOException + { + } + + @Override + public void onError(Throwable failure) + { + if (failure instanceof TimeoutException) + { + response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR_500); + asyncContext.complete(); + handlerLatch.countDown(); + } + } + }); + } + }); + setServerIdleTimeout(idleTimeout); + + DeferredContentProvider contentProvider = new DeferredContentProvider(ByteBuffer.allocate(1)); + CountDownLatch resultLatch = new CountDownLatch(1); + client.POST(newURI()) + .content(contentProvider) + .send(result -> + { + if (result.getResponse().getStatus() == HttpStatus.INTERNAL_SERVER_ERROR_500) + resultLatch.countDown(); + }); + + // Async read should timeout. + Assert.assertTrue(handlerLatch.await(2 * idleTimeout, TimeUnit.MILLISECONDS)); + // Complete the request. + contentProvider.close(); + Assert.assertTrue(resultLatch.await(5, TimeUnit.SECONDS)); + } + + private static class BlockingReadHandler extends AbstractHandler + { + private final CountDownLatch handlerLatch; + + public BlockingReadHandler(CountDownLatch handlerLatch) + { + this.handlerLatch = handlerLatch; + } + + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + baseRequest.setHandled(true); + ServletInputStream input = request.getInputStream(); + Assert.assertEquals(0, input.read()); + try + { + input.read(); + } + catch (IOException x) + { + handlerLatch.countDown(); + throw x; + } + } + } + + private static class BlockingWriteHandler extends AbstractHandler + { + private final CountDownLatch handlerLatch; + + private BlockingWriteHandler(CountDownLatch handlerLatch) + { + this.handlerLatch = handlerLatch; + } + + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + baseRequest.setHandled(true); + ServletOutputStream output = response.getOutputStream(); + try + { + output.write(new byte[64 * 1024 * 1024]); + } + catch (IOException x) + { + handlerLatch.countDown(); + throw x; + } + } + } +} diff --git a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java index 3e48304032d..01397dcb72f 100644 --- a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java +++ b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java @@ -42,7 +42,7 @@ public class ClientCrossContextSessionTest extends AbstractClientCrossContextSes @Override - public AbstractTestServer createServer(final int port, final int max, final int scavenge, final int evictionPolicy) + public AbstractTestServer createServer(final int port, final int max, final int scavenge, final int evictionPolicy) throws Exception { return new FileTestServer(port,max,scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/FileTestServer.java b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/FileTestServer.java index a64dde27dda..30c13ded244 100644 --- a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/FileTestServer.java +++ b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/FileTestServer.java @@ -122,7 +122,7 @@ public class FileTestServer extends AbstractTestServer - public FileTestServer(int port, int maxInactivePeriod, int scavengePeriod, int idlePassivatePeriod) + public FileTestServer(int port, int maxInactivePeriod, int scavengePeriod, int idlePassivatePeriod) throws Exception { super(port, maxInactivePeriod, scavengePeriod, idlePassivatePeriod); } diff --git a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ForwardedSessionTest.java b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ForwardedSessionTest.java index 2843c7b4296..08f0ec008e7 100644 --- a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ForwardedSessionTest.java +++ b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ForwardedSessionTest.java @@ -45,7 +45,7 @@ public class ForwardedSessionTest extends AbstractForwardedSessionTest @Override - public AbstractTestServer createServer(final int port, final int max, final int scavenge, final int evictionPolicy) + public AbstractTestServer createServer(final int port, final int max, final int scavenge, final int evictionPolicy) throws Exception { return new FileTestServer(port,max,scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/IdleSessionTest.java b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/IdleSessionTest.java index 5ce7b4c7855..179e94348cd 100644 --- a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/IdleSessionTest.java +++ b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/IdleSessionTest.java @@ -47,7 +47,7 @@ public class IdleSessionTest extends AbstractIdleSessionTest * @see org.eclipse.jetty.server.session.AbstractIdleSessionTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(final int port, final int max, final int scavenge, final int evictionPolicy) + public AbstractTestServer createServer(final int port, final int max, final int scavenge, final int evictionPolicy) throws Exception { return new FileTestServer(port,max,scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ImmediateSaveTest.java b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ImmediateSaveTest.java index d7db65d3e63..87a5ecdf5f2 100644 --- a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ImmediateSaveTest.java +++ b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ImmediateSaveTest.java @@ -43,7 +43,7 @@ public class ImmediateSaveTest extends AbstractImmediateSaveTest } - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new FileTestServer(port, max, scavenge, evictionPolicy) { public SessionHandler newSessionHandler() diff --git a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ImmortalSessionTest.java b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ImmortalSessionTest.java index c813ccf65de..82babfef651 100644 --- a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ImmortalSessionTest.java +++ b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ImmortalSessionTest.java @@ -37,7 +37,7 @@ public class ImmortalSessionTest extends AbstractImmortalSessionTest @Override - public AbstractTestServer createServer(int port, int max, int scavenge,int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge,int evictionPolicy) throws Exception { return new FileTestServer(port,max,scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java index e643088577a..87977468646 100644 --- a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java +++ b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java @@ -40,7 +40,7 @@ public class NewSessionTest extends AbstractNewSessionTest FileTestServer.teardown(); } - public AbstractTestServer createServer(int port, int max, int scavenge,int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge,int evictionPolicy) throws Exception { return new FileTestServer(port,max,scavenge,evictionPolicy); } diff --git a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/OrphanedSessionTest.java b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/OrphanedSessionTest.java index b16dd46cf33..f4d1470d691 100644 --- a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/OrphanedSessionTest.java +++ b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/OrphanedSessionTest.java @@ -39,7 +39,7 @@ public class OrphanedSessionTest extends AbstractOrphanedSessionTest FileTestServer.teardown(); } - public AbstractTestServer createServer(int port, int max, int scavenge,int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge,int evictionPolicy) throws Exception { return new FileTestServer(port,max,scavenge,evictionPolicy); } diff --git a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ProxySerializationTest.java b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ProxySerializationTest.java index 94851aa8b04..1a87412a175 100644 --- a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ProxySerializationTest.java +++ b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ProxySerializationTest.java @@ -50,7 +50,7 @@ public class ProxySerializationTest extends AbstractProxySerializationTest * @see org.eclipse.jetty.server.session.AbstractProxySerializationTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int max, int scavenge,int evictionPolicy ) + public AbstractTestServer createServer(int port, int max, int scavenge,int evictionPolicy ) throws Exception { return new FileTestServer(port,max,scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java index 16ebd57df3c..86eb9851393 100644 --- a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java +++ b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java @@ -41,7 +41,7 @@ public class ReentrantRequestSessionTest extends AbstractReentrantRequestSession } - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new FileTestServer(port, max, scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/RemoveSessionTest.java b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/RemoveSessionTest.java index 2626506be13..c1ebae9522b 100644 --- a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/RemoveSessionTest.java +++ b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/RemoveSessionTest.java @@ -38,7 +38,7 @@ public class RemoveSessionTest extends AbstractRemoveSessionTest } - public AbstractTestServer createServer(int port, int max, int scavenge,int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge,int evictionPolicy) throws Exception { return new FileTestServer(port,max,scavenge,evictionPolicy); } diff --git a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ScatterGunLoadTest.java b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ScatterGunLoadTest.java index be1aa346c71..da192a10622 100644 --- a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ScatterGunLoadTest.java +++ b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ScatterGunLoadTest.java @@ -43,7 +43,7 @@ public class ScatterGunLoadTest extends AbstractScatterGunLoadTest @Override - public AbstractTestServer createServer(final int port, final int max, final int scavenge, final int evictionPolicy) + public AbstractTestServer createServer(final int port, final int max, final int scavenge, final int evictionPolicy) throws Exception { return new FileTestServer(port,max,scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ServerCrossContextSessionTest.java b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ServerCrossContextSessionTest.java index 6afeda77f84..d5719045621 100644 --- a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ServerCrossContextSessionTest.java +++ b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ServerCrossContextSessionTest.java @@ -40,7 +40,7 @@ public class ServerCrossContextSessionTest extends AbstractServerCrossContextSes @Override - public AbstractTestServer createServer(final int port, final int max, final int scavenge, final int evictionPolicy) + public AbstractTestServer createServer(final int port, final int max, final int scavenge, final int evictionPolicy) throws Exception { return new FileTestServer(port,max,scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/SessionCookieTest.java b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/SessionCookieTest.java index f5ffeb83f11..8b4d9cf6246 100644 --- a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/SessionCookieTest.java +++ b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/SessionCookieTest.java @@ -40,7 +40,7 @@ public class SessionCookieTest extends AbstractSessionCookieTest @Override - public AbstractTestServer createServer(int port, int max, int scavenge,int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge,int evictionPolicy) throws Exception { return new FileTestServer(port, max, scavenge,evictionPolicy); } diff --git a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/SessionInvalidateAndCreateTest.java b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/SessionInvalidateAndCreateTest.java index 5589d933746..344a8f09e3c 100644 --- a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/SessionInvalidateAndCreateTest.java +++ b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/SessionInvalidateAndCreateTest.java @@ -38,7 +38,7 @@ public class SessionInvalidateAndCreateTest extends AbstractSessionInvalidateAnd } @Override - public AbstractTestServer createServer(int port, int max, int scavenge,int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge,int evictionPolicy) throws Exception { return new FileTestServer(port,max,scavenge,evictionPolicy); } diff --git a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/SessionRenewTest.java b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/SessionRenewTest.java index ee7a942d244..3020b81061b 100644 --- a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/SessionRenewTest.java +++ b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/SessionRenewTest.java @@ -40,7 +40,7 @@ public class SessionRenewTest extends AbstractSessionRenewTest } @Override - public AbstractTestServer createServer(int port, int max, int scavenge,int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge,int evictionPolicy) throws Exception { return new FileTestServer(port, max, scavenge,evictionPolicy); } diff --git a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/SessionValueSharedSaving.java b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/SessionValueSharedSaving.java index e71b2d59952..f1cce48fbab 100644 --- a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/SessionValueSharedSaving.java +++ b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/SessionValueSharedSaving.java @@ -38,7 +38,7 @@ public class SessionValueSharedSaving extends AbstractSessionValueSavingTest @Override - public AbstractTestServer createServer(int port, int max, int scavenge,int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge,int evictionPolicy) throws Exception { return new FileTestServer(port,max,scavenge,evictionPolicy); } diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ClientCrossContextSessionTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ClientCrossContextSessionTest.java index bd776456335..643f401ab75 100644 --- a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ClientCrossContextSessionTest.java +++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ClientCrossContextSessionTest.java @@ -41,7 +41,7 @@ public class ClientCrossContextSessionTest extends AbstractClientCrossContextSes } @Override - public AbstractTestServer createServer(int port, int maxInactiveMs, int scavengeMs,int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactiveMs, int scavengeMs,int evictionPolicy) throws Exception { return new GCloudTestServer(port, maxInactiveMs, scavengeMs, evictionPolicy); } diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ForwardedSessionTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ForwardedSessionTest.java index a1d3e0ef4d0..323bc0fb89b 100644 --- a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ForwardedSessionTest.java +++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ForwardedSessionTest.java @@ -41,7 +41,7 @@ public class ForwardedSessionTest extends AbstractForwardedSessionTest @Override - public AbstractTestServer createServer(int port, int maxInactiveMs, int scavengeMs,int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactiveMs, int scavengeMs,int evictionPolicy) throws Exception { return new GCloudTestServer(port, maxInactiveMs, scavengeMs, evictionPolicy); } diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/GCloudSessionTestSupport.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/GCloudSessionTestSupport.java index 0df93b521dc..d9babb1cc9c 100644 --- a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/GCloudSessionTestSupport.java +++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/GCloudSessionTestSupport.java @@ -81,7 +81,7 @@ public class GCloudSessionTestSupport public Set getSessionIds () throws Exception { HashSet ids = new HashSet(); - GqlQuery.Builder builder = Query.gqlQueryBuilder(ResultType.ENTITY, "select * from "+GCloudSessionDataStore.KIND); + GqlQuery.Builder builder = Query.gqlQueryBuilder(ResultType.ENTITY, "select * from "+GCloudSessionDataStore.EntityDataModel.KIND); Query query = builder.build(); @@ -99,7 +99,7 @@ public class GCloudSessionTestSupport public void listSessions () throws Exception { - GqlQuery.Builder builder = Query.gqlQueryBuilder(ResultType.ENTITY, "select * from "+GCloudSessionDataStore.KIND); + GqlQuery.Builder builder = Query.gqlQueryBuilder(ResultType.ENTITY, "select * from "+GCloudSessionDataStore.EntityDataModel.KIND); Query query = builder.build(); @@ -117,7 +117,7 @@ public class GCloudSessionTestSupport public void assertSessions(int count) throws Exception { - Query query = Query.keyQueryBuilder().kind(GCloudSessionDataStore.KIND).build(); + Query query = Query.keyQueryBuilder().kind(GCloudSessionDataStore.EntityDataModel.KIND).build(); QueryResults results = _ds.run(query); assertNotNull(results); int actual = 0; @@ -131,7 +131,7 @@ public class GCloudSessionTestSupport public void deleteSessions () throws Exception { - Query query = Query.keyQueryBuilder().kind(GCloudSessionDataStore.KIND).build(); + Query query = Query.keyQueryBuilder().kind(GCloudSessionDataStore.EntityDataModel.KIND).build(); QueryResults results = _ds.run(query); if (results != null) diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/GCloudTestServer.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/GCloudTestServer.java index a6fe95b9101..57367872561 100644 --- a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/GCloudTestServer.java +++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/GCloudTestServer.java @@ -36,8 +36,9 @@ public class GCloudTestServer extends AbstractTestServer * @param maxInactivePeriod * @param scavengePeriod * @param evictionPolicy + * @throws Exception TODO */ - public GCloudTestServer(int port, int maxInactivePeriod, int scavengePeriod, int evictionPolicy) + public GCloudTestServer(int port, int maxInactivePeriod, int scavengePeriod, int evictionPolicy) throws Exception { super(port, maxInactivePeriod, scavengePeriod, evictionPolicy); } diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ImmediateSaveTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ImmediateSaveTest.java index 53cf28ae464..ffcfd940600 100644 --- a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ImmediateSaveTest.java +++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ImmediateSaveTest.java @@ -46,7 +46,7 @@ public class ImmediateSaveTest extends AbstractImmediateSaveTest - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new GCloudTestServer(port, max, scavenge, evictionPolicy) { diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ImmortalSessionTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ImmortalSessionTest.java index 23081a4eaa3..1fba691abb7 100644 --- a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ImmortalSessionTest.java +++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ImmortalSessionTest.java @@ -43,7 +43,7 @@ public class ImmortalSessionTest extends AbstractImmortalSessionTest * @see org.eclipse.jetty.server.session.AbstractImmortalSessionTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int maxInactiveMs, int scavengeMs,int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactiveMs, int scavengeMs,int evictionPolicy) throws Exception { return new GCloudTestServer(port, maxInactiveMs, scavengeMs, evictionPolicy); } diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/InvalidationSessionTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/InvalidationSessionTest.java index aeea9f1f031..7493b8683fe 100644 --- a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/InvalidationSessionTest.java +++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/InvalidationSessionTest.java @@ -45,7 +45,7 @@ public class InvalidationSessionTest extends AbstractInvalidationSessionTest * @see org.eclipse.jetty.server.session.AbstractInvalidationSessionTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy) throws Exception { GCloudTestServer server = new GCloudTestServer(port, maxInactive, scavengeInterval, evictionPolicy) { diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/LastAccessTimeTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/LastAccessTimeTest.java index c2c37f890d5..333dd43a5a5 100644 --- a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/LastAccessTimeTest.java +++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/LastAccessTimeTest.java @@ -42,7 +42,7 @@ public class LastAccessTimeTest extends AbstractLastAccessTimeTest * @see org.eclipse.jetty.server.session.AbstractLastAccessTimeTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int max, int scavenge,int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge,int evictionPolicy) throws Exception { return new GCloudTestServer(port, max, scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/LocalSessionScavengingTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/LocalSessionScavengingTest.java index 8718e3985fe..14094c7cd85 100644 --- a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/LocalSessionScavengingTest.java +++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/LocalSessionScavengingTest.java @@ -43,7 +43,7 @@ public class LocalSessionScavengingTest extends AbstractLocalSessionScavengingTe * @see org.eclipse.jetty.server.session.AbstractLocalSessionScavengingTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int max, int scavenge,int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge,int evictionPolicy) throws Exception { return new GCloudTestServer(port, max, scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/NewSessionTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/NewSessionTest.java index a7ab6bf16d6..77b4c99085e 100644 --- a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/NewSessionTest.java +++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/NewSessionTest.java @@ -50,7 +50,7 @@ public class NewSessionTest extends AbstractNewSessionTest * @see org.eclipse.jetty.server.session.AbstractNewSessionTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int max, int scavenge,int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge,int evictionPolicy) throws Exception { return new GCloudTestServer(port, max, scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/OrphanedSessionTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/OrphanedSessionTest.java index 7e193ae2d6b..a0fd7cc3072 100644 --- a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/OrphanedSessionTest.java +++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/OrphanedSessionTest.java @@ -44,7 +44,7 @@ public class OrphanedSessionTest extends AbstractOrphanedSessionTest * @see org.eclipse.jetty.server.session.AbstractOrphanedSessionTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int max, int scavenge,int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge,int evictionPolicy) throws Exception { return new GCloudTestServer(port, max, scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ReentrantRequestSessionTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ReentrantRequestSessionTest.java index ce5562653c2..7ab4cf9cb06 100644 --- a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ReentrantRequestSessionTest.java +++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ReentrantRequestSessionTest.java @@ -43,7 +43,7 @@ public class ReentrantRequestSessionTest extends AbstractReentrantRequestSession * @see org.eclipse.jetty.server.session.AbstractReentrantRequestSessionTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port,int max, int scavengePeriod,int evictionPolicy) + public AbstractTestServer createServer(int port,int max, int scavengePeriod,int evictionPolicy) throws Exception { return new GCloudTestServer(port, max, scavengePeriod, evictionPolicy); } diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/RemoveSessionTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/RemoveSessionTest.java index f3f87384814..74472d47dda 100644 --- a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/RemoveSessionTest.java +++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/RemoveSessionTest.java @@ -46,7 +46,7 @@ public class RemoveSessionTest extends AbstractRemoveSessionTest * @see org.eclipse.jetty.server.session.AbstractRemoveSessionTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int max, int scavenge,int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge,int evictionPolicy) throws Exception { return new GCloudTestServer(port, max, scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SameNodeLoadTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SameNodeLoadTest.java index a677e003cff..0e43e7c770a 100644 --- a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SameNodeLoadTest.java +++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SameNodeLoadTest.java @@ -44,7 +44,7 @@ public class SameNodeLoadTest extends AbstractSameNodeLoadTest * @see org.eclipse.jetty.server.session.AbstractSameNodeLoadTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new GCloudTestServer(port, max, scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ServerCrossContextSessionTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ServerCrossContextSessionTest.java index 494c8ec4664..946cba171dd 100644 --- a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ServerCrossContextSessionTest.java +++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ServerCrossContextSessionTest.java @@ -39,7 +39,7 @@ public class ServerCrossContextSessionTest extends AbstractServerCrossContextSes } @Override - public AbstractTestServer createServer(int port, int maxInactiveMs, int scavengeMs,int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactiveMs, int scavengeMs,int evictionPolicy) throws Exception { return new GCloudTestServer(port, maxInactiveMs, scavengeMs, evictionPolicy); } diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionExpiryTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionExpiryTest.java index 78002217c74..8a768ebc1f0 100644 --- a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionExpiryTest.java +++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionExpiryTest.java @@ -48,7 +48,7 @@ public class SessionExpiryTest extends AbstractSessionExpiryTest * @see org.eclipse.jetty.server.session.AbstractSessionExpiryTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new GCloudTestServer(port, max, scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionInvalidateAndCreateTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionInvalidateAndCreateTest.java index 9ab1a4fc84d..033d211a0c1 100644 --- a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionInvalidateAndCreateTest.java +++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionInvalidateAndCreateTest.java @@ -43,7 +43,7 @@ public class SessionInvalidateAndCreateTest extends AbstractSessionInvalidateAnd * @see org.eclipse.jetty.server.session.AbstractSessionInvalidateAndCreateTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new GCloudTestServer(port, max, scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionMigrationTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionMigrationTest.java index ed8e900e156..eb6fe7f2e47 100644 --- a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionMigrationTest.java +++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionMigrationTest.java @@ -43,7 +43,7 @@ public class SessionMigrationTest extends AbstractSessionMigrationTest * @see org.eclipse.jetty.server.session.AbstractSessionMigrationTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int maxInactiveMs, int scavengeMs,int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactiveMs, int scavengeMs,int evictionPolicy) throws Exception { return new GCloudTestServer(port, maxInactiveMs, scavengeMs, evictionPolicy); } diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionRenewTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionRenewTest.java index 0dd816c5110..092c50bd942 100644 --- a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionRenewTest.java +++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionRenewTest.java @@ -47,7 +47,7 @@ public class SessionRenewTest extends AbstractSessionRenewTest * @see org.eclipse.jetty.server.session.AbstractSessionRenewTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new GCloudTestServer(port,max, scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionValueSavingTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionValueSavingTest.java index 7b31bd56a57..573bc9ae53f 100644 --- a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionValueSavingTest.java +++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionValueSavingTest.java @@ -42,7 +42,7 @@ public class SessionValueSavingTest extends AbstractSessionValueSavingTest * @see org.eclipse.jetty.server.session.AbstractSessionValueSavingTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new GCloudTestServer(port, max, scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/StopSessionManagerPreserveSessionTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/StopSessionManagerPreserveSessionTest.java index 8e7569ed76f..b93c36c50ba 100644 --- a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/StopSessionManagerPreserveSessionTest.java +++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/StopSessionManagerPreserveSessionTest.java @@ -60,7 +60,7 @@ public class StopSessionManagerPreserveSessionTest extends AbstractStopSessionMa @Override - public AbstractTestServer createServer(int port, int maxInactiveMs, int scavengeMs,int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactiveMs, int scavengeMs,int evictionPolicy) throws Exception { return new GCloudTestServer(port, maxInactiveMs, scavengeMs, evictionPolicy); } diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java index 870802570b1..a8e48f887d2 100644 --- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java +++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java @@ -37,7 +37,7 @@ public class ClientCrossContextSessionTest extends AbstractClientCrossContextSes @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new HashTestServer(port,max,scavenge,evictionPolicy); } diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/EvictionFailureTest.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/EvictionFailureTest.java index dbcbd52bf58..da0c007a3fb 100644 --- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/EvictionFailureTest.java +++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/EvictionFailureTest.java @@ -31,7 +31,7 @@ public class EvictionFailureTest extends AbstractSessionEvictionFailureTest * @see org.eclipse.jetty.server.session.AbstractTestBase#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy) throws Exception { return new HashTestServer(port, maxInactive, scavengeInterval, evictionPolicy); } diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/HashTestServer.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/HashTestServer.java index 9257d382d68..1090bcc56b8 100644 --- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/HashTestServer.java +++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/HashTestServer.java @@ -25,7 +25,7 @@ public class HashTestServer extends AbstractTestServer { - public HashTestServer(int port, int maxInactivePeriod, int scavengePeriod, int evictionPolicy) + public HashTestServer(int port, int maxInactivePeriod, int scavengePeriod, int evictionPolicy) throws Exception { super(port, maxInactivePeriod, scavengePeriod, evictionPolicy); } diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ImmortalSessionTest.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ImmortalSessionTest.java index 4c18b3c72ea..da6b4eb8161 100644 --- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ImmortalSessionTest.java +++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ImmortalSessionTest.java @@ -22,7 +22,7 @@ public class ImmortalSessionTest extends AbstractImmortalSessionTest { @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new HashTestServer(port,max,scavenge,evictionPolicy); } diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java index 07b34f90cef..459d5a3cabb 100644 --- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java +++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java @@ -26,7 +26,7 @@ import org.junit.Test; public class NewSessionTest extends AbstractNewSessionTest { - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new HashTestServer(port,max,scavenge,evictionPolicy); } diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java index cefb383379f..8093902feca 100644 --- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java +++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java @@ -30,7 +30,7 @@ public class ReentrantRequestSessionTest extends AbstractReentrantRequestSession * @see org.eclipse.jetty.server.session.AbstractReentrantRequestSessionTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new HashTestServer(port, max, scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/RemoveSessionTest.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/RemoveSessionTest.java index 44912267009..2c91400754d 100644 --- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/RemoveSessionTest.java +++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/RemoveSessionTest.java @@ -34,7 +34,7 @@ public class RemoveSessionTest extends AbstractRemoveSessionTest * @see org.eclipse.jetty.server.session.AbstractRemoveSessionTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new HashTestServer (port, max, scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ScatterGunLoadTest.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ScatterGunLoadTest.java index 2b073d8c0ca..9f706129587 100644 --- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ScatterGunLoadTest.java +++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ScatterGunLoadTest.java @@ -27,7 +27,7 @@ public class ScatterGunLoadTest extends AbstractScatterGunLoadTest { @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new HashTestServer(port,max,scavenge,evictionPolicy); } diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ServerCrossContextSessionTest.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ServerCrossContextSessionTest.java index b5fa1f85079..482656e1b8b 100644 --- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ServerCrossContextSessionTest.java +++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ServerCrossContextSessionTest.java @@ -23,7 +23,7 @@ import org.junit.Test; public class ServerCrossContextSessionTest extends AbstractServerCrossContextSessionTest { @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new HashTestServer(port,max,scavenge,evictionPolicy); } diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/SessionCookieTest.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/SessionCookieTest.java index 166a5c9de4f..0df2c9f0b44 100644 --- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/SessionCookieTest.java +++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/SessionCookieTest.java @@ -22,7 +22,7 @@ public class SessionCookieTest extends AbstractSessionCookieTest { @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new HashTestServer(port, max, scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/SessionInvalidateAndCreateTest.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/SessionInvalidateAndCreateTest.java index 8ab67f2940c..12c3b10d599 100644 --- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/SessionInvalidateAndCreateTest.java +++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/SessionInvalidateAndCreateTest.java @@ -24,7 +24,7 @@ public class SessionInvalidateAndCreateTest extends AbstractSessionInvalidateAnd { @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new HashTestServer(port,max,scavenge,evictionPolicy); } diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/SessionRenewTest.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/SessionRenewTest.java index bfa01593bf8..4025d79f43b 100644 --- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/SessionRenewTest.java +++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/SessionRenewTest.java @@ -31,7 +31,7 @@ public class SessionRenewTest extends AbstractSessionRenewTest { @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new HashTestServer(port, max, scavenge,evictionPolicy); } diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/SessionValueSharedSaving.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/SessionValueSharedSaving.java index d2129a4ce85..9d43f6d29b3 100644 --- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/SessionValueSharedSaving.java +++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/SessionValueSharedSaving.java @@ -22,7 +22,7 @@ public class SessionValueSharedSaving extends AbstractSessionValueSavingTest { @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new HashTestServer(port,max,scavenge,evictionPolicy); } diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java index 439de537865..bad3acd2f20 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java @@ -46,7 +46,7 @@ public class ClientCrossContextSessionTest extends AbstractClientCrossContextSes @Override - public AbstractTestServer createServer(int port, int maxInactiveMs, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactiveMs, int scavenge, int evictionPolicy) throws Exception { return new InfinispanTestSessionServer(port, maxInactiveMs, scavenge, evictionPolicy, __testSupport.getCache()); } diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ForwardedSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ForwardedSessionTest.java index d5aa449b4f5..4b78cf6c276 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ForwardedSessionTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ForwardedSessionTest.java @@ -51,7 +51,7 @@ public class ForwardedSessionTest extends AbstractForwardedSessionTest @Override - public AbstractTestServer createServer(int port, int maxInactiveMs, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactiveMs, int scavenge, int evictionPolicy) throws Exception { return new InfinispanTestSessionServer(port, maxInactiveMs, scavenge, evictionPolicy, __testSupport.getCache()); } diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ImmediateSaveTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ImmediateSaveTest.java index 94a4e9c20d7..e85f202016b 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ImmediateSaveTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ImmediateSaveTest.java @@ -47,7 +47,7 @@ public class ImmediateSaveTest extends AbstractImmediateSaveTest } - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { _server = new InfinispanTestSessionServer(port, max, scavenge, evictionPolicy, __testSupport.getCache()) { diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ImmortalSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ImmortalSessionTest.java index 491809b2875..e2fe69c6c05 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ImmortalSessionTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ImmortalSessionTest.java @@ -56,7 +56,7 @@ public class ImmortalSessionTest extends AbstractImmortalSessionTest * @see org.eclipse.jetty.server.session.AbstractImmortalSessionTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int maxInactiveMs, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactiveMs, int scavenge, int evictionPolicy) throws Exception { return new InfinispanTestSessionServer(port, maxInactiveMs, scavenge, evictionPolicy, __testSupport.getCache()); } diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InfinispanTestSessionServer.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InfinispanTestSessionServer.java index 5f615d1072c..ca705937688 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InfinispanTestSessionServer.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InfinispanTestSessionServer.java @@ -31,7 +31,7 @@ public class InfinispanTestSessionServer extends AbstractTestServer - public InfinispanTestSessionServer(int port, int maxInactivePeriod, int scavengePeriod, int evictionPolicy, BasicCache config) + public InfinispanTestSessionServer(int port, int maxInactivePeriod, int scavengePeriod, int evictionPolicy, BasicCache config) throws Exception { super(port, maxInactivePeriod, scavengePeriod, evictionPolicy, config); } diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/LastAccessTimeTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/LastAccessTimeTest.java index 1a8e927f16e..049a7d64ea6 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/LastAccessTimeTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/LastAccessTimeTest.java @@ -42,7 +42,7 @@ public class LastAccessTimeTest extends AbstractLastAccessTimeTest @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new InfinispanTestSessionServer(port, max, scavenge, evictionPolicy, __testSupport.getCache()); } diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/LocalSessionScavengingTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/LocalSessionScavengingTest.java index eb906a96c11..a65d63005ec 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/LocalSessionScavengingTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/LocalSessionScavengingTest.java @@ -51,7 +51,7 @@ public class LocalSessionScavengingTest extends AbstractLocalSessionScavengingTe * @see org.eclipse.jetty.server.session.AbstractLocalSessionScavengingTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new InfinispanTestSessionServer(port, max, scavenge, evictionPolicy, __testSupport.getCache()); } diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java index 8c7794284a2..8af19c7719f 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java @@ -50,7 +50,7 @@ public class NewSessionTest extends AbstractNewSessionTest * @see org.eclipse.jetty.server.session.AbstractNewSessionTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new InfinispanTestSessionServer(port, max, scavenge, evictionPolicy, __testSupport.getCache()); } diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java index 8b90772e258..4783d4569fc 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java @@ -49,7 +49,7 @@ public class ReentrantRequestSessionTest extends AbstractReentrantRequestSession * @see org.eclipse.jetty.server.session.AbstractReentrantRequestSessionTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port,int maxInactive, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port,int maxInactive, int scavenge, int evictionPolicy) throws Exception { return new InfinispanTestSessionServer(port, maxInactive, scavenge, evictionPolicy, __testSupport.getCache()); } diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/RemoveSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/RemoveSessionTest.java index 61d4099a924..c5b9f5935f3 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/RemoveSessionTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/RemoveSessionTest.java @@ -43,7 +43,7 @@ public class RemoveSessionTest extends AbstractRemoveSessionTest @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { InfinispanTestSessionServer s = new InfinispanTestSessionServer(port, max, scavenge, evictionPolicy, __testSupport.getCache()); return s; diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SameNodeLoadTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SameNodeLoadTest.java index fff63912b7b..13901cfb140 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SameNodeLoadTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SameNodeLoadTest.java @@ -51,7 +51,7 @@ public class SameNodeLoadTest extends AbstractSameNodeLoadTest * @see org.eclipse.jetty.server.session.AbstractSameNodeLoadTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port,int maxInactive, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port,int maxInactive, int scavenge, int evictionPolicy) throws Exception { InfinispanTestSessionServer server = new InfinispanTestSessionServer(port,maxInactive, scavenge, evictionPolicy, __testSupport.getCache()); return server; diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionExpiryTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionExpiryTest.java index a813da30ff8..51d2b0f22df 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionExpiryTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionExpiryTest.java @@ -42,7 +42,7 @@ public class SessionExpiryTest extends AbstractSessionExpiryTest } @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { InfinispanTestSessionServer server = new InfinispanTestSessionServer(port, max, scavenge, evictionPolicy, __testSupport.getCache()); return server; diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionInvalidateAndCreateTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionInvalidateAndCreateTest.java index f35661bfd0b..3d6078c1ed4 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionInvalidateAndCreateTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionInvalidateAndCreateTest.java @@ -50,7 +50,7 @@ public class SessionInvalidateAndCreateTest extends AbstractSessionInvalidateAnd * @see org.eclipse.jetty.server.session.AbstractSessionInvalidateAndCreateTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new InfinispanTestSessionServer(port, max, scavenge, evictionPolicy, __testSupport.getCache()); } diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionMigrationTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionMigrationTest.java index 365e5e26221..68b1f65e595 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionMigrationTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionMigrationTest.java @@ -48,7 +48,7 @@ public class SessionMigrationTest extends AbstractSessionMigrationTest @Override - public AbstractTestServer createServer(int port, int maxInactiveMs, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactiveMs, int scavenge, int evictionPolicy) throws Exception { return new InfinispanTestSessionServer(port, maxInactiveMs, scavenge, evictionPolicy, __testSupport.getCache()); } diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionRenewTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionRenewTest.java index 7db9b7c64ae..3f92f49e3fc 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionRenewTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionRenewTest.java @@ -57,7 +57,7 @@ public class SessionRenewTest extends AbstractSessionRenewTest * @see org.eclipse.jetty.server.session.AbstractSessionRenewTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new InfinispanTestSessionServer(port, max, scavenge, evictionPolicy, __testSupport.getCache()); } diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteClientCrossContextSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteClientCrossContextSessionTest.java index 18cb070cbce..50b46d2d9f3 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteClientCrossContextSessionTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteClientCrossContextSessionTest.java @@ -55,7 +55,7 @@ public class RemoteClientCrossContextSessionTest extends AbstractClientCrossCont @Override - public AbstractTestServer createServer(int port, int maxInactiveMs, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactiveMs, int scavenge, int evictionPolicy) throws Exception { return new InfinispanTestSessionServer(port, maxInactiveMs, scavenge, evictionPolicy, __testSupport.getCache()); } diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteForwardedSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteForwardedSessionTest.java index 19b89769afd..4c5f9095b64 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteForwardedSessionTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteForwardedSessionTest.java @@ -53,7 +53,7 @@ public class RemoteForwardedSessionTest extends AbstractForwardedSessionTest @Override - public AbstractTestServer createServer(int port, int maxInactiveMs, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactiveMs, int scavenge, int evictionPolicy) throws Exception { return new InfinispanTestSessionServer(port, maxInactiveMs, scavenge, evictionPolicy, __testSupport.getCache()); } diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteImmediateSaveTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteImmediateSaveTest.java index 5c5db7d3829..56623d2eec5 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteImmediateSaveTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteImmediateSaveTest.java @@ -50,7 +50,7 @@ public class RemoteImmediateSaveTest extends AbstractImmediateSaveTest __testSupport.teardown(); } - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new InfinispanTestSessionServer(port, max, scavenge, evictionPolicy, __testSupport.getCache()) { diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteImmortalSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteImmortalSessionTest.java index 7da9e18a05b..41abdf6392f 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteImmortalSessionTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteImmortalSessionTest.java @@ -59,7 +59,7 @@ public class RemoteImmortalSessionTest extends AbstractImmortalSessionTest * @see org.eclipse.jetty.server.session.AbstractImmortalSessionTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int maxInactiveMs, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactiveMs, int scavenge, int evictionPolicy) throws Exception { return new InfinispanTestSessionServer(port, maxInactiveMs, scavenge, evictionPolicy, __testSupport.getCache()); } diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteInvalidationSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteInvalidationSessionTest.java index f752f7212d0..df8c7b2029e 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteInvalidationSessionTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteInvalidationSessionTest.java @@ -56,7 +56,7 @@ public class RemoteInvalidationSessionTest extends AbstractInvalidationSessionTe * @see org.eclipse.jetty.server.session.AbstractInvalidationSessionTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int maxInterval, int scavengeInterval, int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInterval, int scavengeInterval, int evictionPolicy) throws Exception { return new InfinispanTestSessionServer(port, maxInterval, scavengeInterval, evictionPolicy, __testSupport.getCache()); } diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteLastAccessTimeTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteLastAccessTimeTest.java index 4183e15ccd5..05e942f8fa3 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteLastAccessTimeTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteLastAccessTimeTest.java @@ -52,7 +52,7 @@ public class RemoteLastAccessTimeTest extends AbstractLastAccessTimeTest @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new InfinispanTestSessionServer(port, max, scavenge, evictionPolicy, __testSupport.getCache()); } diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteLocalSessionScavengingTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteLocalSessionScavengingTest.java index 734fcf14303..be80cb6f567 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteLocalSessionScavengingTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteLocalSessionScavengingTest.java @@ -53,7 +53,7 @@ public class RemoteLocalSessionScavengingTest extends AbstractLocalSessionScaven * @see org.eclipse.jetty.server.session.AbstractLocalSessionScavengingTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new InfinispanTestSessionServer(port, max, scavenge, evictionPolicy, __testSupport.getCache()); } diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteNewSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteNewSessionTest.java index 2c58cf5b302..1b85afb18c7 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteNewSessionTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteNewSessionTest.java @@ -53,7 +53,7 @@ public class RemoteNewSessionTest extends AbstractNewSessionTest * @see org.eclipse.jetty.server.session.AbstractNewSessionTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new InfinispanTestSessionServer(port, max, scavenge, evictionPolicy, __testSupport.getCache()); } diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteReentrantRequestSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteReentrantRequestSessionTest.java index 00f8a645fc0..02d42be4e55 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteReentrantRequestSessionTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteReentrantRequestSessionTest.java @@ -52,7 +52,7 @@ public class RemoteReentrantRequestSessionTest extends AbstractReentrantRequestS * @see org.eclipse.jetty.server.session.AbstractReentrantRequestSessionTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int maxInactive, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactive, int scavenge, int evictionPolicy) throws Exception { return new InfinispanTestSessionServer(port, maxInactive, scavenge, evictionPolicy, __testSupport.getCache()); } diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteRemoveSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteRemoveSessionTest.java index ebbf9a999ce..c55c4ef09dc 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteRemoveSessionTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteRemoveSessionTest.java @@ -46,7 +46,7 @@ public class RemoteRemoveSessionTest extends AbstractRemoveSessionTest @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { InfinispanTestSessionServer s = new InfinispanTestSessionServer(port, max, scavenge,evictionPolicy, __testSupport.getCache()); return s; diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSameNodeLoadTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSameNodeLoadTest.java index 069c10475fb..d5253e37ad9 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSameNodeLoadTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSameNodeLoadTest.java @@ -54,7 +54,7 @@ public class RemoteSameNodeLoadTest extends AbstractSameNodeLoadTest * @see org.eclipse.jetty.server.session.AbstractSameNodeLoadTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int maxInactive, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactive, int scavenge, int evictionPolicy) throws Exception { InfinispanTestSessionServer server = new InfinispanTestSessionServer(port, maxInactive, scavenge,evictionPolicy, __testSupport.getCache()); return server; diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionExpiryTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionExpiryTest.java index b0438e68513..4393c1555fa 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionExpiryTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionExpiryTest.java @@ -45,7 +45,7 @@ public class RemoteSessionExpiryTest extends AbstractSessionExpiryTest } @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { InfinispanTestSessionServer server = new InfinispanTestSessionServer(port, max, scavenge, evictionPolicy, __testSupport.getCache()); return server; diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionInvalidateAndCreateTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionInvalidateAndCreateTest.java index c355800f725..a96e854df85 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionInvalidateAndCreateTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionInvalidateAndCreateTest.java @@ -53,7 +53,7 @@ public class RemoteSessionInvalidateAndCreateTest extends AbstractSessionInvalid * @see org.eclipse.jetty.server.session.AbstractSessionInvalidateAndCreateTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new InfinispanTestSessionServer(port, max, scavenge, evictionPolicy, __testSupport.getCache()); } diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionMigrationTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionMigrationTest.java index 8a2b4264e26..0a542bf634c 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionMigrationTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionMigrationTest.java @@ -51,7 +51,7 @@ public class RemoteSessionMigrationTest extends AbstractSessionMigrationTest @Override - public AbstractTestServer createServer(int port, int maxInactiveMs, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactiveMs, int scavenge, int evictionPolicy) throws Exception { return new InfinispanTestSessionServer(port, maxInactiveMs, scavenge, evictionPolicy, __testSupport.getCache()); } diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionRenewTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionRenewTest.java index 6ed38f9de8d..8404c59aa3d 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionRenewTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionRenewTest.java @@ -56,7 +56,7 @@ public class RemoteSessionRenewTest extends AbstractSessionRenewTest * @see org.eclipse.jetty.server.session.AbstractSessionRenewTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new InfinispanTestSessionServer(port, max, scavenge, evictionPolicy, __testSupport.getCache()); } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java index 52cb5765676..518c880dfe4 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java @@ -31,7 +31,7 @@ public class ClientCrossContextSessionTest extends AbstractClientCrossContextSes { @Override - public AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy) throws Exception { return new JdbcTestServer(port, maxInactive, scavengeInterval, evictionPolicy); } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ForwardedSessionTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ForwardedSessionTest.java index a7b908585ff..b565a375d51 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ForwardedSessionTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ForwardedSessionTest.java @@ -31,7 +31,7 @@ public class ForwardedSessionTest extends AbstractForwardedSessionTest { @Override - public AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy) throws Exception { return new JdbcTestServer(port, maxInactive, scavengeInterval, evictionPolicy); } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ImmediateSaveTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ImmediateSaveTest.java index e27c6785e26..fde0200f560 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ImmediateSaveTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ImmediateSaveTest.java @@ -39,7 +39,7 @@ public class ImmediateSaveTest extends AbstractImmediateSaveTest } - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { _server = new JdbcTestServer(port, max, scavenge, evictionPolicy) { diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ImmortalSessionTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ImmortalSessionTest.java index 7403c8e84af..4d85f3f1719 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ImmortalSessionTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ImmortalSessionTest.java @@ -29,7 +29,7 @@ import org.junit.Test; public class ImmortalSessionTest extends AbstractImmortalSessionTest { - public AbstractTestServer createServer(int port, int maxInactiveMs, int scavengeMs, int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactiveMs, int scavengeMs, int evictionPolicy) throws Exception { return new JdbcTestServer(port, maxInactiveMs, scavengeMs, evictionPolicy); } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/InvalidationSessionTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/InvalidationSessionTest.java index e6ad87d6398..7e4b9a52911 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/InvalidationSessionTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/InvalidationSessionTest.java @@ -28,7 +28,7 @@ import org.junit.Test; public class InvalidationSessionTest extends AbstractInvalidationSessionTest { - public AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy) throws Exception { return new JdbcTestServer(port, maxInactive, scavengeInterval, evictionPolicy); } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/JdbcTestServer.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/JdbcTestServer.java index c77f561beaf..13cdc12ebdf 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/JdbcTestServer.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/JdbcTestServer.java @@ -79,12 +79,12 @@ public class JdbcTestServer extends AbstractTestServer } - public JdbcTestServer(int port, int maxInactivePeriod, int scavengePeriod, int idlePassivatePeriod, String connectionUrl) + public JdbcTestServer(int port, int maxInactivePeriod, int scavengePeriod, int idlePassivatePeriod, String connectionUrl) throws Exception { super(port, maxInactivePeriod, scavengePeriod, idlePassivatePeriod); } - public JdbcTestServer(int port, int maxInactivePeriod, int scavengePeriod, int idlePassivatePeriod) + public JdbcTestServer(int port, int maxInactivePeriod, int scavengePeriod, int idlePassivatePeriod) throws Exception { super(port, maxInactivePeriod, scavengePeriod, idlePassivatePeriod); } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/LastAccessTimeTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/LastAccessTimeTest.java index a01df927fc4..08d625f575a 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/LastAccessTimeTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/LastAccessTimeTest.java @@ -26,7 +26,7 @@ import org.junit.Test; */ public class LastAccessTimeTest extends AbstractLastAccessTimeTest { - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new JdbcTestServer(port,max,scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/LocalSessionScavengingTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/LocalSessionScavengingTest.java index 822ce9e3d24..4c938b2304d 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/LocalSessionScavengingTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/LocalSessionScavengingTest.java @@ -43,11 +43,18 @@ public class LocalSessionScavengingTest extends AbstractLocalSessionScavengingTe } } - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new JdbcTestServer(port,max,scavenge, evictionPolicy); } + @Test + public void testNoScavenging() throws Exception + { + super.testNoScavenging(); + } + + @Test public void testLocalSessionsScavenging() throws Exception { diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java index 111dce9381f..616549e9b23 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/NewSessionTest.java @@ -29,7 +29,7 @@ public class NewSessionTest extends AbstractNewSessionTest /** * @see org.eclipse.jetty.server.session.AbstractNewSessionTest#createServer(int, int, int, int) */ - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new JdbcTestServer(port,max,scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/OrphanedSessionTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/OrphanedSessionTest.java index 6f0977bdba7..593aae86d06 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/OrphanedSessionTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/OrphanedSessionTest.java @@ -26,7 +26,7 @@ import org.junit.Test; */ public class OrphanedSessionTest extends AbstractOrphanedSessionTest { - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new JdbcTestServer(port,max,scavenge,evictionPolicy); } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ProxySerializationTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ProxySerializationTest.java index bc28cc21597..3c7f25aff68 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ProxySerializationTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ProxySerializationTest.java @@ -35,7 +35,7 @@ public class ProxySerializationTest extends AbstractProxySerializationTest * @see org.eclipse.jetty.server.session.AbstractProxySerializationTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new JdbcTestServer(port, max, scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java index 5ca51a62184..488be8fd9a7 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java @@ -28,7 +28,7 @@ import org.junit.Test; public class ReentrantRequestSessionTest extends AbstractReentrantRequestSessionTest { - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new JdbcTestServer(port,max,scavenge,evictionPolicy); } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ServerCrossContextSessionTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ServerCrossContextSessionTest.java index ed8787a62f5..023849e95b4 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ServerCrossContextSessionTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ServerCrossContextSessionTest.java @@ -28,7 +28,7 @@ public class ServerCrossContextSessionTest extends AbstractServerCrossContextSes { @Override - public AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy) throws Exception { return new JdbcTestServer(port, maxInactive, scavengeInterval, evictionPolicy); } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionExpiryTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionExpiryTest.java index 2fc52c447e4..ca6302063ec 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionExpiryTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionExpiryTest.java @@ -36,7 +36,7 @@ public class SessionExpiryTest extends AbstractSessionExpiryTest * @see org.eclipse.jetty.server.session.AbstractSessionExpiryTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new JdbcTestServer(port,max,scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionInvalidateAndCreateTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionInvalidateAndCreateTest.java index 68281f71af4..75069236fd3 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionInvalidateAndCreateTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionInvalidateAndCreateTest.java @@ -26,7 +26,7 @@ public class SessionInvalidateAndCreateTest extends AbstractSessionInvalidateAnd { @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new JdbcTestServer(port,max,scavenge,evictionPolicy); } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionMigrationTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionMigrationTest.java index d07155c2b55..939f24d5f1a 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionMigrationTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionMigrationTest.java @@ -28,7 +28,7 @@ public class SessionMigrationTest extends AbstractSessionMigrationTest { @Override - public AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy) throws Exception { return new JdbcTestServer(port, maxInactive, scavengeInterval, evictionPolicy); } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionRenewTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionRenewTest.java index 544597f4230..f26d5389cd7 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionRenewTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionRenewTest.java @@ -30,7 +30,7 @@ public class SessionRenewTest extends AbstractSessionRenewTest { @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new JdbcTestServer(port, max, scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionValueSavingTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionValueSavingTest.java index ae06ee18481..f048e4bb263 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionValueSavingTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionValueSavingTest.java @@ -26,7 +26,7 @@ import org.junit.Test; */ public class SessionValueSavingTest extends AbstractSessionValueSavingTest { - public AbstractTestServer createServer(int port, int max, int scavenge,int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge,int evictionPolicy) throws Exception { return new JdbcTestServer(port,max,scavenge,evictionPolicy); } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/StopSessionManagerPreserveSessionTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/StopSessionManagerPreserveSessionTest.java index 28c5bc04230..844e2a9da7f 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/StopSessionManagerPreserveSessionTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/StopSessionManagerPreserveSessionTest.java @@ -52,7 +52,7 @@ public class StopSessionManagerPreserveSessionTest extends AbstractStopSessionMa } @Override - public AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy) throws Exception { _server = new JdbcTestServer(port, maxInactive, scavengeInterval, evictionPolicy); return _server; diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/WebAppObjectInSessionTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/WebAppObjectInSessionTest.java index 7025e44ee24..1de0db6149e 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/WebAppObjectInSessionTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/WebAppObjectInSessionTest.java @@ -30,7 +30,7 @@ import org.junit.Test; public class WebAppObjectInSessionTest extends AbstractWebAppObjectInSessionTest { @Override - public AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy) throws Exception { Resource.setDefaultUseCaches(false); return new JdbcTestServer(port, maxInactive, scavengeInterval, evictionPolicy); diff --git a/tests/test-sessions/test-memcached-sessions/src/test/java/org/eclipse/jetty/memcached/sessions/CachingSessionDataStoreTest.java b/tests/test-sessions/test-memcached-sessions/src/test/java/org/eclipse/jetty/memcached/sessions/CachingSessionDataStoreTest.java index 8b2bd64084f..35a6aa255cb 100644 --- a/tests/test-sessions/test-memcached-sessions/src/test/java/org/eclipse/jetty/memcached/sessions/CachingSessionDataStoreTest.java +++ b/tests/test-sessions/test-memcached-sessions/src/test/java/org/eclipse/jetty/memcached/sessions/CachingSessionDataStoreTest.java @@ -50,7 +50,7 @@ import org.junit.Test; */ public class CachingSessionDataStoreTest { - public AbstractTestServer createServer (int port, int max, int scavenge,int evictionPolicy) + public AbstractTestServer createServer (int port, int max, int scavenge,int evictionPolicy) throws Exception { return new MemcachedTestServer(port, max, scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-memcached-sessions/src/test/java/org/eclipse/jetty/memcached/sessions/MemcachedTestServer.java b/tests/test-sessions/test-memcached-sessions/src/test/java/org/eclipse/jetty/memcached/sessions/MemcachedTestServer.java index 10024e0d21b..fbd6b31f78d 100644 --- a/tests/test-sessions/test-memcached-sessions/src/test/java/org/eclipse/jetty/memcached/sessions/MemcachedTestServer.java +++ b/tests/test-sessions/test-memcached-sessions/src/test/java/org/eclipse/jetty/memcached/sessions/MemcachedTestServer.java @@ -148,7 +148,7 @@ public class MemcachedTestServer extends AbstractTestServer * @param scavengePeriod * @param evictionPolicy */ - public MemcachedTestServer(int port, int maxInactivePeriod, int scavengePeriod, int evictionPolicy) + public MemcachedTestServer(int port, int maxInactivePeriod, int scavengePeriod, int evictionPolicy) throws Exception { super(port, maxInactivePeriod, scavengePeriod, evictionPolicy); } diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ClientCrossContextSessionTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ClientCrossContextSessionTest.java index 28ece5e6293..9279f462e2b 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ClientCrossContextSessionTest.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ClientCrossContextSessionTest.java @@ -41,7 +41,7 @@ public class ClientCrossContextSessionTest extends AbstractClientCrossContextSes } @Override - public AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy) throws Exception { return new MongoTestServer(port, maxInactive, scavengeInterval, evictionPolicy); } diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/CreateAndInvalidateTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/CreateAndInvalidateTest.java index b2adfae8de7..de3780a4afb 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/CreateAndInvalidateTest.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/CreateAndInvalidateTest.java @@ -57,7 +57,7 @@ public class CreateAndInvalidateTest extends AbstractCreateAndInvalidateTest * @see org.eclipse.jetty.server.session.AbstractCreateAndInvalidateTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(final int port, final int max, final int scavenge, final int evictionPolicy) + public AbstractTestServer createServer(final int port, final int max, final int scavenge, final int evictionPolicy) throws Exception { return new MongoTestServer(port,max,scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ForwardedSessionTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ForwardedSessionTest.java index 26691b79e99..88c4bab4048 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ForwardedSessionTest.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ForwardedSessionTest.java @@ -48,7 +48,7 @@ public class ForwardedSessionTest extends AbstractForwardedSessionTest @Override - public AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy) throws Exception { return new MongoTestServer(port,maxInactive, scavengeInterval, evictionPolicy); } diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/IdleSessionTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/IdleSessionTest.java index aa617d3c634..2e70434d3b7 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/IdleSessionTest.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/IdleSessionTest.java @@ -56,7 +56,7 @@ public class IdleSessionTest extends AbstractIdleSessionTest * @see org.eclipse.jetty.server.session.AbstractIdleSessionTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(final int port, final int max, final int scavenge, final int evictionPolicy) + public AbstractTestServer createServer(final int port, final int max, final int scavenge, final int evictionPolicy) throws Exception { return new MongoTestServer(port,max,scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ImmediateSaveTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ImmediateSaveTest.java index ca28fc1acb2..704e96ad615 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ImmediateSaveTest.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ImmediateSaveTest.java @@ -52,7 +52,7 @@ public class ImmediateSaveTest extends AbstractImmediateSaveTest - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new MongoTestServer(port, max, scavenge, evictionPolicy) { diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ImmortalSessionTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ImmortalSessionTest.java index 188f237e3d5..8029a4f872f 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ImmortalSessionTest.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ImmortalSessionTest.java @@ -34,7 +34,7 @@ public class ImmortalSessionTest extends AbstractImmortalSessionTest * @see org.eclipse.jetty.server.session.AbstractTestBase#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy) throws Exception { return new MongoTestServer(port, maxInactive, scavengeInterval, evictionPolicy); } diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/InvalidateSessionTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/InvalidateSessionTest.java index 53b96c29f72..d5043b46273 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/InvalidateSessionTest.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/InvalidateSessionTest.java @@ -42,7 +42,7 @@ public class InvalidateSessionTest extends AbstractInvalidationSessionTest } @Override - public AbstractTestServer createServer(int port, int maxInterval, int scavengeInterval, int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInterval, int scavengeInterval, int evictionPolicy) throws Exception { return new MongoTestServer(port, maxInterval, scavengeInterval, evictionPolicy); } diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/LastAccessTimeTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/LastAccessTimeTest.java index ca78ffcd5e5..fba3dde06fd 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/LastAccessTimeTest.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/LastAccessTimeTest.java @@ -41,7 +41,7 @@ public class LastAccessTimeTest extends AbstractLastAccessTimeTest MongoTestServer.dropCollection(); } - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new MongoTestServer(port,max,scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/LocalSessionScavengingTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/LocalSessionScavengingTest.java index 13a1ea41a19..537a4318081 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/LocalSessionScavengingTest.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/LocalSessionScavengingTest.java @@ -41,7 +41,7 @@ public class LocalSessionScavengingTest extends AbstractLocalSessionScavengingTe } @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { MongoTestServer mserver=new MongoTestServer(port,max,scavenge, evictionPolicy); diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/MongoTestServer.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/MongoTestServer.java index f12a801115e..06a58c0bfbe 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/MongoTestServer.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/MongoTestServer.java @@ -57,7 +57,7 @@ public class MongoTestServer extends AbstractTestServer } - public MongoTestServer(int port, int maxInactivePeriod, int scavengePeriod, int idlePassivatePeriod) + public MongoTestServer(int port, int maxInactivePeriod, int scavengePeriod, int idlePassivatePeriod) throws Exception { super(port, maxInactivePeriod, scavengePeriod, idlePassivatePeriod); } @@ -65,7 +65,7 @@ public class MongoTestServer extends AbstractTestServer - public MongoTestServer(int port, int maxInactivePeriod, int scavengePeriod, int idlePassivatePeriod, boolean saveAllAttributes) + public MongoTestServer(int port, int maxInactivePeriod, int scavengePeriod, int idlePassivatePeriod, boolean saveAllAttributes) throws Exception { super(port, maxInactivePeriod, scavengePeriod, idlePassivatePeriod); } diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/NewSessionTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/NewSessionTest.java index b85f40cde86..9d66c17d27a 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/NewSessionTest.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/NewSessionTest.java @@ -44,7 +44,7 @@ public class NewSessionTest extends AbstractNewSessionTest } - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new MongoTestServer(port,max,scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/OrphanedSessionTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/OrphanedSessionTest.java index 4ba21f03226..7f1534fb7f8 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/OrphanedSessionTest.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/OrphanedSessionTest.java @@ -44,7 +44,7 @@ public class OrphanedSessionTest extends AbstractOrphanedSessionTest } - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new MongoTestServer(port,max,scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ReentrantRequestSessionTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ReentrantRequestSessionTest.java index 870f60461a3..cef28824d8e 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ReentrantRequestSessionTest.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ReentrantRequestSessionTest.java @@ -55,7 +55,7 @@ public class ReentrantRequestSessionTest extends AbstractReentrantRequestSession * @see org.eclipse.jetty.server.session.AbstractReentrantRequestSessionTest#createServer(int, int, int, int) */ @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new MongoTestServer(port, max, scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/RemoveSessionTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/RemoveSessionTest.java index 9d015ec01d9..596be0f1bfa 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/RemoveSessionTest.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/RemoveSessionTest.java @@ -41,7 +41,7 @@ public class RemoveSessionTest extends AbstractRemoveSessionTest MongoTestServer.dropCollection(); } - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new MongoTestServer(port,max,scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ScatterGunLoadTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ScatterGunLoadTest.java index cc44df46884..a8ad4eff9ed 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ScatterGunLoadTest.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ScatterGunLoadTest.java @@ -45,7 +45,7 @@ public class ScatterGunLoadTest extends AbstractScatterGunLoadTest @Override - public AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy) throws Exception { return new MongoTestServer(port, maxInactive, scavengeInterval, evictionPolicy); } diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ServerCrossContextSessionTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ServerCrossContextSessionTest.java index e85b7ab2388..05cda713ce1 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ServerCrossContextSessionTest.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ServerCrossContextSessionTest.java @@ -43,7 +43,7 @@ public class ServerCrossContextSessionTest extends AbstractServerCrossContextSes @Override - public AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy) throws Exception { return new MongoTestServer(port, maxInactive, scavengeInterval, evictionPolicy); } diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionExpiryTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionExpiryTest.java index 2763a65cc26..4739499f516 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionExpiryTest.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionExpiryTest.java @@ -68,7 +68,7 @@ public class SessionExpiryTest extends AbstractSessionExpiryTest } @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new MongoTestServer(port,max,scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionInvalidateAndCreateTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionInvalidateAndCreateTest.java index e58424619f2..92224e2d5ca 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionInvalidateAndCreateTest.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionInvalidateAndCreateTest.java @@ -42,7 +42,7 @@ public class SessionInvalidateAndCreateTest extends AbstractSessionInvalidateAnd } @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new MongoTestServer(port,max,scavenge,evictionPolicy); } diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionMigrationTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionMigrationTest.java index 21d8c420ac1..50573c0b63e 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionMigrationTest.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionMigrationTest.java @@ -42,7 +42,7 @@ public class SessionMigrationTest extends AbstractSessionMigrationTest } @Override - public AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy) + public AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy) throws Exception { return new MongoTestServer(port, maxInactive, scavengeInterval, evictionPolicy); } diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionRenewTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionRenewTest.java index 54bc507c8b3..6291ec36777 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionRenewTest.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionRenewTest.java @@ -49,7 +49,7 @@ public class SessionRenewTest extends AbstractSessionRenewTest } @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new MongoTestServer(port, max, scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionSavingValueTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionSavingValueTest.java index 55f5f064dda..fa345eec3f0 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionSavingValueTest.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionSavingValueTest.java @@ -42,7 +42,7 @@ public class SessionSavingValueTest extends AbstractSessionValueSavingTest } @Override - public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) + public AbstractTestServer createServer(int port, int max, int scavenge, int evictionPolicy) throws Exception { return new MongoTestServer(port, max, scavenge, evictionPolicy); } diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLocalSessionScavengingTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLocalSessionScavengingTest.java index 7920698b6a8..6f31f17d870 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLocalSessionScavengingTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLocalSessionScavengingTest.java @@ -29,11 +29,14 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import javax.servlet.http.HttpSessionEvent; +import javax.servlet.http.HttpSessionListener; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.util.statistic.CounterStatistic; import org.junit.Test; /** @@ -53,6 +56,88 @@ public abstract class AbstractLocalSessionScavengingTest extends AbstractTestBas e.printStackTrace(); } } + + + public static class SessionListener implements HttpSessionListener + { + public CounterStatistic count = new CounterStatistic(); + /** + * @see javax.servlet.http.HttpSessionListener#sessionCreated(javax.servlet.http.HttpSessionEvent) + */ + @Override + public void sessionCreated(HttpSessionEvent se) + { + count.increment(); + } + + /** + * @see javax.servlet.http.HttpSessionListener#sessionDestroyed(javax.servlet.http.HttpSessionEvent) + */ + @Override + public void sessionDestroyed(HttpSessionEvent se) + { + count.decrement(); + } + } + + @Test + public void testNoScavenging() throws Exception + { + String contextPath = ""; + String servletMapping = "/server"; + int inactivePeriod = 3; + int scavengePeriod = 0; + AbstractTestServer server1 = createServer(0, inactivePeriod, scavengePeriod, SessionCache.NEVER_EVICT); + ServletContextHandler context1 = server1.addContext(contextPath); + context1.addServlet(TestServlet.class, servletMapping); + SessionListener listener = new SessionListener(); + context1.getSessionHandler().addEventListener(listener); + + + try + { + server1.start(); + int port1 = server1.getPort(); + + HttpClient client = new HttpClient(); + client.start(); + try + { + String url = "http://localhost:" + port1 + contextPath + servletMapping; + + + // Create the session + ContentResponse response1 = client.GET(url + "?action=init"); + assertEquals(HttpServletResponse.SC_OK,response1.getStatus()); + String sessionCookie = response1.getHeaders().get("Set-Cookie"); + assertTrue(sessionCookie != null); + // Mangle the cookie, replacing Path with $Path, etc. + sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); + SessionHandler m1 = context1.getSessionHandler(); + assertEquals(1, m1.getSessionsCreated()); + + + // Wait a while to ensure that the session should have expired, if the + //scavenger was running + pause(2*inactivePeriod); + + assertEquals(1, m1.getSessionsCreated()); + + + //check a session removed listener did not get called + assertEquals(1, listener.count.getCurrent()); + } + finally + { + client.stop(); + } + } + finally + { + server1.stop(); + } + } + @Test public void testLocalSessionsScavenging() throws Exception diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractTestBase.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractTestBase.java index 6b1f225b6da..07be9f8f5b1 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractTestBase.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractTestBase.java @@ -26,5 +26,5 @@ package org.eclipse.jetty.server.session; */ public abstract class AbstractTestBase { - public abstract AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy); + public abstract AbstractTestServer createServer(int port, int maxInactive, int scavengeInterval, int evictionPolicy) throws Exception; } diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractTestServer.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractTestServer.java index 065f4daddd2..8581ed9a583 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractTestServer.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractTestServer.java @@ -25,12 +25,6 @@ import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.webapp.WebAppContext; - -/** - * AbstractTestServer - * - * - */ public abstract class AbstractTestServer { public static int DEFAULT_MAX_INACTIVE = 30; @@ -38,7 +32,7 @@ public abstract class AbstractTestServer public static int DEFAULT_EVICTIONPOLICY = SessionCache.NEVER_EVICT; protected static int __workers=0; - + protected final Server _server; protected final int _maxInactivePeriod; protected final int _evictionPolicy; @@ -48,8 +42,6 @@ public abstract class AbstractTestServer private HouseKeeper _housekeeper; protected Object _config; - - public static String extractSessionId (String sessionCookie) { if (sessionCookie == null) @@ -66,14 +58,12 @@ public abstract class AbstractTestServer return sessionCookie; } - - - public AbstractTestServer(int port, int maxInactivePeriod, int scavengePeriod, int evictionPolicy) + public AbstractTestServer(int port, int maxInactivePeriod, int scavengePeriod, int evictionPolicy) throws Exception { this (port, maxInactivePeriod, scavengePeriod, evictionPolicy, null); } - public AbstractTestServer(int port, int maxInactivePeriod, int scavengePeriod, int evictionPolicy, Object cfg) + public AbstractTestServer(int port, int maxInactivePeriod, int scavengePeriod, int evictionPolicy, Object cfg) throws Exception { _server = new Server(port); _maxInactivePeriod = maxInactivePeriod; @@ -88,12 +78,7 @@ public abstract class AbstractTestServer _housekeeper.setIntervalSec(_scavengePeriod); ((DefaultSessionIdManager)_sessionIdManager).setSessionHouseKeeper(_housekeeper); } - - - /** - * @return - */ public SessionIdManager newSessionIdManager() { DefaultSessionIdManager idManager = new DefaultSessionIdManager(getServer()); @@ -101,10 +86,8 @@ public abstract class AbstractTestServer return idManager; } - public abstract SessionHandler newSessionHandler(); - public void start() throws Exception { // server -> contexts collection -> context handler -> session handler -> servlet handler @@ -139,11 +122,6 @@ public abstract class AbstractTestServer _server.stop(); } - public void join() throws Exception - { - _server.join(); - } - public WebAppContext addWebAppContext(String warPath, String contextPath) { WebAppContext context = new WebAppContext(_contexts, warPath, contextPath);