]> WPIA git - gigi.git/commitdiff
updating jetty to jetty-9.2.16.v2016040
authorFelix Dörre <felix@dogcraft.de>
Thu, 30 Jun 2016 10:58:08 +0000 (12:58 +0200)
committerFelix Dörre <felix@dogcraft.de>
Thu, 30 Jun 2016 15:14:16 +0000 (17:14 +0200)
Change-Id: I5b14fada113d25f8e08be400b47a335dbe70e02f

343 files changed:
lib/jetty/org/eclipse/jetty/http/DateGenerator.java
lib/jetty/org/eclipse/jetty/http/DateParser.java
lib/jetty/org/eclipse/jetty/http/HttpContent.java
lib/jetty/org/eclipse/jetty/http/HttpCookie.java
lib/jetty/org/eclipse/jetty/http/HttpField.java
lib/jetty/org/eclipse/jetty/http/HttpFields.java
lib/jetty/org/eclipse/jetty/http/HttpGenerator.java
lib/jetty/org/eclipse/jetty/http/HttpHeader.java
lib/jetty/org/eclipse/jetty/http/HttpHeaderValue.java
lib/jetty/org/eclipse/jetty/http/HttpMethod.java
lib/jetty/org/eclipse/jetty/http/HttpParser.java
lib/jetty/org/eclipse/jetty/http/HttpScheme.java
lib/jetty/org/eclipse/jetty/http/HttpStatus.java
lib/jetty/org/eclipse/jetty/http/HttpTester.java
lib/jetty/org/eclipse/jetty/http/HttpTokens.java
lib/jetty/org/eclipse/jetty/http/HttpURI.java
lib/jetty/org/eclipse/jetty/http/HttpVersion.java
lib/jetty/org/eclipse/jetty/http/MimeTypes.java
lib/jetty/org/eclipse/jetty/http/PathMap.java
lib/jetty/org/eclipse/jetty/http/mime.properties
lib/jetty/org/eclipse/jetty/http/package-info.java
lib/jetty/org/eclipse/jetty/http/pathmap/MappedResource.java [new file with mode: 0644]
lib/jetty/org/eclipse/jetty/http/pathmap/PathMappings.java [new file with mode: 0644]
lib/jetty/org/eclipse/jetty/http/pathmap/PathSpec.java [new file with mode: 0644]
lib/jetty/org/eclipse/jetty/http/pathmap/PathSpecGroup.java [new file with mode: 0644]
lib/jetty/org/eclipse/jetty/http/pathmap/PathSpecSet.java [new file with mode: 0644]
lib/jetty/org/eclipse/jetty/http/pathmap/RegexPathSpec.java [new file with mode: 0644]
lib/jetty/org/eclipse/jetty/http/pathmap/ServletPathSpec.java [new file with mode: 0644]
lib/jetty/org/eclipse/jetty/http/pathmap/UriTemplatePathSpec.java [new file with mode: 0644]
lib/jetty/org/eclipse/jetty/io/AbstractConnection.java
lib/jetty/org/eclipse/jetty/io/AbstractEndPoint.java
lib/jetty/org/eclipse/jetty/io/ArrayByteBufferPool.java
lib/jetty/org/eclipse/jetty/io/ByteArrayEndPoint.java
lib/jetty/org/eclipse/jetty/io/ByteBufferPool.java
lib/jetty/org/eclipse/jetty/io/ChannelEndPoint.java
lib/jetty/org/eclipse/jetty/io/ClientConnectionFactory.java
lib/jetty/org/eclipse/jetty/io/Connection.java
lib/jetty/org/eclipse/jetty/io/EndPoint.java
lib/jetty/org/eclipse/jetty/io/EofException.java
lib/jetty/org/eclipse/jetty/io/FillInterest.java
lib/jetty/org/eclipse/jetty/io/IdleTimeout.java
lib/jetty/org/eclipse/jetty/io/LeakTrackingByteBufferPool.java
lib/jetty/org/eclipse/jetty/io/MappedByteBufferPool.java
lib/jetty/org/eclipse/jetty/io/NegotiatingClientConnection.java
lib/jetty/org/eclipse/jetty/io/NegotiatingClientConnectionFactory.java
lib/jetty/org/eclipse/jetty/io/NetworkTrafficListener.java
lib/jetty/org/eclipse/jetty/io/NetworkTrafficSelectChannelEndPoint.java
lib/jetty/org/eclipse/jetty/io/RuntimeIOException.java
lib/jetty/org/eclipse/jetty/io/SelectChannelEndPoint.java
lib/jetty/org/eclipse/jetty/io/SelectorManager.java
lib/jetty/org/eclipse/jetty/io/UncheckedPrintWriter.java
lib/jetty/org/eclipse/jetty/io/WriteFlusher.java
lib/jetty/org/eclipse/jetty/io/WriterOutputStream.java
lib/jetty/org/eclipse/jetty/io/package-info.java
lib/jetty/org/eclipse/jetty/io/ssl/SslClientConnectionFactory.java
lib/jetty/org/eclipse/jetty/io/ssl/SslConnection.java
lib/jetty/org/eclipse/jetty/io/ssl/package-info.java
lib/jetty/org/eclipse/jetty/security/AbstractUserAuthentication.java
lib/jetty/org/eclipse/jetty/security/Authenticator.java
lib/jetty/org/eclipse/jetty/security/ConstraintAware.java
lib/jetty/org/eclipse/jetty/security/ConstraintMapping.java
lib/jetty/org/eclipse/jetty/security/ConstraintSecurityHandler.java
lib/jetty/org/eclipse/jetty/security/CrossContextPsuedoSession.java
lib/jetty/org/eclipse/jetty/security/DefaultAuthenticatorFactory.java
lib/jetty/org/eclipse/jetty/security/DefaultIdentityService.java
lib/jetty/org/eclipse/jetty/security/DefaultUserIdentity.java
lib/jetty/org/eclipse/jetty/security/HashCrossContextPsuedoSession.java
lib/jetty/org/eclipse/jetty/security/HashLoginService.java
lib/jetty/org/eclipse/jetty/security/IdentityService.java
lib/jetty/org/eclipse/jetty/security/JDBCLoginService.java
lib/jetty/org/eclipse/jetty/security/LoginService.java
lib/jetty/org/eclipse/jetty/security/MappedLoginService.java
lib/jetty/org/eclipse/jetty/security/PropertyUserStore.java
lib/jetty/org/eclipse/jetty/security/RoleInfo.java
lib/jetty/org/eclipse/jetty/security/RoleRunAsToken.java
lib/jetty/org/eclipse/jetty/security/RunAsToken.java
lib/jetty/org/eclipse/jetty/security/SecurityHandler.java
lib/jetty/org/eclipse/jetty/security/ServerAuthException.java
lib/jetty/org/eclipse/jetty/security/SpnegoLoginService.java
lib/jetty/org/eclipse/jetty/security/SpnegoUserIdentity.java
lib/jetty/org/eclipse/jetty/security/SpnegoUserPrincipal.java
lib/jetty/org/eclipse/jetty/security/UserAuthentication.java
lib/jetty/org/eclipse/jetty/security/UserDataConstraint.java
lib/jetty/org/eclipse/jetty/security/authentication/BasicAuthenticator.java
lib/jetty/org/eclipse/jetty/security/authentication/ClientCertAuthenticator.java
lib/jetty/org/eclipse/jetty/security/authentication/DeferredAuthentication.java
lib/jetty/org/eclipse/jetty/security/authentication/DigestAuthenticator.java
lib/jetty/org/eclipse/jetty/security/authentication/FormAuthenticator.java
lib/jetty/org/eclipse/jetty/security/authentication/LoginAuthenticator.java
lib/jetty/org/eclipse/jetty/security/authentication/LoginCallback.java
lib/jetty/org/eclipse/jetty/security/authentication/LoginCallbackImpl.java
lib/jetty/org/eclipse/jetty/security/authentication/SessionAuthentication.java
lib/jetty/org/eclipse/jetty/security/authentication/SpnegoAuthenticator.java
lib/jetty/org/eclipse/jetty/security/authentication/package-info.java
lib/jetty/org/eclipse/jetty/security/package-info.java
lib/jetty/org/eclipse/jetty/server/AbstractConnectionFactory.java
lib/jetty/org/eclipse/jetty/server/AbstractConnector.java
lib/jetty/org/eclipse/jetty/server/AbstractNCSARequestLog.java
lib/jetty/org/eclipse/jetty/server/AbstractNetworkConnector.java
lib/jetty/org/eclipse/jetty/server/AsyncContextEvent.java
lib/jetty/org/eclipse/jetty/server/AsyncContextState.java
lib/jetty/org/eclipse/jetty/server/AsyncNCSARequestLog.java
lib/jetty/org/eclipse/jetty/server/Authentication.java
lib/jetty/org/eclipse/jetty/server/ByteBufferQueuedHttpInput.java
lib/jetty/org/eclipse/jetty/server/ClassLoaderDump.java
lib/jetty/org/eclipse/jetty/server/ConnectionFactory.java
lib/jetty/org/eclipse/jetty/server/Connector.java
lib/jetty/org/eclipse/jetty/server/ConnectorStatistics.java
lib/jetty/org/eclipse/jetty/server/CookieCutter.java
lib/jetty/org/eclipse/jetty/server/Dispatcher.java
lib/jetty/org/eclipse/jetty/server/EncodingHttpWriter.java
lib/jetty/org/eclipse/jetty/server/ForwardedRequestCustomizer.java
lib/jetty/org/eclipse/jetty/server/Handler.java
lib/jetty/org/eclipse/jetty/server/HandlerContainer.java
lib/jetty/org/eclipse/jetty/server/HomeBaseWarning.java [new file with mode: 0644]
lib/jetty/org/eclipse/jetty/server/HostHeaderCustomizer.java
lib/jetty/org/eclipse/jetty/server/HttpChannel.java
lib/jetty/org/eclipse/jetty/server/HttpChannelState.java
lib/jetty/org/eclipse/jetty/server/HttpConfiguration.java
lib/jetty/org/eclipse/jetty/server/HttpConnection.java
lib/jetty/org/eclipse/jetty/server/HttpConnectionFactory.java
lib/jetty/org/eclipse/jetty/server/HttpInput.java
lib/jetty/org/eclipse/jetty/server/HttpInputOverHTTP.java
lib/jetty/org/eclipse/jetty/server/HttpOutput.java
lib/jetty/org/eclipse/jetty/server/HttpTransport.java
lib/jetty/org/eclipse/jetty/server/HttpWriter.java
lib/jetty/org/eclipse/jetty/server/InclusiveByteRange.java
lib/jetty/org/eclipse/jetty/server/Iso88591HttpWriter.java
lib/jetty/org/eclipse/jetty/server/LocalConnector.java
lib/jetty/org/eclipse/jetty/server/LowResourceMonitor.java
lib/jetty/org/eclipse/jetty/server/NCSARequestLog.java
lib/jetty/org/eclipse/jetty/server/NegotiatingServerConnection.java
lib/jetty/org/eclipse/jetty/server/NegotiatingServerConnectionFactory.java
lib/jetty/org/eclipse/jetty/server/NetworkConnector.java
lib/jetty/org/eclipse/jetty/server/NetworkTrafficServerConnector.java
lib/jetty/org/eclipse/jetty/server/QueuedHttpInput.java
lib/jetty/org/eclipse/jetty/server/QuietServletException.java
lib/jetty/org/eclipse/jetty/server/Request.java
lib/jetty/org/eclipse/jetty/server/RequestLog.java
lib/jetty/org/eclipse/jetty/server/ResourceCache.java
lib/jetty/org/eclipse/jetty/server/Response.java
lib/jetty/org/eclipse/jetty/server/SecureRequestCustomizer.java
lib/jetty/org/eclipse/jetty/server/Server.java
lib/jetty/org/eclipse/jetty/server/ServerConnector.java
lib/jetty/org/eclipse/jetty/server/ServletRequestHttpWrapper.java
lib/jetty/org/eclipse/jetty/server/ServletResponseHttpWrapper.java
lib/jetty/org/eclipse/jetty/server/SessionIdManager.java
lib/jetty/org/eclipse/jetty/server/SessionManager.java
lib/jetty/org/eclipse/jetty/server/ShutdownMonitor.java
lib/jetty/org/eclipse/jetty/server/SslConnectionFactory.java
lib/jetty/org/eclipse/jetty/server/UserIdentity.java
lib/jetty/org/eclipse/jetty/server/Utf8HttpWriter.java
lib/jetty/org/eclipse/jetty/server/handler/AbstractHandler.java
lib/jetty/org/eclipse/jetty/server/handler/AbstractHandlerContainer.java
lib/jetty/org/eclipse/jetty/server/handler/AllowSymLinkAliasChecker.java
lib/jetty/org/eclipse/jetty/server/handler/AsyncDelayHandler.java [new file with mode: 0644]
lib/jetty/org/eclipse/jetty/server/handler/ContextHandler.java
lib/jetty/org/eclipse/jetty/server/handler/ContextHandlerCollection.java
lib/jetty/org/eclipse/jetty/server/handler/DebugHandler.java
lib/jetty/org/eclipse/jetty/server/handler/DefaultHandler.java
lib/jetty/org/eclipse/jetty/server/handler/ErrorHandler.java
lib/jetty/org/eclipse/jetty/server/handler/HandlerCollection.java
lib/jetty/org/eclipse/jetty/server/handler/HandlerList.java
lib/jetty/org/eclipse/jetty/server/handler/HandlerWrapper.java
lib/jetty/org/eclipse/jetty/server/handler/HotSwapHandler.java
lib/jetty/org/eclipse/jetty/server/handler/IPAccessHandler.java
lib/jetty/org/eclipse/jetty/server/handler/IdleTimeoutHandler.java
lib/jetty/org/eclipse/jetty/server/handler/MovedContextHandler.java
lib/jetty/org/eclipse/jetty/server/handler/RequestLogHandler.java
lib/jetty/org/eclipse/jetty/server/handler/ResourceHandler.java
lib/jetty/org/eclipse/jetty/server/handler/ScopedHandler.java
lib/jetty/org/eclipse/jetty/server/handler/SecuredRedirectHandler.java [new file with mode: 0644]
lib/jetty/org/eclipse/jetty/server/handler/ShutdownHandler.java
lib/jetty/org/eclipse/jetty/server/handler/StatisticsHandler.java
lib/jetty/org/eclipse/jetty/server/handler/package-info.java
lib/jetty/org/eclipse/jetty/server/nio/NetworkTrafficSelectChannelConnector.java
lib/jetty/org/eclipse/jetty/server/nio/package-info.java
lib/jetty/org/eclipse/jetty/server/package-info.java
lib/jetty/org/eclipse/jetty/server/session/AbstractSession.java
lib/jetty/org/eclipse/jetty/server/session/AbstractSessionIdManager.java
lib/jetty/org/eclipse/jetty/server/session/AbstractSessionManager.java
lib/jetty/org/eclipse/jetty/server/session/HashSessionIdManager.java
lib/jetty/org/eclipse/jetty/server/session/HashSessionManager.java
lib/jetty/org/eclipse/jetty/server/session/HashedSession.java
lib/jetty/org/eclipse/jetty/server/session/JDBCSessionIdManager.java
lib/jetty/org/eclipse/jetty/server/session/JDBCSessionManager.java
lib/jetty/org/eclipse/jetty/server/session/MemSession.java
lib/jetty/org/eclipse/jetty/server/session/SessionHandler.java
lib/jetty/org/eclipse/jetty/server/session/package-info.java
lib/jetty/org/eclipse/jetty/servlet/BaseHolder.java
lib/jetty/org/eclipse/jetty/servlet/DefaultServlet.java
lib/jetty/org/eclipse/jetty/servlet/ErrorPageErrorHandler.java
lib/jetty/org/eclipse/jetty/servlet/FilterHolder.java
lib/jetty/org/eclipse/jetty/servlet/FilterMapping.java
lib/jetty/org/eclipse/jetty/servlet/Holder.java
lib/jetty/org/eclipse/jetty/servlet/Invoker.java
lib/jetty/org/eclipse/jetty/servlet/JspPropertyGroupServlet.java
lib/jetty/org/eclipse/jetty/servlet/ListenerHolder.java
lib/jetty/org/eclipse/jetty/servlet/NoJspServlet.java
lib/jetty/org/eclipse/jetty/servlet/ServletContextHandler.java
lib/jetty/org/eclipse/jetty/servlet/ServletHandler.java
lib/jetty/org/eclipse/jetty/servlet/ServletHolder.java
lib/jetty/org/eclipse/jetty/servlet/ServletMapping.java
lib/jetty/org/eclipse/jetty/servlet/ServletTester.java
lib/jetty/org/eclipse/jetty/servlet/StatisticsServlet.java
lib/jetty/org/eclipse/jetty/servlet/listener/ELContextCleaner.java
lib/jetty/org/eclipse/jetty/servlet/listener/IntrospectorCleaner.java
lib/jetty/org/eclipse/jetty/servlet/listener/package-info.java
lib/jetty/org/eclipse/jetty/servlet/package-info.java
lib/jetty/org/eclipse/jetty/util/AbstractTrie.java
lib/jetty/org/eclipse/jetty/util/ArrayQueue.java
lib/jetty/org/eclipse/jetty/util/ArrayTernaryTrie.java
lib/jetty/org/eclipse/jetty/util/ArrayTrie.java
lib/jetty/org/eclipse/jetty/util/ArrayUtil.java
lib/jetty/org/eclipse/jetty/util/Atomics.java
lib/jetty/org/eclipse/jetty/util/Attributes.java
lib/jetty/org/eclipse/jetty/util/AttributesMap.java
lib/jetty/org/eclipse/jetty/util/B64Code.java
lib/jetty/org/eclipse/jetty/util/BlockingArrayQueue.java
lib/jetty/org/eclipse/jetty/util/BlockingCallback.java
lib/jetty/org/eclipse/jetty/util/BufferUtil.java
lib/jetty/org/eclipse/jetty/util/ByteArrayISO8859Writer.java
lib/jetty/org/eclipse/jetty/util/ByteArrayOutputStream2.java
lib/jetty/org/eclipse/jetty/util/Callback.java
lib/jetty/org/eclipse/jetty/util/ClassLoadingObjectInputStream.java
lib/jetty/org/eclipse/jetty/util/CompletableCallback.java
lib/jetty/org/eclipse/jetty/util/ConcurrentArrayQueue.java
lib/jetty/org/eclipse/jetty/util/ConcurrentHashSet.java
lib/jetty/org/eclipse/jetty/util/CountingCallback.java [new file with mode: 0644]
lib/jetty/org/eclipse/jetty/util/DateCache.java
lib/jetty/org/eclipse/jetty/util/Fields.java
lib/jetty/org/eclipse/jetty/util/ForkInvoker.java [deleted file]
lib/jetty/org/eclipse/jetty/util/FutureCallback.java
lib/jetty/org/eclipse/jetty/util/FuturePromise.java
lib/jetty/org/eclipse/jetty/util/HostMap.java
lib/jetty/org/eclipse/jetty/util/HttpCookieStore.java
lib/jetty/org/eclipse/jetty/util/IO.java
lib/jetty/org/eclipse/jetty/util/IPAddressMap.java
lib/jetty/org/eclipse/jetty/util/IncludeExclude.java [new file with mode: 0644]
lib/jetty/org/eclipse/jetty/util/IntrospectionUtil.java
lib/jetty/org/eclipse/jetty/util/IteratingCallback.java
lib/jetty/org/eclipse/jetty/util/IteratingNestedCallback.java
lib/jetty/org/eclipse/jetty/util/Jetty.java
lib/jetty/org/eclipse/jetty/util/LazyList.java
lib/jetty/org/eclipse/jetty/util/LeakDetector.java
lib/jetty/org/eclipse/jetty/util/Loader.java
lib/jetty/org/eclipse/jetty/util/MemoryUtils.java
lib/jetty/org/eclipse/jetty/util/MultiException.java
lib/jetty/org/eclipse/jetty/util/MultiMap.java
lib/jetty/org/eclipse/jetty/util/MultiPartInputStreamParser.java
lib/jetty/org/eclipse/jetty/util/MultiPartOutputStream.java
lib/jetty/org/eclipse/jetty/util/MultiPartWriter.java
lib/jetty/org/eclipse/jetty/util/PatternMatcher.java
lib/jetty/org/eclipse/jetty/util/Predicate.java [new file with mode: 0644]
lib/jetty/org/eclipse/jetty/util/Promise.java
lib/jetty/org/eclipse/jetty/util/QuotedStringTokenizer.java
lib/jetty/org/eclipse/jetty/util/ReadLineInputStream.java
lib/jetty/org/eclipse/jetty/util/RegexSet.java [new file with mode: 0644]
lib/jetty/org/eclipse/jetty/util/RolloverFileOutputStream.java
lib/jetty/org/eclipse/jetty/util/Scanner.java
lib/jetty/org/eclipse/jetty/util/SharedBlockingCallback.java
lib/jetty/org/eclipse/jetty/util/SocketAddressResolver.java
lib/jetty/org/eclipse/jetty/util/StringUtil.java
lib/jetty/org/eclipse/jetty/util/TreeTrie.java
lib/jetty/org/eclipse/jetty/util/Trie.java
lib/jetty/org/eclipse/jetty/util/TypeUtil.java
lib/jetty/org/eclipse/jetty/util/URIUtil.java
lib/jetty/org/eclipse/jetty/util/Uptime.java [new file with mode: 0644]
lib/jetty/org/eclipse/jetty/util/UrlEncoded.java
lib/jetty/org/eclipse/jetty/util/Utf8Appendable.java
lib/jetty/org/eclipse/jetty/util/Utf8LineParser.java
lib/jetty/org/eclipse/jetty/util/Utf8StringBuffer.java
lib/jetty/org/eclipse/jetty/util/Utf8StringBuilder.java
lib/jetty/org/eclipse/jetty/util/annotation/ManagedAttribute.java
lib/jetty/org/eclipse/jetty/util/annotation/ManagedObject.java
lib/jetty/org/eclipse/jetty/util/annotation/ManagedOperation.java
lib/jetty/org/eclipse/jetty/util/annotation/Name.java
lib/jetty/org/eclipse/jetty/util/annotation/package-info.java
lib/jetty/org/eclipse/jetty/util/component/AbstractLifeCycle.java
lib/jetty/org/eclipse/jetty/util/component/Container.java
lib/jetty/org/eclipse/jetty/util/component/ContainerLifeCycle.java
lib/jetty/org/eclipse/jetty/util/component/Destroyable.java
lib/jetty/org/eclipse/jetty/util/component/Dumpable.java
lib/jetty/org/eclipse/jetty/util/component/FileDestroyable.java
lib/jetty/org/eclipse/jetty/util/component/FileNoticeLifeCycleListener.java
lib/jetty/org/eclipse/jetty/util/component/Graceful.java
lib/jetty/org/eclipse/jetty/util/component/LifeCycle.java
lib/jetty/org/eclipse/jetty/util/component/package-info.java
lib/jetty/org/eclipse/jetty/util/log/AbstractLogger.java
lib/jetty/org/eclipse/jetty/util/log/JavaUtilLog.java
lib/jetty/org/eclipse/jetty/util/log/Log.java
lib/jetty/org/eclipse/jetty/util/log/Logger.java
lib/jetty/org/eclipse/jetty/util/log/LoggerLog.java
lib/jetty/org/eclipse/jetty/util/log/StacklessLogging.java
lib/jetty/org/eclipse/jetty/util/log/StdErrLog.java
lib/jetty/org/eclipse/jetty/util/log/package-info.java
lib/jetty/org/eclipse/jetty/util/package-info.java
lib/jetty/org/eclipse/jetty/util/preventers/AWTLeakPreventer.java
lib/jetty/org/eclipse/jetty/util/preventers/AbstractLeakPreventer.java
lib/jetty/org/eclipse/jetty/util/preventers/AppContextLeakPreventer.java
lib/jetty/org/eclipse/jetty/util/preventers/DOMLeakPreventer.java
lib/jetty/org/eclipse/jetty/util/preventers/DriverManagerLeakPreventer.java
lib/jetty/org/eclipse/jetty/util/preventers/GCThreadLeakPreventer.java
lib/jetty/org/eclipse/jetty/util/preventers/Java2DLeakPreventer.java
lib/jetty/org/eclipse/jetty/util/preventers/LDAPLeakPreventer.java
lib/jetty/org/eclipse/jetty/util/preventers/LoginConfigurationLeakPreventer.java
lib/jetty/org/eclipse/jetty/util/preventers/SecurityProviderLeakPreventer.java
lib/jetty/org/eclipse/jetty/util/preventers/package-info.java
lib/jetty/org/eclipse/jetty/util/resource/BadResource.java
lib/jetty/org/eclipse/jetty/util/resource/EmptyResource.java
lib/jetty/org/eclipse/jetty/util/resource/FileResource.java
lib/jetty/org/eclipse/jetty/util/resource/JarFileResource.java
lib/jetty/org/eclipse/jetty/util/resource/JarResource.java
lib/jetty/org/eclipse/jetty/util/resource/PathResource.java [new file with mode: 0644]
lib/jetty/org/eclipse/jetty/util/resource/Resource.java
lib/jetty/org/eclipse/jetty/util/resource/ResourceCollection.java
lib/jetty/org/eclipse/jetty/util/resource/ResourceFactory.java
lib/jetty/org/eclipse/jetty/util/resource/URLResource.java
lib/jetty/org/eclipse/jetty/util/resource/package-info.java
lib/jetty/org/eclipse/jetty/util/security/CertificateUtils.java
lib/jetty/org/eclipse/jetty/util/security/CertificateValidator.java
lib/jetty/org/eclipse/jetty/util/security/Constraint.java
lib/jetty/org/eclipse/jetty/util/security/Credential.java
lib/jetty/org/eclipse/jetty/util/security/Password.java
lib/jetty/org/eclipse/jetty/util/security/package-info.java
lib/jetty/org/eclipse/jetty/util/ssl/AliasedX509ExtendedKeyManager.java
lib/jetty/org/eclipse/jetty/util/ssl/AliasedX509KeyManager.java
lib/jetty/org/eclipse/jetty/util/ssl/SslContextFactory.java
lib/jetty/org/eclipse/jetty/util/ssl/package-info.java
lib/jetty/org/eclipse/jetty/util/statistic/CounterStatistic.java
lib/jetty/org/eclipse/jetty/util/statistic/SampleStatistic.java
lib/jetty/org/eclipse/jetty/util/statistic/package-info.java
lib/jetty/org/eclipse/jetty/util/thread/ExecutorThreadPool.java
lib/jetty/org/eclipse/jetty/util/thread/NonBlockingThread.java
lib/jetty/org/eclipse/jetty/util/thread/QueuedThreadPool.java
lib/jetty/org/eclipse/jetty/util/thread/ScheduledExecutorScheduler.java
lib/jetty/org/eclipse/jetty/util/thread/Scheduler.java
lib/jetty/org/eclipse/jetty/util/thread/ShutdownThread.java
lib/jetty/org/eclipse/jetty/util/thread/SpinLock.java [new file with mode: 0644]
lib/jetty/org/eclipse/jetty/util/thread/Sweeper.java [new file with mode: 0644]
lib/jetty/org/eclipse/jetty/util/thread/ThreadPool.java
lib/jetty/org/eclipse/jetty/util/thread/TimerScheduler.java
lib/jetty/org/eclipse/jetty/util/thread/package-info.java

index 3ecaad8cc896b35a79a2ad3700645ef2d97c48b8..e38d3c690e9aaa80690fa35f2b4ccd6d63ef4278 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 1ede4cec1809ec78be58954ff740ede4446745b6..f181ce1dc257c4c286752d0532213747a9acf4ac 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index ebae56d15cb587886cadebf8702d3cde7863e92a..ba098805406521b8ba649b5e4a01099e5a32612b 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -168,5 +168,11 @@ public interface HttpContent
         {
             _resource.close();
         }
+        
+        @Override
+        public String toString()
+        {
+            return String.format("%s@%x{r=%s}",this.getClass().getSimpleName(),hashCode(),_resource);
+        }
     }
 }
index 1a2426b112cbd7eb9d48a7f873b0b7d9e9311414..2d769df6ff61e2fefbf9e008d715ebf6f112b537 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 50f29b1ec18e32a086b0238ea27766c984066833..55ab65cac13c20cdca6b1e49fcc93423a7b226d0 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index d474227453062d6606ef0c614ad4f6a2d6248093..6bec4d97d38c1ea19c56b0268acd90beb0a91446 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -171,6 +171,17 @@ public class HttpFields implements Iterable<HttpField>
 
         return false;
     }
+
+    public boolean contains(HttpHeader header)
+    {
+        for (int i=0;i<_fields.size();i++)
+        {
+            HttpField f=_fields.get(i);
+            if (f.getHeader()==header)
+                return true;
+        }
+        return false;
+    }
     
     public boolean containsKey(String name)
     {
@@ -182,7 +193,8 @@ public class HttpFields implements Iterable<HttpField>
         }
         return false;
     }
-
+    
+    
     public String getStringField(HttpHeader header)
     {
         return getStringField(header.asString());
index a51e4ba7b85d0e9901b2ea214eb5a52211d97bc0..6f7ead3ec358d485b2ec641f58bceb21ec72500a 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -23,6 +23,8 @@ import java.nio.BufferOverflowException;
 import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
 
 import org.eclipse.jetty.http.HttpTokens.EndOfContent;
 import org.eclipse.jetty.util.BufferUtil;
@@ -70,8 +72,8 @@ public class HttpGenerator
     private final int _send;
     private final static int SEND_SERVER = 0x01;
     private final static int SEND_XPOWEREDBY = 0x02;
-
-
+    private final static Set<String> __assumedContentMethods = new HashSet<>(Arrays.asList(new String[]{HttpMethod.POST.asString(),HttpMethod.PUT.asString()}));
+  
     /* ------------------------------------------------------------------------------- */
     public static void setJettyVersion(String serverVersion)
     {
@@ -158,6 +160,12 @@ public class HttpGenerator
         return _endOfContent==EndOfContent.CHUNKED_CONTENT;
     }
 
+    /* ------------------------------------------------------------ */
+    public boolean isNoContent()
+    {
+        return _noContent;
+    }
+    
     /* ------------------------------------------------------------ */
     public void setPersistent(boolean persistent)
     {
@@ -287,7 +295,8 @@ public class HttpGenerator
             {
                 if (BufferUtil.hasContent(content))
                 {
-                    LOG.debug("discarding content in COMPLETING");
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("discarding content in COMPLETING");
                     BufferUtil.clear(content);
                 }
 
@@ -310,7 +319,8 @@ public class HttpGenerator
             case END:
                 if (BufferUtil.hasContent(content))
                 {
-                    LOG.debug("discarding content in COMPLETING");
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("discarding content in COMPLETING");
                     BufferUtil.clear(content);
                 }
                 return Result.DONE;
@@ -436,7 +446,8 @@ public class HttpGenerator
             {
                 if (BufferUtil.hasContent(content))
                 {
-                    LOG.debug("discarding content in COMPLETING");
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("discarding content in COMPLETING");
                     BufferUtil.clear(content);
                 }
 
@@ -462,7 +473,8 @@ public class HttpGenerator
             case END:
                 if (BufferUtil.hasContent(content))
                 {
-                    LOG.debug("discarding content in COMPLETING");
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("discarding content in COMPLETING");
                     BufferUtil.clear(content);
                 }
                 return Result.DONE;
@@ -621,7 +633,7 @@ public class HttpGenerator
 
                         if (values[0]==null)
                         {
-                            split = field.getValue().split("\\s*,\\s*");
+                            split = StringUtil.csvSplit(field.getValue());
                             if (split.length>0)
                             {
                                 values=new HttpHeaderValue[split.length];
@@ -735,12 +747,17 @@ public class HttpGenerator
                     long content_length = _contentPrepared+BufferUtil.length(content);
 
                     // Do we need to tell the headers about it
-                    if ((response!=null || content_length>0 || content_type ) && !_noContent)
+                    if (content_length>0)
                     {
                         header.put(HttpHeader.CONTENT_LENGTH.getBytesColonSpace());
                         BufferUtil.putDecLong(header, content_length);
                         header.put(HttpTokens.CRLF);
                     }
+                    else if (!_noContent)
+                    {
+                        if (content_type || response!=null || (request!=null && __assumedContentMethods.contains(request.getMethod())))
+                            header.put(CONTENT_LENGTH_0);
+                    }
                 }
                 else
                 {
@@ -757,19 +774,21 @@ public class HttpGenerator
 
             case CONTENT_LENGTH:
                 long content_length = _info.getContentLength();
-                if ((response!=null || content_length>0 || content_type ) && !_noContent)
+                if (content_length>0)
                 {
-                    // known length but not actually set.
                     header.put(HttpHeader.CONTENT_LENGTH.getBytesColonSpace());
                     BufferUtil.putDecLong(header, content_length);
                     header.put(HttpTokens.CRLF);
                 }
+                else if (!_noContent)
+                {
+                    if (content_type || response!=null || (request!=null && __assumedContentMethods.contains(request.getMethod())))
+                        header.put(CONTENT_LENGTH_0);
+                }
                 break;
 
             case NO_CONTENT:
-                if (response!=null && status >= 200 && status != 204 && status != 304)
-                    header.put(CONTENT_LENGTH_0);
-                break;
+                throw new IllegalStateException();
 
             case EOF_CONTENT:
                 _persistent = request!=null;
@@ -1042,7 +1061,7 @@ public class HttpGenerator
             char c=s.charAt(i);
             
             if (c<0 || c>0xff || c=='\r' || c=='\n')
-                buffer.put((byte)'?');
+                buffer.put((byte)' ');
             else
                 buffer.put((byte)(0xff&c));
         }
index ab0ddcf3b0f156ab2c30e3c0e21172a7bf1cc105..a62f5f2792ca58dc7911ce3d10a91604affdaba5 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 8338a3221589a6afb6e6fe1b4c603ba38df4d783..71301003ee671ec7f9602ef877b58c1b6f37c126 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 8a2626803a715ba67562907db6c5e46d23fe1958..1d2eeda0e53066d46288681df55b5afc35c6d777 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -39,11 +39,12 @@ public enum HttpMethod
     TRACE,
     CONNECT,
     MOVE,
-    PROXY;
+    PROXY,
+    PRI;
 
     /* ------------------------------------------------------------ */
     /**
-     * Optimised lookup to find a method name and trailing space in a byte array.
+     * Optimized lookup to find a method name and trailing space in a byte array.
      * @param bytes Array containing ISO-8859-1 characters
      * @param position The first valid index
      * @param limit The first non valid index
@@ -67,33 +68,35 @@ public enum HttpMethod
                     return PROXY;
                 if (bytes[position+1]=='U' && bytes[position+2]=='T' && bytes[position+3]==' ')
                     return PUT;
+                if (bytes[position+1]=='R' && bytes[position+2]=='I' && bytes[position+3]==' ')
+                    return PRI;
                 break;
             case 'H':
                 if (bytes[position+1]=='E' && bytes[position+2]=='A' && bytes[position+3]=='D' && length>=5 && bytes[position+4]==' ')
                     return HEAD;
                 break;
             case 'O':
-                if (bytes[position+1]=='O' && bytes[position+2]=='T' && bytes[position+3]=='I' && length>=8 &&
-                bytes[position+4]=='O' && bytes[position+5]=='N' && bytes[position+6]=='S' && bytes[position+7]==' ' )
+                if (bytes[position+1]=='P' && bytes[position+2]=='T' && bytes[position+3]=='I' && length>=8 &&
+                    bytes[position+4]=='O' && bytes[position+5]=='N' && bytes[position+6]=='S' && bytes[position+7]==' ' )
                     return OPTIONS;
                 break;
             case 'D':
                 if (bytes[position+1]=='E' && bytes[position+2]=='L' && bytes[position+3]=='E' && length>=7 &&
-                bytes[position+4]=='T' && bytes[position+5]=='E' && bytes[position+6]==' ' )
+                    bytes[position+4]=='T' && bytes[position+5]=='E' && bytes[position+6]==' ' )
                     return DELETE;
                 break;
             case 'T':
                 if (bytes[position+1]=='R' && bytes[position+2]=='A' && bytes[position+3]=='C' && length>=6 &&
-                bytes[position+4]=='E' && bytes[position+5]==' ' )
+                    bytes[position+4]=='E' && bytes[position+5]==' ' )
                     return TRACE;
                 break;
             case 'C':
                 if (bytes[position+1]=='O' && bytes[position+2]=='N' && bytes[position+3]=='N' && length>=8 &&
-                bytes[position+4]=='E' && bytes[position+5]=='C' && bytes[position+6]=='T' && bytes[position+7]==' ' )
+                    bytes[position+4]=='E' && bytes[position+5]=='C' && bytes[position+6]=='T' && bytes[position+7]==' ' )
                     return CONNECT;
                 break;
             case 'M':
-                if (bytes[position+1]=='O' && bytes[position+2]=='V' && bytes[position+3]=='E' &&  bytes[position+4]==' ')
+                if (bytes[position+1]=='O' && bytes[position+2]=='V' && bytes[position+3]=='E' && length>=5 && bytes[position+4]==' ')
                     return MOVE;
                 break;
 
@@ -105,17 +108,26 @@ public enum HttpMethod
 
     /* ------------------------------------------------------------ */
     /**
-     * Optimised lookup to find a method name and trailing space in a byte array.
-     * @param buffer buffer containing ISO-8859-1 characters
+     * Optimized lookup to find a method name and trailing space in a byte array.
+     * @param buffer buffer containing ISO-8859-1 characters, it is not modified.
      * @return A HttpMethod if a match or null if no easy match.
      */
     public static HttpMethod lookAheadGet(ByteBuffer buffer)
     {
         if (buffer.hasArray())
             return lookAheadGet(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.arrayOffset()+buffer.limit());
-
-        // TODO use cache and check for space
-        // return CACHE.getBest(buffer,0,buffer.remaining());
+        
+        int l = buffer.remaining();
+        if (l>=4)
+        {
+            HttpMethod m = CACHE.getBest(buffer,0,l);
+            if (m!=null)
+            {
+                int ml = m.asString().length();
+                if (l>ml && buffer.get(buffer.position()+ml)==' ')
+                    return m;
+            }
+        }
         return null;
     }
 
@@ -162,6 +174,7 @@ public enum HttpMethod
         return toString();
     }
 
+    /* ------------------------------------------------------------ */
     /**
      * Converts the given String parameter to an HttpMethod
      * @param method the String to get the equivalent HttpMethod from
index 79f1c28d90d407a0d9469e9dd26b27270442a362..e1ddee838c22aac3a90d4fb195986c294b135bca 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -18,6 +18,8 @@
 
 package org.eclipse.jetty.http;
 
+import static org.eclipse.jetty.http.HttpTokens.*;
+
 import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
 
@@ -35,7 +37,7 @@ import org.eclipse.jetty.util.log.Logger;
 /* ------------------------------------------------------------ */
 /** A Parser for HTTP 0.9, 1.0 and 1.1
  * <p>
- * This parser parses HTTP client and server messages from buffers
+ * This parser parses HTTP client and server messages from buffers
  * passed in the {@link #parseNext(ByteBuffer)} method.  The parsed
  * elements of the HTTP message are passed as event calls to the 
  * {@link HttpHandler} instance the parser is constructed with.
@@ -115,6 +117,7 @@ public class HttpParser
         CHUNK_SIZE,
         CHUNK_PARAMS,
         CHUNK,
+        CHUNK_END,
         END,
         CLOSED
     }
@@ -329,33 +332,31 @@ public class HttpParser
     }
 
     /* ------------------------------------------------------------------------------- */
-    private static class BadMessage extends Error
+    @SuppressWarnings("serial")
+    private static class BadMessageException extends RuntimeException
     {
-        private static final long serialVersionUID = 1L;
         private final int _code;
-        private final String _message;
 
-        BadMessage()
+        private BadMessageException()
         {
             this(400,null);
         }
         
-        BadMessage(int code)
+        private BadMessageException(int code)
         {
             this(code,null);
         }
         
-        BadMessage(String message)
+        private BadMessageException(String message)
         {
             this(400,message);
         }
         
-        BadMessage(int code,String message)
+        private BadMessageException(int code,String message)
         {
+            super(message);
             _code=code;
-            _message=message;
         }
-        
     }
     
     /* ------------------------------------------------------------------------------- */
@@ -365,23 +366,23 @@ public class HttpParser
         
         if (_cr)
         {
-            if (ch!=HttpTokens.LINE_FEED)
-                throw new BadMessage("Bad EOL");
+            if (ch!=LINE_FEED)
+                throw new BadMessageException("Bad EOL");
             _cr=false;
             return ch;
         }
 
-        if (ch>=0 && ch<HttpTokens.SPACE)
+        if (ch>=0 && ch<SPACE)
         {
-            if (ch==HttpTokens.CARRIAGE_RETURN)
+            if (ch==CARRIAGE_RETURN)
             {
                 if (buffer.hasRemaining())
                 {
                     if(_maxHeaderBytes>0 && _state.ordinal()<State.END.ordinal())
                         _headerBytes++;
                     ch=buffer.get();
-                    if (ch!=HttpTokens.LINE_FEED)
-                        throw new BadMessage("Bad EOL");
+                    if (ch!=LINE_FEED)
+                        throw new BadMessageException("Bad EOL");
                 }
                 else
                 {
@@ -392,8 +393,8 @@ public class HttpParser
                 }
             }
             // Only LF or TAB acceptable special characters
-            else if (!(ch==HttpTokens.LINE_FEED || ch==HttpTokens.TAB))
-                throw new BadMessage("Illegal character");
+            else if (!(ch==LINE_FEED || ch==TAB))
+                throw new IllegalCharacterException(_state,ch,buffer);
         }
         
         return ch;
@@ -433,7 +434,7 @@ public class HttpParser
         {
             int ch=next(buffer);
 
-            if (ch > HttpTokens.SPACE)
+            if (ch > SPACE)
             {
                 _string.setLength(0);
                 _string.append((char)ch);
@@ -443,13 +444,13 @@ public class HttpParser
             else if (ch==0)
                 break;
             else if (ch<0)
-                throw new BadMessage();
+                throw new BadMessageException();
             
             // count this white space as a header byte to avoid DOS
             if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes)
             {
                 LOG.warn("padding is too large >"+_maxHeaderBytes);
-                throw new BadMessage(HttpStatus.BAD_REQUEST_400);
+                throw new BadMessageException(HttpStatus.BAD_REQUEST_400);
             }
         }
         return false;
@@ -493,7 +494,7 @@ public class HttpParser
                 if (_state==State.URI)
                 {
                     LOG.warn("URI is too large >"+_maxHeaderBytes);
-                    throw new BadMessage(HttpStatus.REQUEST_URI_TOO_LONG_414);
+                    throw new BadMessageException(HttpStatus.REQUEST_URI_TOO_LONG_414);
                 }
                 else
                 {
@@ -501,14 +502,14 @@ public class HttpParser
                         LOG.warn("request is too large >"+_maxHeaderBytes);
                     else
                         LOG.warn("response is too large >"+_maxHeaderBytes);
-                    throw new BadMessage(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413);
+                    throw new BadMessageException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413);
                 }
             }
 
             switch (_state)
             {
                 case METHOD:
-                    if (ch == HttpTokens.SPACE)
+                    if (ch == SPACE)
                     {
                         _length=_string.length();
                         _methodString=takeString();
@@ -517,8 +518,13 @@ public class HttpParser
                             _methodString=method.asString();
                         setState(State.SPACE1);
                     }
-                    else if (ch < HttpTokens.SPACE)
-                        throw new BadMessage(ch<0?"Illegal character":"No URI");
+                    else if (ch < SPACE)
+                    {
+                        if (ch==LINE_FEED)
+                            throw new BadMessageException("No URI");
+                        else
+                            throw new IllegalCharacterException(_state,ch,buffer);
+                    }
                     else
                         _string.append((char)ch);
                     break;
@@ -530,11 +536,11 @@ public class HttpParser
                         String version=takeString();
                         _version=HttpVersion.CACHE.get(version);
                         if (_version==null)
-                            throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Unknown Version");
+                            throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Unknown Version");
                         setState(State.SPACE1);
                     }
                     else if (ch < HttpTokens.SPACE)
-                        throw new BadMessage(ch<0?"Illegal character":"No Status");
+                        throw new IllegalCharacterException(_state,ch,buffer);
                     else
                         _string.append((char)ch);
                     break;
@@ -567,7 +573,7 @@ public class HttpParser
                                 if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes)
                                 {
                                     LOG.warn("URI is too large >"+_maxHeaderBytes);
-                                    throw new BadMessage(HttpStatus.REQUEST_URI_TOO_LONG_414);
+                                    throw new BadMessageException(HttpStatus.REQUEST_URI_TOO_LONG_414);
                                 }
                                 if (_uri.remaining()<=len)
                                 {
@@ -585,7 +591,7 @@ public class HttpParser
                     }
                     else if (ch < HttpTokens.SPACE)
                     {
-                        throw new BadMessage(HttpStatus.BAD_REQUEST_400,_requestHandler!=null?"No URI":"No Status");
+                        throw new BadMessageException(HttpStatus.BAD_REQUEST_400,_requestHandler!=null?"No URI":"No Status");
                     }
                     break;
 
@@ -605,7 +611,7 @@ public class HttpParser
                     }
                     else
                     {
-                        throw new BadMessage();
+                        throw new BadMessageException();
                     }
                     break;
 
@@ -623,6 +629,7 @@ public class HttpParser
                         BufferUtil.clear(buffer);
                         handle=_handler.headerComplete()||handle;
                         handle=_handler.messageComplete()||handle;
+                        return handle;
                     }
                     else
                     {
@@ -662,7 +669,7 @@ public class HttpParser
                                 if (_method==HttpMethod.PROXY)
                                 {
                                     if (!(_requestHandler instanceof ProxyHandler))
-                                        throw new BadMessage();
+                                        throw new BadMessageException();
                                     
                                     _uri.flip();
                                     String protocol=BufferUtil.toString(_uri);
@@ -718,10 +725,11 @@ public class HttpParser
                             BufferUtil.clear(buffer);
                             handle=_handler.headerComplete()||handle;
                             handle=_handler.messageComplete()||handle;
+                            return handle;
                         }
                     }
                     else if (ch<0)
-                        throw new BadMessage();
+                        throw new BadMessageException();
                     break;
 
                 case REQUEST_VERSION:
@@ -733,7 +741,7 @@ public class HttpParser
                             _version=HttpVersion.CACHE.get(takeString());
                         }
                         if (_version==null)
-                            throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Unknown Version");
+                            throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Unknown Version");
                         
                         // Should we try to cache header fields?
                         if (_connectionFields==null && _version.getVersion()>=HttpVersion.HTTP_1_1.getVersion())
@@ -750,7 +758,7 @@ public class HttpParser
                     else if (ch>=HttpTokens.SPACE)
                         _string.append((char)ch);
                     else
-                        throw new BadMessage();
+                        throw new BadMessageException();
 
                     break;
 
@@ -770,7 +778,7 @@ public class HttpParser
                             _length=_string.length();
                     } 
                     else
-                        throw new BadMessage();
+                        throw new BadMessageException();
                     break;
 
                 default:
@@ -797,7 +805,7 @@ public class HttpParser
                     catch(NumberFormatException e)
                     {
                         LOG.ignore(e);
-                        throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad Content-Length");
+                        throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad Content-Length");
                     }
                     if (_contentLength <= 0)
                         _endOfContent=EndOfContent.NO_CONTENT;
@@ -815,7 +823,7 @@ public class HttpParser
                         _endOfContent=EndOfContent.CHUNKED_CONTENT;
                     else if (_valueString.contains(HttpHeaderValue.CHUNKED.toString()))
                     {
-                        throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad chunking");
+                        throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad chunking");
                     }
                 }
                 break;
@@ -827,7 +835,7 @@ public class HttpParser
                 int port=0;
                 if (host==null || host.length()==0)
                 {
-                    throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad Host header");
+                    throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad Host header");
                 }
 
                 int len=host.length();
@@ -849,7 +857,7 @@ public class HttpParser
                             {
                                 if (DEBUG)
                                     LOG.debug(e);
-                                throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad Host header");
+                                throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad Host header");
                             }
                             break loop;
                     }
@@ -858,9 +866,9 @@ public class HttpParser
                 {
                     if (host.charAt(len-1)!=']') 
                     {
-                        throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad IPv6 Host header");
+                        throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad IPv6 Host header");
                     }
-                    host = host.substring(1,len-1);
+                    host = host.substring(0,len);
                 }
                 else if (len!=host.length())
                     host = host.substring(0,len);
@@ -922,7 +930,7 @@ public class HttpParser
             if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes)
             {
                 LOG.warn("Header is too large >"+_maxHeaderBytes);
-                throw new BadMessage(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413);
+                throw new BadMessageException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413);
             }
 
             switch (_state)
@@ -980,9 +988,9 @@ public class HttpParser
                                 // End of headers!
 
                                 // Was there a required host header?
-                                if (!_host && _version!=HttpVersion.HTTP_1_0 && _requestHandler!=null)
+                                if (!_host && _version==HttpVersion.HTTP_1_1 && _requestHandler!=null)
                                 {
-                                    throw new BadMessage(HttpStatus.BAD_REQUEST_400,"No Host");
+                                    throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"No Host");
                                 }
 
                                 // is it a response that cannot have a body?
@@ -1010,27 +1018,27 @@ public class HttpParser
                                     case EOF_CONTENT:
                                         setState(State.EOF_CONTENT);
                                         handle=_handler.headerComplete()||handle;
-                                        break;
+                                        return handle;
 
                                     case CHUNKED_CONTENT:
                                         setState(State.CHUNKED_CONTENT);
                                         handle=_handler.headerComplete()||handle;
-                                        break;
+                                        return handle;
 
                                     case NO_CONTENT:
                                         handle=_handler.headerComplete()||handle;
                                         setState(State.END);
                                         handle=_handler.messageComplete()||handle;
-                                        break;
+                                        return handle;
 
                                     default:
                                         setState(State.CONTENT);
                                         handle=_handler.headerComplete()||handle;
-                                        break;
+                                        return handle;
                                 }
                             }
                             else if (ch<=HttpTokens.SPACE)
-                                throw new BadMessage();
+                                throw new BadMessageException();
                             else
                             {
                                 if (buffer.hasRemaining())
@@ -1147,8 +1155,8 @@ public class HttpParser
                             _length=_string.length();
                         break;
                     }
-                     
-                    throw new BadMessage("Illegal character");
+
+                    throw new IllegalCharacterException(_state,ch,buffer);
 
                 case HEADER_VALUE:
                     if (ch>HttpTokens.SPACE || ch<0)
@@ -1172,8 +1180,8 @@ public class HttpParser
                         setState(State.HEADER);
                         break; 
                     }
-
-                    throw new BadMessage("Illegal character");
+                    
+                    throw new IllegalCharacterException(_state,ch,buffer);
 
                 case HEADER_IN_VALUE:
                     if (ch>=HttpTokens.SPACE || ch<0 || ch==HttpTokens.TAB)
@@ -1201,7 +1209,8 @@ public class HttpParser
                         setState(State.HEADER);
                         break;
                     }
-                    throw new BadMessage("Illegal character");
+
+                    throw new IllegalCharacterException(_state,ch,buffer);
                     
                 default:
                     throw new IllegalStateException(_state.toString());
@@ -1256,8 +1265,7 @@ public class HttpParser
                 if (_responseStatus>0 && _headResponse)
                 {
                     setState(State.END);
-                    if (_handler.messageComplete())
-                        return true;
+                    return _handler.messageComplete();
                 }
                 else
                 {
@@ -1280,7 +1288,7 @@ public class HttpParser
                     // Just ignore data when closed
                     _headerBytes+=buffer.remaining();
                     BufferUtil.clear(buffer);
-                    if (_headerBytes>_maxHeaderBytes)
+                    if (_maxHeaderBytes>0 && _headerBytes>_maxHeaderBytes)
                     {
                         // Don't want to waste time reading data of a closed request
                         throw new IllegalStateException("too much data after closed");
@@ -1329,15 +1337,15 @@ public class HttpParser
             
             return false;
         }
-        catch(BadMessage e)
+        catch(BadMessageException e)
         {
             BufferUtil.clear(buffer);
 
-            LOG.warn("badMessage: "+e._code+(e._message!=null?" "+e._message:"")+" for "+_handler);
+            LOG.warn("badMessage: "+e._code+(e.getMessage()!=null?" "+e.getMessage():"")+" for "+_handler);
             if (DEBUG)
                 LOG.debug(e);
             setState(State.CLOSED);
-            _handler.badMessage(e._code, e._message);
+            _handler.badMessage(e._code, e.getMessage());
             return false;
         }
         catch(Exception e)
@@ -1372,8 +1380,7 @@ public class HttpParser
             if (content == 0)
             {
                 setState(State.END);
-                if (_handler.messageComplete())
-                    return true;
+                return _handler.messageComplete();
             }
         }
         
@@ -1397,8 +1404,7 @@ public class HttpParser
                     if (content == 0)
                     {
                         setState(State.END);
-                        if (_handler.messageComplete())
-                            return true;
+                        return _handler.messageComplete();
                     }
                     else
                     {
@@ -1421,8 +1427,7 @@ public class HttpParser
                         if(_contentPosition == _contentLength)
                         {
                             setState(State.END);
-                            if (_handler.messageComplete())
-                                return true;
+                            return _handler.messageComplete();
                         }
                     }
                     break;
@@ -1449,11 +1454,7 @@ public class HttpParser
                     if (ch == HttpTokens.LINE_FEED)
                     {
                         if (_chunkLength == 0)
-                        {
-                            setState(State.END);
-                            if (_handler.messageComplete())
-                                return true;
-                        }
+                            setState(State.CHUNK_END);
                         else
                             setState(State.CHUNK);
                     }
@@ -1470,11 +1471,7 @@ public class HttpParser
                     if (ch == HttpTokens.LINE_FEED)
                     {
                         if (_chunkLength == 0)
-                        {
-                            setState(State.END);
-                            if (_handler.messageComplete())
-                                return true;
-                        }
+                            setState(State.CHUNK_END);
                         else
                             setState(State.CHUNK);
                     }
@@ -1505,6 +1502,20 @@ public class HttpParser
                     break;
                 }
                 
+                case CHUNK_END:
+                {
+                    // TODO handle chunk trailer
+                    ch=next(buffer);
+                    if (ch==0)
+                        break;
+                    if (ch == HttpTokens.LINE_FEED)
+                    {
+                        setState(State.END);
+                        return _handler.messageComplete();
+                    }
+                    throw new IllegalCharacterException(_state,ch,buffer);
+                }
+                
                 case CLOSED:
                 {
                     BufferUtil.clear(buffer);
@@ -1577,6 +1588,29 @@ public class HttpParser
         _state=state;
     }
 
+    /* ------------------------------------------------------------------------------- */
+    public Trie<HttpField> getFieldCache()
+    {
+        return _connectionFields;
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    private String getProxyField(ByteBuffer buffer)
+    {
+        _string.setLength(0);
+        _length=0;
+        
+        while (buffer.hasRemaining())
+        {
+            // process each character
+            byte ch=next(buffer);
+            if (ch<=' ')
+                return _string.toString();
+            _string.append((char)ch);    
+        }
+        throw new BadMessageException();
+    }
+    
     /* ------------------------------------------------------------------------------- */
     @Override
     public String toString()
@@ -1632,11 +1666,17 @@ public class HttpParser
         public int getHeaderCacheSize();
     }
 
+    /* ------------------------------------------------------------------------------- */
+    /* ------------------------------------------------------------------------------- */
+    /* ------------------------------------------------------------------------------- */
     public interface ProxyHandler 
     {
         void proxied(String protocol, String sAddr, String dAddr, int sPort, int dPort);
     }
-    
+
+    /* ------------------------------------------------------------------------------- */
+    /* ------------------------------------------------------------------------------- */
+    /* ------------------------------------------------------------------------------- */
     public interface RequestHandler<T> extends HttpHandler<T>
     {
         /**
@@ -1657,6 +1697,9 @@ public class HttpParser
         public abstract boolean parsedHostHeader(String host,int port);
     }
 
+    /* ------------------------------------------------------------------------------- */
+    /* ------------------------------------------------------------------------------- */
+    /* ------------------------------------------------------------------------------- */
     public interface ResponseHandler<T> extends HttpHandler<T>
     {
         /**
@@ -1665,24 +1708,15 @@ public class HttpParser
         public abstract boolean startResponse(HttpVersion version, int status, String reason);
     }
 
-    public Trie<HttpField> getFieldCache()
-    {
-        return _connectionFields;
-    }
-
-    private String getProxyField(ByteBuffer buffer)
+    /* ------------------------------------------------------------------------------- */
+    @SuppressWarnings("serial")
+    private static class IllegalCharacterException extends BadMessageException
     {
-        _string.setLength(0);
-        _length=0;
-        
-        while (buffer.hasRemaining())
+        private IllegalCharacterException(State state,byte ch,ByteBuffer buffer)
         {
-            // process each character
-            byte ch=next(buffer);
-            if (ch<=' ')
-                return _string.toString();
-            _string.append((char)ch);    
+            super(400,String.format("Illegal character 0x%X",ch));
+            // Bug #460642 - don't reveal buffers to end user
+            LOG.warn(String.format("Illegal character 0x%X in state=%s for buffer %s",ch,state,BufferUtil.toDetailString(buffer)));
         }
-        throw new BadMessage();
     }
 }
index 13f2a8d3fa531195ff5dec2d4e554395b7d60878..f44bcdd63742caf0e0e857479046aedd0b3e8bfd 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index e6ea1f714a53925c7163daa7ca96dad1596ccc25..8762644cfe7b351d32292057f3d3b915fc96b095 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -612,7 +612,6 @@ package org.eclipse.jetty.http;
  */
 public class HttpStatus
 {
-    public final static int NOT_SET_000 = 0;
     public final static int CONTINUE_100 = 100;
     public final static int SWITCHING_PROTOCOLS_101 = 101;
     public final static int PROCESSING_102 = 102;
index 537c457cb4196ddd7573bcf5b6b7c1c8edf7142e..0283f9e3e7f0d93dd0bee035ec96e5875c33d0cb 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 4138334de070b917c236ec0255452d1f103746ce..067a21ef560c51850fcdf4796e497a11d14a9a59 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index afe925e1ca8be0027babfa6bbdba3730ce24c8d3..46a8a5bca2ec9c121e208e876c8e77c6eae52326 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -539,8 +539,6 @@ public class HttpURI
     {
         if (_host==_port)
             return null;
-        if (_raw[_host]=='[')
-            return new String(_raw,_host+1,_port-_host-2,_charset);
         return new String(_raw,_host,_port-_host,_charset);
     }
 
index eb889e56a32712edf52c178bdc602210a0131262..ddedc274710b380d7ba1cb2b6fd023b89659c925 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -31,7 +31,7 @@ public enum HttpVersion
     HTTP_0_9("HTTP/0.9",9),
     HTTP_1_0("HTTP/1.0",10),
     HTTP_1_1("HTTP/1.1",11),
-    HTTP_2_0("HTTP/2.0",20);
+    HTTP_2("HTTP/2.0",20);
 
     /* ------------------------------------------------------------ */
     public final static Trie<HttpVersion> CACHE= new ArrayTrie<HttpVersion>();
@@ -74,7 +74,7 @@ public enum HttpVersion
                     switch(bytes[position+7])
                     {
                         case '0':
-                            return HTTP_2_0;
+                            return HTTP_2;
                     }
                     break;
             }
@@ -166,6 +166,7 @@ public enum HttpVersion
             case 9: return HttpVersion.HTTP_0_9;
             case 10: return HttpVersion.HTTP_1_0;
             case 11: return HttpVersion.HTTP_1_1;
+            case 20: return HttpVersion.HTTP_2;
             default: throw new IllegalArgumentException();
         }
     }
index 9cac4abd8bcca835e4dcd4886807249d12a6a753..145f22008d758fed462f43006cc0b7544a1f65d5 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index b78f5728d30822092e6816267323e8ce77b85f95..d2196874245663db2b0fb1802aff6012ee68a1da 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
 
 package org.eclipse.jetty.http;
 
+import java.util.AbstractSet;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.StringTokenizer;
 
 import org.eclipse.jetty.util.ArrayTernaryTrie;
+import org.eclipse.jetty.util.IncludeExclude;
+import org.eclipse.jetty.util.Predicate;
 import org.eclipse.jetty.util.Trie;
 import org.eclipse.jetty.util.URIUtil;
 
@@ -569,4 +573,54 @@ public class PathMap<O> extends HashMap<String,O>
             this.mapped = mapped;
         }
     }
+    
+    public static class PathSet extends AbstractSet<String> implements Predicate<String>
+    {
+        private final PathMap<Boolean> _map = new PathMap<>();
+        
+        @Override
+        public Iterator<String> iterator()
+        {
+            return _map.keySet().iterator();
+        }
+
+        @Override
+        public int size()
+        {
+            return _map.size();
+        }
+        
+        @Override
+        public boolean add(String item)
+        {
+            return _map.put(item,Boolean.TRUE)==null;
+        }
+        
+        @Override
+        public boolean remove(Object item)
+        {
+            return _map.remove(item)!=null;
+        }
+
+        @Override
+        public boolean contains(Object o) 
+        { 
+            return _map.containsKey(o); 
+        }
+        
+        @Override
+        public boolean test(String s)
+        {
+            return _map.containsMatch(s);
+        }
+        
+        public boolean containsMatch(String s) 
+        { 
+            return _map.containsMatch(s); 
+        }
+        public boolean matches(String item)
+        {
+            return _map.containsMatch(item);
+        }
+    }
 }
index b2709897ae5ad1d2a269cdb265b92d40a9a13f04..302cbd0a0b5dae2260d2b9e6091a3b5cdb1c9d61 100644 (file)
@@ -12,6 +12,7 @@ bcpio=application/x-bcpio
 bin=application/octet-stream
 cab=application/x-cabinet
 cdf=application/x-netcdf
+chm=application/vnd.ms-htmlhelp
 class=application/java-vm
 cpio=application/x-cpio
 cpt=application/mac-compactpro
@@ -141,6 +142,7 @@ src=application/x-wais-source
 sv4cpio=application/x-sv4cpio
 sv4crc=application/x-sv4crc
 svg=image/svg+xml
+svgz=image/svg+xml
 swf=application/x-shockwave-flash
 t=application/x-troff
 tar=application/x-tar
index 825422a3dfcd1eca40e8e5b06d652eed910875be..aeca4a3f2a6bc8d203519a6097d459a336b7e6e0 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
diff --git a/lib/jetty/org/eclipse/jetty/http/pathmap/MappedResource.java b/lib/jetty/org/eclipse/jetty/http/pathmap/MappedResource.java
new file mode 100644 (file)
index 0000000..155dce8
--- /dev/null
@@ -0,0 +1,101 @@
+//
+//  ========================================================================
+//  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.pathmap;
+
+import org.eclipse.jetty.util.annotation.ManagedAttribute;
+import org.eclipse.jetty.util.annotation.ManagedObject;
+
+@ManagedObject("Mapped Resource")
+public class MappedResource<E> implements Comparable<MappedResource<E>>
+{
+    private final PathSpec pathSpec;
+    private final E resource;
+
+    public MappedResource(PathSpec pathSpec, E resource)
+    {
+        this.pathSpec = pathSpec;
+        this.resource = resource;
+    }
+
+    /**
+     * Comparison is based solely on the pathSpec
+     */
+    @Override
+    public int compareTo(MappedResource<E> other)
+    {
+        return this.pathSpec.compareTo(other.pathSpec);
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+        if (obj == null)
+        {
+            return false;
+        }
+        if (getClass() != obj.getClass())
+        {
+            return false;
+        }
+        MappedResource<?> other = (MappedResource<?>)obj;
+        if (pathSpec == null)
+        {
+            if (other.pathSpec != null)
+            {
+                return false;
+            }
+        }
+        else if (!pathSpec.equals(other.pathSpec))
+        {
+            return false;
+        }
+        return true;
+    }
+
+    @ManagedAttribute(value = "path spec", readonly = true)
+    public PathSpec getPathSpec()
+    {
+        return pathSpec;
+    }
+
+    @ManagedAttribute(value = "resource", readonly = true)
+    public E getResource()
+    {
+        return resource;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        result = (prime * result) + ((pathSpec == null) ? 0 : pathSpec.hashCode());
+        return result;
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("MappedResource[pathSpec=%s,resource=%s]",pathSpec,resource);
+    }
+}
\ No newline at end of file
diff --git a/lib/jetty/org/eclipse/jetty/http/pathmap/PathMappings.java b/lib/jetty/org/eclipse/jetty/http/pathmap/PathMappings.java
new file mode 100644 (file)
index 0000000..d1c36cf
--- /dev/null
@@ -0,0 +1,159 @@
+//
+//  ========================================================================
+//  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.pathmap;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.jetty.util.annotation.ManagedAttribute;
+import org.eclipse.jetty.util.annotation.ManagedObject;
+import org.eclipse.jetty.util.component.ContainerLifeCycle;
+import org.eclipse.jetty.util.component.Dumpable;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+/**
+ * Path Mappings of PathSpec to Resource.
+ * <p>
+ * Sorted into search order upon entry into the Set
+ * 
+ * @param <E> the type of mapping endpoint
+ */
+@ManagedObject("Path Mappings")
+public class PathMappings<E> implements Iterable<MappedResource<E>>, Dumpable
+{
+    private static final Logger LOG = Log.getLogger(PathMappings.class);
+    private List<MappedResource<E>> mappings = new ArrayList<MappedResource<E>>();
+    private MappedResource<E> defaultResource = null;
+    private MappedResource<E> rootResource = null;
+
+    @Override
+    public String dump()
+    {
+        return ContainerLifeCycle.dump(this);
+    }
+
+    @Override
+    public void dump(Appendable out, String indent) throws IOException
+    {
+        ContainerLifeCycle.dump(out,indent,mappings);
+    }
+
+    @ManagedAttribute(value = "mappings", readonly = true)
+    public List<MappedResource<E>> getMappings()
+    {
+        return mappings;
+    }
+
+    public void reset()
+    {
+        mappings.clear();
+    }
+    
+    /**
+     * Return a list of MappedResource matches for the specified path.
+     * 
+     * @param path the path to return matches on
+     * @return the list of mapped resource the path matches on
+     */
+    public List<MappedResource<E>> getMatches(String path)
+    {
+        boolean matchRoot = "/".equals(path);
+        
+        List<MappedResource<E>> ret = new ArrayList<>();
+        int len = mappings.size();
+        for (int i = 0; i < len; i++)
+        {
+            MappedResource<E> mr = mappings.get(i);
+
+            switch (mr.getPathSpec().group)
+            {
+                case ROOT:
+                    if (matchRoot)
+                        ret.add(mr);
+                    break;
+                case DEFAULT:
+                    if (matchRoot || mr.getPathSpec().matches(path))
+                        ret.add(mr);
+                    break;
+                default:
+                    if (mr.getPathSpec().matches(path))
+                        ret.add(mr);
+                    break;
+            }
+        }
+        return ret;
+    }
+
+    public MappedResource<E> getMatch(String path)
+    {
+        if (path.equals("/") && rootResource != null)
+        {
+            return rootResource;
+        }
+        
+        int len = mappings.size();
+        for (int i = 0; i < len; i++)
+        {
+            MappedResource<E> mr = mappings.get(i);
+            if (mr.getPathSpec().matches(path))
+            {
+                return mr;
+            }
+        }
+        return defaultResource;
+    }
+
+    @Override
+    public Iterator<MappedResource<E>> iterator()
+    {
+        return mappings.iterator();
+    }
+
+    @SuppressWarnings("incomplete-switch")
+    public void put(PathSpec pathSpec, E resource)
+    {
+        MappedResource<E> entry = new MappedResource<>(pathSpec,resource);
+        switch (pathSpec.group)
+        {
+            case DEFAULT:
+                defaultResource = entry;
+                break;
+            case ROOT:
+                rootResource = entry;
+                break;
+        }
+        
+        // TODO: add warning when replacing an existing pathspec?
+        
+        mappings.add(entry);
+        if (LOG.isDebugEnabled())
+            LOG.debug("Added {} to {}",entry,this);
+        Collections.sort(mappings);
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("%s[size=%d]",this.getClass().getSimpleName(),mappings.size());
+    }
+}
diff --git a/lib/jetty/org/eclipse/jetty/http/pathmap/PathSpec.java b/lib/jetty/org/eclipse/jetty/http/pathmap/PathSpec.java
new file mode 100644 (file)
index 0000000..a2b8ea5
--- /dev/null
@@ -0,0 +1,167 @@
+//
+//  ========================================================================
+//  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.pathmap;
+
+/**
+ * The base PathSpec, what all other path specs are based on
+ */
+public abstract class PathSpec implements Comparable<PathSpec>
+{
+    protected String pathSpec;
+    protected PathSpecGroup group;
+    protected int pathDepth;
+    protected int specLength;
+
+    @Override
+    public int compareTo(PathSpec other)
+    {
+        // Grouping (increasing)
+        int diff = this.group.ordinal() - other.group.ordinal();
+        if (diff != 0)
+        {
+            return diff;
+        }
+
+        // Spec Length (decreasing)
+        diff = other.specLength - this.specLength;
+        if (diff != 0)
+        {
+            return diff;
+        }
+
+        // Path Spec Name (alphabetical)
+        return this.pathSpec.compareTo(other.pathSpec);
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+        if (obj == null)
+        {
+            return false;
+        }
+        if (getClass() != obj.getClass())
+        {
+            return false;
+        }
+        PathSpec other = (PathSpec)obj;
+        if (pathSpec == null)
+        {
+            if (other.pathSpec != null)
+            {
+                return false;
+            }
+        }
+        else if (!pathSpec.equals(other.pathSpec))
+        {
+            return false;
+        }
+        return true;
+    }
+
+    public PathSpecGroup getGroup()
+    {
+        return group;
+    }
+
+    /**
+     * Get the number of path elements that this path spec declares.
+     * <p>
+     * This is used to determine longest match logic.
+     * 
+     * @return the depth of the path segments that this spec declares
+     */
+    public int getPathDepth()
+    {
+        return pathDepth;
+    }
+
+    /**
+     * Return the portion of the path that is after the path spec.
+     * 
+     * @param path
+     *            the path to match against
+     * @return the path info portion of the string
+     */
+    public abstract String getPathInfo(String path);
+
+    /**
+     * Return the portion of the path that matches a path spec.
+     * 
+     * @param path
+     *            the path to match against
+     * @return the match, or null if no match at all
+     */
+    public abstract String getPathMatch(String path);
+
+    /**
+     * The as-provided path spec.
+     * 
+     * @return the as-provided path spec
+     */
+    public String getDeclaration()
+    {
+        return pathSpec;
+    }
+
+    /**
+     * Get the relative path.
+     * 
+     * @param base
+     *            the base the path is relative to
+     * @param path
+     *            the additional path
+     * @return the base plus path with pathSpec portion removed
+     */
+    public abstract String getRelativePath(String base, String path);
+
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        result = (prime * result) + ((pathSpec == null)?0:pathSpec.hashCode());
+        return result;
+    }
+
+    /**
+     * Test to see if the provided path matches this path spec
+     * 
+     * @param path
+     *            the path to test
+     * @return true if the path matches this path spec, false otherwise
+     */
+    public abstract boolean matches(String path);
+
+    @Override
+    public String toString()
+    {
+        StringBuilder str = new StringBuilder();
+        str.append(this.getClass().getSimpleName()).append("[\"");
+        str.append(pathSpec);
+        str.append("\",pathDepth=").append(pathDepth);
+        str.append(",group=").append(group);
+        str.append("]");
+        return str.toString();
+    }
+}
diff --git a/lib/jetty/org/eclipse/jetty/http/pathmap/PathSpecGroup.java b/lib/jetty/org/eclipse/jetty/http/pathmap/PathSpecGroup.java
new file mode 100644 (file)
index 0000000..f9d96ce
--- /dev/null
@@ -0,0 +1,101 @@
+//
+//  ========================================================================
+//  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.pathmap;
+
+/**
+ * Types of path spec groups.
+ * <p>
+ * This is used to facilitate proper pathspec search order.
+ * <p>
+ * Search Order: 
+ * <ol>
+ * <li>{@link PathSpecGroup#ordinal()} [increasing]</li>
+ * <li>{@link PathSpec#specLength} [decreasing]</li>
+ * <li>{@link PathSpec#pathSpec} [natural sort order]</li>
+ * </ol>
+ */
+public enum PathSpecGroup
+{
+    // NOTE: Order of enums determines order of Groups.
+
+    /**
+     * For exactly defined path specs, no glob.
+     */
+    EXACT,
+    /**
+     * For path specs that have a hardcoded prefix and suffix with wildcard glob in the middle.
+     * 
+     * <pre>
+     *   "^/downloads/[^/]*.zip$"  - regex spec
+     *   "/a/{var}/c"              - uri-template spec
+     * </pre>
+     * 
+     * Note: there is no known servlet spec variant of this kind of path spec
+     */
+    MIDDLE_GLOB,
+    /**
+     * For path specs that have a hardcoded prefix and a trailing wildcard glob.
+     * <p>
+     * 
+     * <pre>
+     *   "/downloads/*"          - servlet spec
+     *   "/api/*"                - servlet spec
+     *   "^/rest/.*$"            - regex spec
+     *   "/bookings/{guest-id}"  - uri-template spec
+     *   "/rewards/{vip-level}"  - uri-template spec
+     * </pre>
+     */
+    PREFIX_GLOB,
+    /**
+     * For path specs that have a wildcard glob with a hardcoded suffix
+     * 
+     * <pre>
+     *   "*.do"        - servlet spec
+     *   "*.css"       - servlet spec
+     *   "^.*\.zip$"   - regex spec
+     * </pre>
+     * 
+     * Note: there is no known uri-template spec variant of this kind of path spec
+     */
+    SUFFIX_GLOB,
+    /**
+     * The root spec for accessing the Root behavior.
+     * 
+     * <pre>
+     *   ""           - servlet spec       (Root Servlet)
+     *   null         - servlet spec       (Root Servlet)
+     * </pre>
+     * 
+     * Note: there is no known uri-template spec variant of this kind of path spec
+     */
+    ROOT,
+    /**
+     * The default spec for accessing the Default path behavior.
+     * 
+     * <pre>
+     *   "/"           - servlet spec      (Default Servlet)
+     *   "/"           - uri-template spec (Root Context)
+     *   "^/$"         - regex spec        (Root Context)
+     * </pre>
+     * 
+     * Per Servlet Spec, pathInfo is always null for these specs.
+     * If nothing above matches, then default will match.
+     */
+    DEFAULT,
+}
diff --git a/lib/jetty/org/eclipse/jetty/http/pathmap/PathSpecSet.java b/lib/jetty/org/eclipse/jetty/http/pathmap/PathSpecSet.java
new file mode 100644 (file)
index 0000000..1ffb783
--- /dev/null
@@ -0,0 +1,223 @@
+//
+//  ========================================================================
+//  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.pathmap;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.eclipse.jetty.util.Predicate;
+
+/**
+ * A Set of PathSpec strings.
+ * <p>
+ * Used by {@link org.eclipse.jetty.util.IncludeExclude} logic
+ */
+public class PathSpecSet implements Set<String>, Predicate<String>
+{
+    private final Set<PathSpec> specs = new TreeSet<>();
+
+    @Override
+    public boolean test(String s)
+    {
+        for (PathSpec spec : specs)
+        {
+            if (spec.matches(s))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean isEmpty()
+    {
+        return specs.isEmpty();
+    }
+
+    @Override
+    public Iterator<String> iterator()
+    {
+        return new Iterator<String>()
+        {
+            private Iterator<PathSpec> iter = specs.iterator();
+
+            @Override
+            public boolean hasNext()
+            {
+                return iter.hasNext();
+            }
+
+            @Override
+            public String next()
+            {
+                PathSpec spec = iter.next();
+                if (spec == null)
+                {
+                    return null;
+                }
+                return spec.getDeclaration();
+            }
+
+            @Override
+            public void remove()
+            {
+                throw new UnsupportedOperationException("Remove not supported by this Iterator");
+            }
+        };
+    }
+
+    @Override
+    public int size()
+    {
+        return specs.size();
+    }
+
+    @Override
+    public boolean contains(Object o)
+    {
+        if (o instanceof PathSpec)
+        {
+            return specs.contains(o);
+        }
+        if (o instanceof String)
+        {
+            return specs.contains(toPathSpec((String)o));
+        }
+        return false;
+    }
+
+    private PathSpec asPathSpec(Object o)
+    {
+        if (o == null)
+        {
+            return null;
+        }
+        if (o instanceof PathSpec)
+        {
+            return (PathSpec)o;
+        }
+        if (o instanceof String)
+        {
+            return toPathSpec((String)o);
+        }
+        return toPathSpec(o.toString());
+    }
+
+    private PathSpec toPathSpec(String rawSpec)
+    {
+        if ((rawSpec == null) || (rawSpec.length() < 1))
+        {
+            throw new RuntimeException("Path Spec String must start with '^', '/', or '*.': got [" + rawSpec + "]");
+        }
+        if (rawSpec.charAt(0) == '^')
+        {
+            return new RegexPathSpec(rawSpec);
+        }
+        else
+        {
+            return new ServletPathSpec(rawSpec);
+        }
+    }
+
+    @Override
+    public Object[] toArray()
+    {
+        return toArray(new String[specs.size()]);
+    }
+
+    @Override
+    public <T> T[] toArray(T[] a)
+    {
+        int i = 0;
+        for (PathSpec spec : specs)
+        {
+            a[i++] = (T)spec.getDeclaration();
+        }
+        return a;
+    }
+
+    @Override
+    public boolean add(String e)
+    {
+        return specs.add(toPathSpec(e));
+    }
+
+    @Override
+    public boolean remove(Object o)
+    {
+        return specs.remove(asPathSpec(o));
+    }
+
+    @Override
+    public boolean containsAll(Collection<?> coll)
+    {
+        for (Object o : coll)
+        {
+            if (!specs.contains(asPathSpec(o)))
+                return false;
+        }
+        return true;
+    }
+
+    @Override
+    public boolean addAll(Collection<? extends String> coll)
+    {
+        boolean ret = false;
+
+        for (String s : coll)
+        {
+            ret |= add(s);
+        }
+
+        return ret;
+    }
+
+    @Override
+    public boolean retainAll(Collection<?> coll)
+    {
+        List<PathSpec> collSpecs = new ArrayList<>();
+        for (Object o : coll)
+        {
+            collSpecs.add(asPathSpec(o));
+        }
+        return specs.retainAll(collSpecs);
+    }
+
+    @Override
+    public boolean removeAll(Collection<?> coll)
+    {
+        List<PathSpec> collSpecs = new ArrayList<>();
+        for (Object o : coll)
+        {
+            collSpecs.add(asPathSpec(o));
+        }
+        return specs.removeAll(collSpecs);
+    }
+
+    @Override
+    public void clear()
+    {
+        specs.clear();
+    }
+}
diff --git a/lib/jetty/org/eclipse/jetty/http/pathmap/RegexPathSpec.java b/lib/jetty/org/eclipse/jetty/http/pathmap/RegexPathSpec.java
new file mode 100644 (file)
index 0000000..0d83f3b
--- /dev/null
@@ -0,0 +1,176 @@
+//
+//  ========================================================================
+//  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.pathmap;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class RegexPathSpec extends PathSpec
+{
+    protected Pattern pattern;
+
+    protected RegexPathSpec()
+    {
+        super();
+    }
+
+    public RegexPathSpec(String regex)
+    {
+        super.pathSpec = regex;
+        boolean inGrouping = false;
+        this.pathDepth = 0;
+        this.specLength = pathSpec.length();
+        // build up a simple signature we can use to identify the grouping
+        StringBuilder signature = new StringBuilder();
+        for (char c : pathSpec.toCharArray())
+        {
+            switch (c)
+            {
+                case '[':
+                    inGrouping = true;
+                    break;
+                case ']':
+                    inGrouping = false;
+                    signature.append('g'); // glob
+                    break;
+                case '*':
+                    signature.append('g'); // glob
+                    break;
+                case '/':
+                    if (!inGrouping)
+                    {
+                        this.pathDepth++;
+                    }
+                    break;
+                default:
+                    if (!inGrouping)
+                    {
+                        if (Character.isLetterOrDigit(c))
+                        {
+                            signature.append('l'); // literal (exact)
+                        }
+                    }
+                    break;
+            }
+        }
+        this.pattern = Pattern.compile(pathSpec);
+
+        // Figure out the grouping based on the signature
+        String sig = signature.toString();
+
+        if (Pattern.matches("^l*$",sig))
+        {
+            this.group = PathSpecGroup.EXACT;
+        }
+        else if (Pattern.matches("^l*g+",sig))
+        {
+            this.group = PathSpecGroup.PREFIX_GLOB;
+        }
+        else if (Pattern.matches("^g+l+$",sig))
+        {
+            this.group = PathSpecGroup.SUFFIX_GLOB;
+        }
+        else
+        {
+            this.group = PathSpecGroup.MIDDLE_GLOB;
+        }
+    }
+
+    public Matcher getMatcher(String path)
+    {
+        return this.pattern.matcher(path);
+    }
+
+    @Override
+    public String getPathInfo(String path)
+    {
+        // Path Info only valid for PREFIX_GLOB types
+        if (group == PathSpecGroup.PREFIX_GLOB)
+        {
+            Matcher matcher = getMatcher(path);
+            if (matcher.matches())
+            {
+                if (matcher.groupCount() >= 1)
+                {
+                    String pathInfo = matcher.group(1);
+                    if ("".equals(pathInfo))
+                    {
+                        return "/";
+                    }
+                    else
+                    {
+                        return pathInfo;
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public String getPathMatch(String path)
+    {
+        Matcher matcher = getMatcher(path);
+        if (matcher.matches())
+        {
+            if (matcher.groupCount() >= 1)
+            {
+                int idx = matcher.start(1);
+                if (idx > 0)
+                {
+                    if (path.charAt(idx - 1) == '/')
+                    {
+                        idx--;
+                    }
+                    return path.substring(0,idx);
+                }
+            }
+            return path;
+        }
+        return null;
+    }
+
+    public Pattern getPattern()
+    {
+        return this.pattern;
+    }
+
+    @Override
+    public String getRelativePath(String base, String path)
+    {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public boolean matches(final String path)
+    {
+        int idx = path.indexOf('?');
+        if (idx >= 0)
+        {
+            // match only non-query part
+            return getMatcher(path.substring(0,idx)).matches();
+        }
+        else
+        {
+            // match entire path
+            return getMatcher(path).matches();
+        }
+    }
+}
diff --git a/lib/jetty/org/eclipse/jetty/http/pathmap/ServletPathSpec.java b/lib/jetty/org/eclipse/jetty/http/pathmap/ServletPathSpec.java
new file mode 100644 (file)
index 0000000..4563305
--- /dev/null
@@ -0,0 +1,261 @@
+//
+//  ========================================================================
+//  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.pathmap;
+
+import org.eclipse.jetty.util.URIUtil;
+
+public class ServletPathSpec extends PathSpec
+{
+    public ServletPathSpec(String servletPathSpec)
+    {
+        super();
+        assertValidServletPathSpec(servletPathSpec);
+
+        // The Root Path Spec
+        if ((servletPathSpec == null) || (servletPathSpec.length() == 0))
+        {
+            super.pathSpec = "";
+            super.pathDepth = -1; // force this to be at the end of the sort order
+            this.specLength = 1;
+            this.group = PathSpecGroup.ROOT;
+            return;
+        }
+
+        // The Default Path Spec
+        if("/".equals(servletPathSpec))
+        {
+            super.pathSpec = "/";
+            super.pathDepth = -1; // force this to be at the end of the sort order
+            this.specLength = 1;
+            this.group = PathSpecGroup.DEFAULT;
+            return;
+        }
+        
+        this.specLength = servletPathSpec.length();
+        super.pathDepth = 0;
+        char lastChar = servletPathSpec.charAt(specLength - 1);
+        // prefix based
+        if ((servletPathSpec.charAt(0) == '/') && (specLength > 1) && (lastChar == '*'))
+        {
+            this.group = PathSpecGroup.PREFIX_GLOB;
+        }
+        // suffix based
+        else if (servletPathSpec.charAt(0) == '*')
+        {
+            this.group = PathSpecGroup.SUFFIX_GLOB;
+        }
+        else
+        {
+            this.group = PathSpecGroup.EXACT;
+        }
+
+        for (int i = 0; i < specLength; i++)
+        {
+            int cp = servletPathSpec.codePointAt(i);
+            if (cp < 128)
+            {
+                char c = (char)cp;
+                switch (c)
+                {
+                    case '/':
+                        super.pathDepth++;
+                        break;
+                }
+            }
+        }
+
+        super.pathSpec = servletPathSpec;
+    }
+
+    private void assertValidServletPathSpec(String servletPathSpec)
+    {
+        if ((servletPathSpec == null) || servletPathSpec.equals(""))
+        {
+            return; // empty path spec
+        }
+
+        int len = servletPathSpec.length();
+        // path spec must either start with '/' or '*.'
+        if (servletPathSpec.charAt(0) == '/')
+        {
+            // Prefix Based
+            if (len == 1)
+            {
+                return; // simple '/' path spec
+            }
+            int idx = servletPathSpec.indexOf('*');
+            if (idx < 0)
+            {
+                return; // no hit on glob '*'
+            }
+            // only allowed to have '*' at the end of the path spec
+            if (idx != (len - 1))
+            {
+                throw new IllegalArgumentException("Servlet Spec 12.2 violation: glob '*' can only exist at end of prefix based matches: bad spec \""+ servletPathSpec +"\"");
+            }
+        }
+        else if (servletPathSpec.startsWith("*."))
+        {
+            // Suffix Based
+            int idx = servletPathSpec.indexOf('/');
+            // cannot have path separator
+            if (idx >= 0)
+            {
+                throw new IllegalArgumentException("Servlet Spec 12.2 violation: suffix based path spec cannot have path separators: bad spec \""+ servletPathSpec +"\"");
+            }
+
+            idx = servletPathSpec.indexOf('*',2);
+            // only allowed to have 1 glob '*', at the start of the path spec
+            if (idx >= 1)
+            {
+                throw new IllegalArgumentException("Servlet Spec 12.2 violation: suffix based path spec cannot have multiple glob '*': bad spec \""+ servletPathSpec +"\"");
+            }
+        }
+        else
+        {
+            throw new IllegalArgumentException("Servlet Spec 12.2 violation: path spec must start with \"/\" or \"*.\": bad spec \""+ servletPathSpec +"\"");
+        }
+    }
+
+    @Override
+    public String getPathInfo(String path)
+    {
+        // Path Info only valid for PREFIX_GLOB types
+        if (group == PathSpecGroup.PREFIX_GLOB)
+        {
+            if (path.length() == (specLength - 2))
+            {
+                return null;
+            }
+            return path.substring(specLength - 2);
+        }
+
+        return null;
+    }
+
+    @Override
+    public String getPathMatch(String path)
+    {
+        switch (group)
+        {
+            case EXACT:
+                if (pathSpec.equals(path))
+                {
+                    return path;
+                }
+                else
+                {
+                    return null;
+                }
+            case PREFIX_GLOB:
+                if (isWildcardMatch(path))
+                {
+                    return path.substring(0,specLength - 2);
+                }
+                else
+                {
+                    return null;
+                }
+            case SUFFIX_GLOB:
+                if (path.regionMatches(path.length() - (specLength - 1),pathSpec,1,specLength - 1))
+                {
+                    return path;
+                }
+                else
+                {
+                    return null;
+                }
+            case DEFAULT:
+                return path;
+            default:
+                return null;
+        }
+    }
+
+    @Override
+    public String getRelativePath(String base, String path)
+    {
+        String info = getPathInfo(path);
+        if (info == null)
+        {
+            info = path;
+        }
+
+        if (info.startsWith("./"))
+        {
+            info = info.substring(2);
+        }
+        if (base.endsWith(URIUtil.SLASH))
+        {
+            if (info.startsWith(URIUtil.SLASH))
+            {
+                path = base + info.substring(1);
+            }
+            else
+            {
+                path = base + info;
+            }
+        }
+        else if (info.startsWith(URIUtil.SLASH))
+        {
+            path = base + info;
+        }
+        else
+        {
+            path = base + URIUtil.SLASH + info;
+        }
+        return path;
+    }
+
+    private boolean isWildcardMatch(String path)
+    {
+        // For a spec of "/foo/*" match "/foo" , "/foo/..." but not "/foobar"
+        int cpl = specLength - 2;
+        if ((group == PathSpecGroup.PREFIX_GLOB) && (path.regionMatches(0,pathSpec,0,cpl)))
+        {
+            if ((path.length() == cpl) || ('/' == path.charAt(cpl)))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean matches(String path)
+    {
+        switch (group)
+        {
+            case EXACT:
+                return pathSpec.equals(path);
+            case PREFIX_GLOB:
+                return isWildcardMatch(path);
+            case SUFFIX_GLOB:
+                return path.regionMatches((path.length() - specLength) + 1,pathSpec,1,specLength - 1);
+            case ROOT:
+                // Only "/" matches
+                return ("/".equals(path));
+            case DEFAULT:
+                // If we reached this point, then everything matches
+                return true;
+            default:
+                return false;
+        }
+    }
+}
diff --git a/lib/jetty/org/eclipse/jetty/http/pathmap/UriTemplatePathSpec.java b/lib/jetty/org/eclipse/jetty/http/pathmap/UriTemplatePathSpec.java
new file mode 100644 (file)
index 0000000..208820b
--- /dev/null
@@ -0,0 +1,341 @@
+//
+//  ========================================================================
+//  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.pathmap;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.jetty.util.TypeUtil;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+/**
+ * PathSpec for URI Template based declarations
+ * 
+ * @see <a href="https://tools.ietf.org/html/rfc6570">URI Templates (Level 1)</a>
+ */
+public class UriTemplatePathSpec extends RegexPathSpec
+{
+    private static final Logger LOG = Log.getLogger(UriTemplatePathSpec.class);
+    
+    private static final Pattern VARIABLE_PATTERN = Pattern.compile("\\{(.*)\\}");
+    /** Reserved Symbols in URI Template variable */
+    private static final String VARIABLE_RESERVED = ":/?#[]@" + // gen-delims
+                                                    "!$&'()*+,;="; // sub-delims
+    /** Allowed Symbols in a URI Template variable */
+    private static final String VARIABLE_SYMBOLS="-._";
+    private static final Set<String> FORBIDDEN_SEGMENTS;
+
+    static
+    {
+        FORBIDDEN_SEGMENTS = new HashSet<>();
+        FORBIDDEN_SEGMENTS.add("/./");
+        FORBIDDEN_SEGMENTS.add("/../");
+        FORBIDDEN_SEGMENTS.add("//");
+    }
+
+    private String variables[];
+
+    public UriTemplatePathSpec(String rawSpec)
+    {
+        super();
+        Objects.requireNonNull(rawSpec,"Path Param Spec cannot be null");
+
+        if ("".equals(rawSpec) || "/".equals(rawSpec))
+        {
+            super.pathSpec = "/";
+            super.pattern = Pattern.compile("^/$");
+            super.pathDepth = 1;
+            this.specLength = 1;
+            this.variables = new String[0];
+            this.group = PathSpecGroup.EXACT;
+            return;
+        }
+
+        if (rawSpec.charAt(0) != '/')
+        {
+            // path specs must start with '/'
+            StringBuilder err = new StringBuilder();
+            err.append("Syntax Error: path spec \"");
+            err.append(rawSpec);
+            err.append("\" must start with '/'");
+            throw new IllegalArgumentException(err.toString());
+        }
+
+        for (String forbidden : FORBIDDEN_SEGMENTS)
+        {
+            if (rawSpec.contains(forbidden))
+            {
+                StringBuilder err = new StringBuilder();
+                err.append("Syntax Error: segment ");
+                err.append(forbidden);
+                err.append(" is forbidden in path spec: ");
+                err.append(rawSpec);
+                throw new IllegalArgumentException(err.toString());
+            }
+        }
+
+        this.pathSpec = rawSpec;
+
+        StringBuilder regex = new StringBuilder();
+        regex.append('^');
+
+        List<String> varNames = new ArrayList<>();
+        // split up into path segments (ignoring the first slash that will always be empty)
+        String segments[] = rawSpec.substring(1).split("/");
+        char segmentSignature[] = new char[segments.length];
+        this.pathDepth = segments.length;
+        for (int i = 0; i < segments.length; i++)
+        {
+            String segment = segments[i];
+            Matcher mat = VARIABLE_PATTERN.matcher(segment);
+
+            if (mat.matches())
+            {
+                // entire path segment is a variable.
+                String variable = mat.group(1);
+                if (varNames.contains(variable))
+                {
+                    // duplicate variable names
+                    StringBuilder err = new StringBuilder();
+                    err.append("Syntax Error: variable ");
+                    err.append(variable);
+                    err.append(" is duplicated in path spec: ");
+                    err.append(rawSpec);
+                    throw new IllegalArgumentException(err.toString());
+                }
+
+                assertIsValidVariableLiteral(variable);
+
+                segmentSignature[i] = 'v'; // variable
+                // valid variable name
+                varNames.add(variable);
+                // build regex
+                regex.append("/([^/]+)");
+            }
+            else if (mat.find(0))
+            {
+                // variable exists as partial segment
+                StringBuilder err = new StringBuilder();
+                err.append("Syntax Error: variable ");
+                err.append(mat.group());
+                err.append(" must exist as entire path segment: ");
+                err.append(rawSpec);
+                throw new IllegalArgumentException(err.toString());
+            }
+            else if ((segment.indexOf('{') >= 0) || (segment.indexOf('}') >= 0))
+            {
+                // variable is split with a path separator
+                StringBuilder err = new StringBuilder();
+                err.append("Syntax Error: invalid path segment /");
+                err.append(segment);
+                err.append("/ variable declaration incomplete: ");
+                err.append(rawSpec);
+                throw new IllegalArgumentException(err.toString());
+            }
+            else if (segment.indexOf('*') >= 0)
+            {
+                // glob segment
+                StringBuilder err = new StringBuilder();
+                err.append("Syntax Error: path segment /");
+                err.append(segment);
+                err.append("/ contains a wildcard symbol (not supported by this uri-template implementation): ");
+                err.append(rawSpec);
+                throw new IllegalArgumentException(err.toString());
+            }
+            else
+            {
+                // valid path segment
+                segmentSignature[i] = 'e'; // exact
+                // build regex
+                regex.append('/');
+                // escape regex special characters
+                for (char c : segment.toCharArray())
+                {
+                    if ((c == '.') || (c == '[') || (c == ']') || (c == '\\'))
+                    {
+                        regex.append('\\');
+                    }
+                    regex.append(c);
+                }
+            }
+        }
+        
+        // Handle trailing slash (which is not picked up during split)
+        if(rawSpec.charAt(rawSpec.length()-1) == '/')
+        {
+            regex.append('/');
+        }
+
+        regex.append('$');
+
+        this.pattern = Pattern.compile(regex.toString());
+
+        int varcount = varNames.size();
+        this.variables = varNames.toArray(new String[varcount]);
+
+        // Convert signature to group
+        String sig = String.valueOf(segmentSignature);
+
+        if (Pattern.matches("^e*$",sig))
+        {
+            this.group = PathSpecGroup.EXACT;
+        }
+        else if (Pattern.matches("^e*v+",sig))
+        {
+            this.group = PathSpecGroup.PREFIX_GLOB;
+        }
+        else if (Pattern.matches("^v+e+",sig))
+        {
+            this.group = PathSpecGroup.SUFFIX_GLOB;
+        }
+        else
+        {
+            this.group = PathSpecGroup.MIDDLE_GLOB;
+        }
+    }
+
+    /**
+     * Validate variable literal name, per RFC6570, Section 2.1 Literals
+     * @param variable
+     * @param pathParamSpec
+     */
+    private void assertIsValidVariableLiteral(String variable)
+    {
+        int len = variable.length();
+        
+        int i = 0;
+        int codepoint;
+        boolean valid = (len > 0); // must not be zero length
+        
+        while (valid && i < len)
+        {
+            codepoint = variable.codePointAt(i);
+            i += Character.charCount(codepoint);
+
+            // basic letters, digits, or symbols
+            if (isValidBasicLiteralCodepoint(codepoint))
+            {
+                continue;
+            }
+
+            // The ucschar and iprivate pieces
+            if (Character.isSupplementaryCodePoint(codepoint))
+            {
+                continue;
+            }
+
+            // pct-encoded
+            if (codepoint == '%')
+            {
+                if (i + 2 > len)
+                {
+                    // invalid percent encoding, missing extra 2 chars
+                    valid = false;
+                    continue;
+                }
+                codepoint = TypeUtil.convertHexDigit(variable.codePointAt(i++)) << 4;
+                codepoint |= TypeUtil.convertHexDigit(variable.codePointAt(i++));
+
+                // validate basic literal
+                if (isValidBasicLiteralCodepoint(codepoint))
+                {
+                    continue;
+                }
+            }
+            
+            valid = false;
+        }
+
+        if (!valid)
+        {
+            // invalid variable name
+            StringBuilder err = new StringBuilder();
+            err.append("Syntax Error: variable {");
+            err.append(variable);
+            err.append("} an invalid variable name: ");
+            err.append(pathSpec);
+            throw new IllegalArgumentException(err.toString());
+        }
+    }
+    
+    private boolean isValidBasicLiteralCodepoint(int codepoint)
+    {
+        // basic letters or digits
+        if((codepoint >= 'a' && codepoint <= 'z') ||
+           (codepoint >= 'A' && codepoint <= 'Z') ||
+           (codepoint >= '0' && codepoint <= '9'))
+        {
+            return true;
+        }
+        
+        // basic allowed symbols
+        if(VARIABLE_SYMBOLS.indexOf(codepoint) >= 0)
+        {
+            return true; // valid simple value
+        }
+        
+        // basic reserved symbols
+        if(VARIABLE_RESERVED.indexOf(codepoint) >= 0)
+        {
+            LOG.warn("Detected URI Template reserved symbol [{}] in path spec \"{}\"",(char)codepoint,pathSpec);
+            return false; // valid simple value
+        }
+
+        return false;
+    }
+
+    public Map<String, String> getPathParams(String path)
+    {
+        Matcher matcher = getMatcher(path);
+        if (matcher.matches())
+        {
+            if (group == PathSpecGroup.EXACT)
+            {
+                return Collections.emptyMap();
+            }
+            Map<String, String> ret = new HashMap<>();
+            int groupCount = matcher.groupCount();
+            for (int i = 1; i <= groupCount; i++)
+            {
+                ret.put(this.variables[i - 1],matcher.group(i));
+            }
+            return ret;
+        }
+        return null;
+    }
+
+    public int getVariableCount()
+    {
+        return variables.length;
+    }
+
+    public String[] getVariables()
+    {
+        return this.variables;
+    }
+}
index 7f8e9f81ca023bc595d0656838ebf35513756c2f..28c7082f6135f5f16595649b0550149b06c1ff5a 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -40,7 +40,7 @@ import org.eclipse.jetty.util.thread.NonBlockingThread;
 public abstract class AbstractConnection implements Connection
 {
     private static final Logger LOG = Log.getLogger(AbstractConnection.class);
-    
+
     public static final boolean EXECUTE_ONFILLABLE=true;
 
     private final List<Listener> listeners = new CopyOnWriteArrayList<>();
@@ -56,7 +56,7 @@ public abstract class AbstractConnection implements Connection
     {
         this(endp,executor,EXECUTE_ONFILLABLE);
     }
-    
+
     protected AbstractConnection(EndPoint endp, Executor executor, final boolean executeOnfillable)
     {
         if (executor == null)
@@ -88,7 +88,7 @@ public abstract class AbstractConnection implements Connection
     {
         return _executor;
     }
-    
+
     protected void failedCallback(final Callback callback, final Throwable x)
     {
         if (NonBlockingThread.isNonBlockingThread())
@@ -115,7 +115,7 @@ public abstract class AbstractConnection implements Connection
             callback.failed(x);
         }
     }
-    
+
     /**
      * <p>Utility method to be called to register read interest.</p>
      * <p>After a call to this method, {@link #onFillable()} or {@link #onFillInterestedFailed(Throwable)}
@@ -124,8 +124,9 @@ public abstract class AbstractConnection implements Connection
      */
     public void fillInterested()
     {
-        LOG.debug("fillInterested {}",this);           
-        
+        if (LOG.isDebugEnabled())
+            LOG.debug("fillInterested {}",this);
+
         while(true)
         {
             State state=_state.get();
@@ -133,10 +134,11 @@ public abstract class AbstractConnection implements Connection
                 break;
         }
     }
-    
+
     public void fillInterested(Callback callback)
     {
-        LOG.debug("fillInterested {}",this);
+        if (LOG.isDebugEnabled())
+            LOG.debug("fillInterested {}",this);
 
         while(true)
         {
@@ -149,7 +151,7 @@ public abstract class AbstractConnection implements Connection
                 break;
         }
     }
-    
+
     /**
      * <p>Callback method invoked when the endpoint is ready to be read.</p>
      * @see #fillInterested()
@@ -162,7 +164,8 @@ public abstract class AbstractConnection implements Connection
      */
     protected void onFillInterestedFailed(Throwable cause)
     {
-        LOG.debug("{} onFillInterestedFailed {}", this, cause);
+        if (LOG.isDebugEnabled())
+            LOG.debug("{} onFillInterestedFailed {}", this, cause);
         if (_endPoint.isOpen())
         {
             boolean close = true;
@@ -178,7 +181,7 @@ public abstract class AbstractConnection implements Connection
         }
 
         if (_endPoint.isOpen())
-            fillInterested();        
+            fillInterested();
     }
 
     /**
@@ -193,7 +196,8 @@ public abstract class AbstractConnection implements Connection
     @Override
     public void onOpen()
     {
-        LOG.debug("onOpen {}", this);
+        if (LOG.isDebugEnabled())
+            LOG.debug("onOpen {}", this);
 
         for (Listener listener : listeners)
             listener.onOpened(this);
@@ -202,7 +206,8 @@ public abstract class AbstractConnection implements Connection
     @Override
     public void onClose()
     {
-        LOG.debug("onClose {}",this);
+        if (LOG.isDebugEnabled())
+            LOG.debug("onClose {}",this);
 
         for (Listener listener : listeners)
             listener.onClosed(this);
@@ -253,23 +258,28 @@ public abstract class AbstractConnection implements Connection
     @Override
     public String toString()
     {
-        return String.format("%s@%x{%s}", getClass().getSimpleName(), hashCode(), _state.get());
+        return String.format("%s@%x[%s,%s]",
+                getClass().getSimpleName(),
+                hashCode(),
+                _state.get(),
+                _endPoint);
     }
-    
+
     public boolean next(State state, State next)
     {
         if (next==null)
             return true;
         if(_state.compareAndSet(state,next))
         {
-            LOG.debug("{}-->{} {}",state,next,this);
+            if (LOG.isDebugEnabled())
+                LOG.debug("{}-->{} {}",state,next,this);
             if (next!=state)
                 next.onEnter(AbstractConnection.this);
             return true;
         }
         return false;
     }
-    
+
     private static final class IdleState extends State
     {
         private IdleState()
@@ -402,11 +412,11 @@ public abstract class AbstractConnection implements Connection
         {
             return _name;
         }
-        
+
         void onEnter(AbstractConnection connection)
         {
         }
-        
+
         State fillInterested()
         {
             throw new IllegalStateException(this.toString());
@@ -421,28 +431,28 @@ public abstract class AbstractConnection implements Connection
         {
             throw new IllegalStateException(this.toString());
         }
-        
+
         State onFailed()
         {
             throw new IllegalStateException(this.toString());
         }
     }
-    
+
 
     public static final State IDLE=new IdleState();
-    
+
     public static final State FILL_INTERESTED=new FillInterestedState();
-    
+
     public static final State FILLING=new FillingState();
-    
+
     public static final State REFILLING=new RefillingState();
 
     public static final State FILLING_FILL_INTERESTED=new FillingFillInterestedState("FILLING_FILL_INTERESTED");
-    
+
     public class NestedState extends State
     {
         private final State _nested;
-        
+
         NestedState(State nested)
         {
             super("NESTED("+nested+")");
@@ -465,19 +475,19 @@ public abstract class AbstractConnection implements Connection
         {
             return new NestedState(_nested.onFillable());
         }
-        
+
         @Override
         State onFilled()
         {
             return new NestedState(_nested.onFilled());
         }
     }
-    
-    
+
+
     public class FillingInterestedCallback extends NestedState
     {
         private final Callback _callback;
-        
+
         FillingInterestedCallback(Callback callback,State nested)
         {
             super("FILLING_INTERESTED_CALLBACK",nested==FILLING?REFILLING:nested);
@@ -517,13 +527,13 @@ public abstract class AbstractConnection implements Connection
                             break;
                     }
                     _callback.failed(x);
-                }  
+                }
             };
-            
+
             connection.getEndPoint().fillInterested(callback);
         }
     }
-    
+
     private final Runnable _runOnFillable = new Runnable()
     {
         @Override
@@ -544,10 +554,10 @@ public abstract class AbstractConnection implements Connection
             }
         }
     };
-    
-    
+
+
     private class ReadCallback implements Callback
-    {   
+    {
         @Override
         public void succeeded()
         {
@@ -577,7 +587,7 @@ public abstract class AbstractConnection implements Connection
                 }
             });
         }
-        
+
         @Override
         public String toString()
         {
index 8fa2cc86ef98812bcce0d024df0c3dc834f2b6b5..44a38ecb887a5e18c135ea670311ab232cb368a9 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -23,6 +23,7 @@ import java.net.InetSocketAddress;
 import java.nio.ByteBuffer;
 import java.util.concurrent.TimeoutException;
 
+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;
@@ -44,7 +45,7 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint
             return AbstractEndPoint.this.needsFill();
         }
     };
-    
+
     private final WriteFlusher _writeFlusher = new WriteFlusher(this)
     {
         @Override
@@ -78,7 +79,7 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint
     {
         return _remote;
     }
-    
+
     @Override
     public Connection getConnection()
     {
@@ -94,7 +95,8 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint
     @Override
     public void onOpen()
     {
-        LOG.debug("onOpen {}",this);
+        if (LOG.isDebugEnabled())
+            LOG.debug("onOpen {}",this);
         super.onOpen();
     }
 
@@ -102,11 +104,12 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint
     public void onClose()
     {
         super.onClose();
-        LOG.debug("onClose {}",this);
+        if (LOG.isDebugEnabled())
+            LOG.debug("onClose {}",this);
         _writeFlusher.onClose();
         _fillInterest.onClose();
     }
-    
+
     @Override
     public void close()
     {
@@ -147,24 +150,45 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint
         boolean input_shutdown=isInputShutdown();
         boolean fillFailed = _fillInterest.onFail(timeout);
         boolean writeFailed = _writeFlusher.onFail(timeout);
-        
-        // If the endpoint is half closed and there was no onFail handling, the close here
-        // This handles the situation where the connection has completed its close handling 
+
+        // If the endpoint is half closed and there was no fill/write handling, then close here.
+        // This handles the situation where the connection has completed its close handling
         // and the endpoint is half closed, but the other party does not complete the close.
         // This perhaps should not check for half closed, however the servlet spec case allows
-        // for a dispatched servlet or suspended request to extend beyond the connections idle 
-        // time.  So if this test would always close an idle endpoint that is not handled, then 
+        // for a dispatched servlet or suspended request to extend beyond the connections idle
+        // time.  So if this test would always close an idle endpoint that is not handled, then
         // we would need a mode to ignore timeouts for some HTTP states
         if (isOpen() && (output_shutdown || input_shutdown) && !(fillFailed || writeFailed))
             close();
-        else 
+        else
             LOG.debug("Ignored idle endpoint {}",this);
     }
 
+    @Override
+    public void upgrade(Connection newConnection)
+    {
+        Connection old_connection = getConnection();
+
+        if (LOG.isDebugEnabled())
+            LOG.debug("{} upgrading from {} to {}", this, old_connection, newConnection);
+
+        ByteBuffer prefilled = (old_connection instanceof Connection.UpgradeFrom)
+                ?((Connection.UpgradeFrom)old_connection).onUpgradeFrom():null;
+        old_connection.onClose();
+        old_connection.getEndPoint().setConnection(newConnection);
+
+        if (newConnection instanceof Connection.UpgradeTo)
+            ((Connection.UpgradeTo)newConnection).onUpgradeTo(prefilled);
+        else if (BufferUtil.hasContent(prefilled))
+            throw new IllegalStateException();
+
+        newConnection.onOpen();
+    }
+
     @Override
     public String toString()
     {
-        return String.format("%s@%x{%s<->%d,%s,%s,%s,%s,%s,%d,%s}",
+        return String.format("%s@%x{%s<->%d,%s,%s,%s,%s,%s,%d/%d,%s}",
                 getClass().getSimpleName(),
                 hashCode(),
                 getRemoteAddress(),
@@ -174,6 +198,7 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint
                 isOutputShutdown()?"OSHUT":"out",
                 _fillInterest.isInterested()?"R":"-",
                 _writeFlusher.isInProgress()?"W":"-",
+                getIdleFor(),
                 getIdleTimeout(),
                 getConnection()==null?null:getConnection().getClass().getSimpleName());
     }
index fa3a01d0a0c49d04a3667b930be63f858e5ba043..86b49722df24ba89d940ee92857b5ce20e913fdf 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 4b8c527c2f675af1137acef42bccdbd2ad290013..73cea8c83d18a888f1c0c1fec3ef94c1146c0755 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 302adde35d879be5795b727ec8f47140bae5a352..4b5bada4f71a9a9806ee31372d81ab6710cf4035 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index c65ca0ccfc874c1e5fee2f6290f17570976a521b..5ce60e7bb1ec4fd02950a572c640c75e232e6099 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -61,7 +61,8 @@ public class ChannelEndPoint extends AbstractEndPoint
 
     protected void shutdownInput()
     {
-        LOG.debug("ishut {}", this);
+        if (LOG.isDebugEnabled())
+            LOG.debug("ishut {}", this);
         _ishut=true;
         if (_oshut)
             close();
@@ -70,7 +71,8 @@ public class ChannelEndPoint extends AbstractEndPoint
     @Override
     public void shutdownOutput()
     {
-        LOG.debug("oshut {}", this);
+        if (LOG.isDebugEnabled())
+            LOG.debug("oshut {}", this);
         _oshut = true;
         if (_channel.isOpen())
         {
@@ -109,7 +111,8 @@ public class ChannelEndPoint extends AbstractEndPoint
     public void close()
     {
         super.close();
-        LOG.debug("close {}", this);
+        if (LOG.isDebugEnabled())
+            LOG.debug("close {}", this);
         try
         {
             _channel.close();
index 7eb59318409026f88d9fe51f976e9669e65df932..a11fe8e43cdd95f7532d1f507e1a7dff1e8f80f4 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -19,6 +19,7 @@
 package org.eclipse.jetty.io;
 
 import java.io.IOException;
+import java.nio.ByteBuffer;
 import java.util.Map;
 
 import org.eclipse.jetty.util.log.Log;
@@ -51,7 +52,7 @@ public interface ClientConnectionFactory
          * {@link EndPoint} associated with {@code oldConnection}, performing connection lifecycle management.
          * <p />
          * The {@code oldConnection} will be closed by invoking {@link org.eclipse.jetty.io.Connection#onClose()}
-         * and the {@code newConnection} will be opened by invoking {@link org.eclipse.jetty.io.Connection#onOpen()}.
+         * and the {@code newConnection} will be opened by invoking {@link org.eclipse.jetty.io.Connection#onOpen(ByteBuffer)}.
          * @param oldConnection the old connection to replace
          * @param newConnection the new connection replacement
          */
index 96baa01676fcf17bc3108758285f2c886d4133ee..5c7d564d749303dab24b324ced45805da5888825 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
 package org.eclipse.jetty.io;
 
 import java.io.Closeable;
-
-import org.eclipse.jetty.util.Callback;
+import java.nio.ByteBuffer;
 
 /**
  * <p>A {@link Connection} is associated to an {@link EndPoint} so that I/O events
  * happening on the {@link EndPoint} can be processed by the {@link Connection}.</p>
- * <p>A typical implementation of {@link Connection} overrides {@link #onOpen()} to
+ * <p>A typical implementation of {@link Connection} overrides {@link #onOpen(ByteBuffer)} to
  * {@link EndPoint#fillInterested(Callback) set read interest} on the {@link EndPoint},
  * and when the {@link EndPoint} signals read readyness, this {@link Connection} can
  * read bytes from the network and interpret them.</p>
@@ -34,10 +33,6 @@ public interface Connection extends Closeable
 {
     public void addListener(Listener listener);
 
-    /**
-     * <p>Callback method invoked when this {@link Connection} is opened.</p>
-     * <p>Creators of the connection implementation are responsible for calling this method.</p>
-     */
     public void onOpen();
 
     /**
@@ -50,7 +45,7 @@ public interface Connection extends Closeable
      * @return the {@link EndPoint} associated with this {@link Connection}
      */
     public EndPoint getEndPoint();
-
+    
     /**
      * <p>Performs a logical close of this connection.</p>
      * <p>For simple connections, this may just mean to delegate the close to the associated
@@ -66,6 +61,30 @@ public interface Connection extends Closeable
     public long getBytesOut();
     public long getCreatedTimeStamp();
     
+    public interface UpgradeFrom extends Connection
+    {
+        /* ------------------------------------------------------------ */
+        /** Take the input buffer from the connection on upgrade.
+         * <p>This method is used to take any unconsumed input from
+         * a connection during an upgrade.
+         * @return A buffer of unconsumed input. The caller must return the buffer
+         * to the bufferpool when consumed and this connection must not.
+         */
+        ByteBuffer onUpgradeFrom();
+    }
+    
+    public interface UpgradeTo extends Connection
+    {
+        /**
+         * <p>Callback method invoked when this {@link Connection} is upgraded.</p>
+         * <p>This must be called before {@link #onOpen()}.</p>
+         * @param prefilledBuffer An optional buffer that can contain prefilled data. Typically this
+         * results from an upgrade of one protocol to the other where the old connection has buffered
+         * data destined for the new connection.  The new connection must take ownership of the buffer
+         * and is responsible for returning it to the buffer pool
+         */
+        void onUpgradeTo(ByteBuffer prefilled);
+    }
     
     public interface Listener
     {
index 87adb40be1ff17aafc995bf0f393de58ccbe50d1..c96dcb8b775b1fe122f93c5adfe358722a507127 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -26,8 +26,6 @@ import java.nio.channels.ReadPendingException;
 import java.nio.channels.WritePendingException;
 
 import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.FutureCallback;
-
 
 /**
  *
@@ -224,6 +222,7 @@ public interface EndPoint extends Closeable
     /**
      * @param connection the {@link Connection} associated with this {@link EndPoint}
      * @see #getConnection()
+     * @see #upgrade(Connection)
      */
     void setConnection(Connection connection);
 
@@ -239,5 +238,13 @@ public interface EndPoint extends Closeable
      */
     void onClose();
 
-    
+
+    /** Upgrade connections.
+     * Close the old connection, update the endpoint and open the new connection.
+     * If the oldConnection is an instance of {@link Connection.UpgradeFrom} then
+     * a prefilled buffer is requested and passed to the newConnection if it is an instance
+     * of {@link Connection.UpgradeTo}
+     * @param newConnection The connection to upgrade to
+     */
+    public void upgrade(Connection newConnection);
 }
index 72042f4016c91603a4ee1ce8ffef7be3d741abdc..29aa5e0c504eba9c1c9a5c56c2b91c5ca2b39136 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index b2c3f6855591b769c4f9c7a8239efc67e08afe2d..a2343975822fe58103a762d5c084fa2c8cf040cf 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -58,7 +58,7 @@ public abstract class FillInterest
         
         if (!_interested.compareAndSet(null,callback))
         {
-            LOG.warn("Read pending for "+_interested.get()+" pervented "+callback);
+            LOG.warn("Read pending for "+_interested.get()+" prevented "+callback);
             throw new ReadPendingException();
         }
         try
index 8b251ac862c92bd592400445f7408890d031d4ab..d8a6c274d82391eaa9d8de08186c1482cfc7b098 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -66,6 +66,11 @@ public abstract class IdleTimeout
         return _idleTimestamp;
     }
 
+    public long getIdleFor()
+    {
+        return System.currentTimeMillis() - getIdleTimestamp();
+    }
+
     public long getIdleTimeout()
     {
         return _idleTimeout;
@@ -142,13 +147,15 @@ public abstract class IdleTimeout
             long idleElapsed = System.currentTimeMillis() - idleTimestamp;
             long idleLeft = idleTimeout - idleElapsed;
 
-            LOG.debug("{} idle timeout check, elapsed: {} ms, remaining: {} ms", this, idleElapsed, idleLeft);
+            if (LOG.isDebugEnabled())
+                LOG.debug("{} idle timeout check, elapsed: {} ms, remaining: {} ms", this, idleElapsed, idleLeft);
 
             if (idleTimestamp != 0 && idleTimeout > 0)
             {
                 if (idleLeft <= 0)
                 {
-                    LOG.debug("{} idle timeout expired", this);
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("{} idle timeout expired", this);
                     try
                     {
                         onIdleExpired(new TimeoutException("Idle timeout expired: " + idleElapsed + "/" + idleTimeout + " ms"));
index a6fc7562d2e750982d49ed89e04e95f0d6d5c56f..f9ac66e7259f54b777015086fd85e36bd4b5369d 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -19,7 +19,9 @@
 package org.eclipse.jetty.io;
 
 import java.nio.ByteBuffer;
+import java.util.concurrent.atomic.AtomicLong;
 
+import org.eclipse.jetty.util.BufferUtil;
 import org.eclipse.jetty.util.LeakDetector;
 import org.eclipse.jetty.util.component.ContainerLifeCycle;
 import org.eclipse.jetty.util.log.Log;
@@ -31,14 +33,24 @@ public class LeakTrackingByteBufferPool extends ContainerLifeCycle implements By
 
     private final LeakDetector<ByteBuffer> leakDetector = new LeakDetector<ByteBuffer>()
     {
+        public String id(ByteBuffer resource)
+        {
+            return BufferUtil.toIDString(resource);
+        }
+
         @Override
         protected void leaked(LeakInfo leakInfo)
         {
+            leaked.incrementAndGet();
             LeakTrackingByteBufferPool.this.leaked(leakInfo);
         }
     };
-    
+
+    private final static boolean NOISY = Boolean.getBoolean(LeakTrackingByteBufferPool.class.getName() + ".NOISY");
     private final ByteBufferPool delegate;
+    private final AtomicLong leakedReleases = new AtomicLong(0);
+    private final AtomicLong leakedAcquires = new AtomicLong(0);
+    private final AtomicLong leaked = new AtomicLong(0);
 
     public LeakTrackingByteBufferPool(ByteBufferPool delegate)
     {
@@ -51,8 +63,13 @@ public class LeakTrackingByteBufferPool extends ContainerLifeCycle implements By
     public ByteBuffer acquire(int size, boolean direct)
     {
         ByteBuffer buffer = delegate.acquire(size, direct);
-        if (!leakDetector.acquired(buffer))
-            LOG.warn("ByteBuffer {}@{} not tracked", buffer, System.identityHashCode(buffer));
+        boolean leaked = leakDetector.acquired(buffer);
+        if (NOISY || !leaked)
+        {
+            leakedAcquires.incrementAndGet();
+            LOG.info(String.format("ByteBuffer acquire %s leaked.acquired=%s", leakDetector.id(buffer), leaked ? "normal" : "LEAK"),
+                    new Throwable("LeakStack.Acquire"));
+        }
         return buffer;
     }
 
@@ -61,11 +78,46 @@ public class LeakTrackingByteBufferPool extends ContainerLifeCycle implements By
     {
         if (buffer == null)
             return;
-        if (!leakDetector.released(buffer))
-            LOG.warn("ByteBuffer {}@{} released but not acquired", buffer, System.identityHashCode(buffer));
+        boolean leaked = leakDetector.released(buffer);
+        if (NOISY || !leaked)
+        {
+            leakedReleases.incrementAndGet();
+            LOG.info(String.format("ByteBuffer release %s leaked.released=%s", leakDetector.id(buffer), leaked ? "normal" : "LEAK"), new Throwable(
+                    "LeakStack.Release"));
+        }
         delegate.release(buffer);
     }
 
+    public void clearTracking()
+    {
+        leakedAcquires.set(0);
+        leakedReleases.set(0);
+    }
+
+    /**
+     * @return count of BufferPool.acquire() calls that detected a leak
+     */
+    public long getLeakedAcquires()
+    {
+        return leakedAcquires.get();
+    }
+
+    /**
+     * @return count of BufferPool.release() calls that detected a leak
+     */
+    public long getLeakedReleases()
+    {
+        return leakedReleases.get();
+    }
+
+    /**
+     * @return count of resources that were acquired but not released
+     */
+    public long getLeakedResources()
+    {
+        return leaked.get();
+    }
+
     protected void leaked(LeakDetector<ByteBuffer>.LeakInfo leakInfo)
     {
         LOG.warn("ByteBuffer " + leakInfo.getResourceDescription() + " leaked at:", leakInfo.getStackFrames());
index b331904c4ef26180e216b09afe245cd92d5d9bcd..bc9e8147360fb7c9ff752751d353f8a93e27d7ea 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -23,6 +23,7 @@ import java.util.Queue;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import org.eclipse.jetty.util.BufferUtil;
 
@@ -56,13 +57,19 @@ public class MappedByteBufferPool implements ByteBufferPool
         if (result == null)
         {
             int capacity = bucket * factor;
-            result = direct ? BufferUtil.allocateDirect(capacity) : BufferUtil.allocate(capacity);
+            result = newByteBuffer(capacity, direct);
         }
 
         BufferUtil.clear(result);
         return result;
     }
 
+    protected ByteBuffer newByteBuffer(int capacity, boolean direct)
+    {
+        return direct ? BufferUtil.allocateDirect(capacity)
+                      : BufferUtil.allocate(capacity);
+    }
+
     @Override
     public void release(ByteBuffer buffer)
     {
@@ -108,4 +115,20 @@ public class MappedByteBufferPool implements ByteBufferPool
     {
         return direct ? directBuffers : heapBuffers;
     }
+
+    public static class Tagged extends MappedByteBufferPool
+    {
+        private final AtomicInteger tag = new AtomicInteger();
+
+        @Override
+        protected ByteBuffer newByteBuffer(int capacity, boolean direct)
+        {
+            ByteBuffer buffer = super.newByteBuffer(capacity + 4, direct);
+            buffer.limit(buffer.capacity());
+            buffer.putInt(tag.incrementAndGet());
+            ByteBuffer slice = buffer.slice();
+            BufferUtil.clear(slice);
+            return slice;
+        }
+    }
 }
index cd05630f62f98f02a1bc5982cc68e33d07bf579b..f0a8b1f3e7dd00c1b872826efc0310459ddefc16 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
 package org.eclipse.jetty.io;
 
 import java.io.IOException;
+import java.nio.ByteBuffer;
 import java.util.Map;
 import java.util.concurrent.Executor;
+
 import javax.net.ssl.SSLEngine;
 
 import org.eclipse.jetty.util.BufferUtil;
index ff3860071f70ff3f5f93e44d5c592b528be2c6a8..5f20837cdffca5489166fc4622b902335d264904 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 6a4239f0e10f5a01c223069af70ad25c95d46d8e..3a04207ca06f7e6cb6ab19d94c35aa9fb2d3ae3c 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index a4b6f7d2a163cbbf15c863219a7eb9648aac0f28..bf7606bae3cee176e2b2c523c2eb643c4e3eb0a6 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -25,7 +25,6 @@ import java.nio.channels.SelectionKey;
 import java.nio.channels.SocketChannel;
 import java.util.List;
 
-import org.eclipse.jetty.util.BufferUtil;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.util.thread.Scheduler;
index 88c33f73832a88eb9b8051e20eb0dfafe50a2b34..5f0e95b609e1564b86b591a853b55b4853d979e0 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 30504029947bf3d54df33045eb3e7c04328cc99a..6eec73d43dae5bfdf5375605d8cce22ecceea4ae 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -132,18 +132,21 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements SelectorMa
             {
                 if (_interestOps.compareAndSet(oldInterestOps, newInterestOps))
                 {
-                    LOG.debug("Local interests updated {} -> {} for {}", oldInterestOps, newInterestOps, this);
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Local interests updating {} -> {} for {}", oldInterestOps, newInterestOps, this);
                     _selector.updateKey(_updateTask);
                 }
                 else
                 {
-                    LOG.debug("Local interests update conflict: now {}, was {}, attempted {} for {}", _interestOps.get(), oldInterestOps, newInterestOps, this);
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Local interests update conflict: now {}, was {}, attempted {} for {}", _interestOps.get(), oldInterestOps, newInterestOps, this);
                     continue;
                 }
             }
             else
             {
-                LOG.debug("Ignoring local interests update {} -> {} for {}", oldInterestOps, newInterestOps, this);
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Ignoring local interests update {} -> {} for {}", oldInterestOps, newInterestOps, this);
             }
             break;
         }
@@ -152,8 +155,9 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements SelectorMa
 
     private void setKeyInterests(int oldInterestOps, int newInterestOps)
     {
-        LOG.debug("Key interests updated {} -> {}", oldInterestOps, newInterestOps);
         _key.interestOps(newInterestOps);
+        if (LOG.isDebugEnabled())
+            LOG.debug("Key interests updated {} -> {} on {}", oldInterestOps, newInterestOps, this);
     }
 
     @Override
index fd3c6c6b9eedb0537203bc225be576c3fc036e5c..26a18c3d3b34ef6bc7d63b43522c2d5d987cbe27 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -41,6 +41,7 @@ import java.util.concurrent.atomic.AtomicReference;
 
 import org.eclipse.jetty.util.ConcurrentArrayQueue;
 import org.eclipse.jetty.util.TypeUtil;
+import org.eclipse.jetty.util.annotation.ManagedAttribute;
 import org.eclipse.jetty.util.component.AbstractLifeCycle;
 import org.eclipse.jetty.util.component.ContainerLifeCycle;
 import org.eclipse.jetty.util.component.Dumpable;
@@ -60,14 +61,15 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
     public static final String SUBMIT_KEY_UPDATES = "org.eclipse.jetty.io.SelectorManager.submitKeyUpdates";
     public static final int DEFAULT_CONNECT_TIMEOUT = 15000;
     protected static final Logger LOG = Log.getLogger(SelectorManager.class);
-    private final static boolean __submitKeyUpdates = Boolean.valueOf(System.getProperty(SUBMIT_KEY_UPDATES, "false"));
-    
+    private final static boolean __submitKeyUpdates = Boolean.valueOf(System.getProperty(SUBMIT_KEY_UPDATES, "true"));
+
     private final Executor executor;
     private final Scheduler scheduler;
     private final ManagedSelector[] _selectors;
     private long _connectTimeout = DEFAULT_CONNECT_TIMEOUT;
     private long _selectorIndex;
-    
+    private int _priorityDelta;
+
     protected SelectorManager(Executor executor, Scheduler scheduler)
     {
         this(executor, scheduler, (Runtime.getRuntime().availableProcessors() + 1) / 2);
@@ -112,6 +114,42 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
         _connectTimeout = milliseconds;
     }
 
+
+    @ManagedAttribute("The priority delta to apply to selector threads")
+    public int getSelectorPriorityDelta()
+    {
+        return _priorityDelta;
+    }
+
+    /**
+     * Sets the selector thread priority delta to the given amount.
+     * <p>This allows the selector threads to run at a different priority.
+     * Typically this would be used to lower the priority to give preference
+     * to handling previously accepted connections rather than accepting
+     * new connections.</p>
+     *
+     * @param selectorPriorityDelta the amount to change the thread priority
+     *                              delta to (may be negative)
+     * @see Thread#getPriority()
+     */
+    public void setSelectorPriorityDelta(int selectorPriorityDelta)
+    {
+        int oldDelta = _priorityDelta;
+        _priorityDelta = selectorPriorityDelta;
+        if (oldDelta != selectorPriorityDelta && isStarted())
+        {
+            for (ManagedSelector selector : _selectors)
+            {
+                Thread thread = selector._thread;
+                if (thread != null)
+                {
+                    int deltaDiff = selectorPriorityDelta - oldDelta;
+                    thread.setPriority(Math.max(Thread.MIN_PRIORITY, Math.min(Thread.MAX_PRIORITY, thread.getPriority() - deltaDiff)));
+                }
+            }
+        }
+    }
+
     /**
      * Executes the given task in a different thread.
      *
@@ -142,11 +180,13 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
 
     /**
      * <p>Registers a channel to perform a non-blocking connect.</p>
-     * <p>The channel must be set in non-blocking mode, and {@link SocketChannel#connect(SocketAddress)}
-     * must be called prior to calling this method.</p>
+     * <p>The channel must be set in non-blocking mode, {@link SocketChannel#connect(SocketAddress)}
+     * must be called prior to calling this method, and the connect operation must not be completed
+     * (the return value of {@link SocketChannel#connect(SocketAddress)} must be false).</p>
      *
      * @param channel    the channel to register
      * @param attachment the attachment object
+     * @see #accept(SocketChannel, Object)
      */
     public void connect(SocketChannel channel, Object attachment)
     {
@@ -154,33 +194,44 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
         set.submit(set.new Connect(channel, attachment));
     }
 
+    /**
+     * @see #accept(SocketChannel, Object)
+     */
+    public void accept(SocketChannel channel)
+    {
+        accept(channel, null);
+    }
+
     /**
      * <p>Registers a channel to perform non-blocking read/write operations.</p>
      * <p>This method is called just after a channel has been accepted by {@link ServerSocketChannel#accept()},
-     * or just after having performed a blocking connect via {@link Socket#connect(SocketAddress, int)}.</p>
+     * or just after having performed a blocking connect via {@link Socket#connect(SocketAddress, int)}, or
+     * just after a non-blocking connect via {@link SocketChannel#connect(SocketAddress)} that completed
+     * successfully.</p>
      *
      * @param channel the channel to register
+     * @param attachment the attachment object
      */
-    public void accept(final SocketChannel channel)
+    public void accept(SocketChannel channel, Object attachment)
     {
         final ManagedSelector selector = chooseSelector();
-        selector.submit(selector.new Accept(channel));
+        selector.submit(selector.new Accept(channel, attachment));
     }
-    
+
     /**
      * <p>Registers a server channel for accept operations.
      * When a {@link SocketChannel} is accepted from the given {@link ServerSocketChannel}
      * then the {@link #accepted(SocketChannel)} method is called, which must be
      * overridden by a derivation of this class to handle the accepted channel
-     * 
+     *
      * @param server the server channel to register
      */
-    public void acceptor(final ServerSocketChannel server)
+    public void acceptor(ServerSocketChannel server)
     {
         final ManagedSelector selector = chooseSelector();
         selector.submit(selector.new Acceptor(server));
     }
-    
+
     /**
      * Callback method when a channel is accepted from the {@link ServerSocketChannel}
      * passed to {@link #acceptor(ServerSocketChannel)}.
@@ -263,7 +314,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
             if (isRunning())
                 LOG.warn("Exception while notifying connection " + connection, x);
             else
-                LOG.debug("Exception while notifying connection {}",connection, x);
+                LOG.debug("Exception while notifying connection " + connection, x);
+            throw x;
         }
     }
 
@@ -377,17 +429,19 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
         @Override
         protected void doStop() throws Exception
         {
-            LOG.debug("Stopping {}", this);
+            if (LOG.isDebugEnabled())
+                LOG.debug("Stopping {}", this);
             Stop stop = new Stop();
             submit(stop);
             stop.await(getStopTimeout());
-            LOG.debug("Stopped {}", this);
+            if (LOG.isDebugEnabled())
+                LOG.debug("Stopped {}", this);
         }
 
         /**
          * Submit a task to update a selector key.  If the System property {@link SelectorManager#SUBMIT_KEY_UPDATES}
-         * is set true (default is false), the task is passed to {@link #submit(Runnable)}.   Otherwise it is run immediately and the selector 
-         * woken up if need be.   
+         * is set true (default is false), the task is passed to {@link #submit(Runnable)}.   Otherwise it is run immediately and the selector
+         * woken up if need be.
          * @param update the update to a key
          */
         public void updateKey(Runnable update)
@@ -398,12 +452,16 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
             }
             else
             {
-                runChange(update);
+                // Run only 1 change at once
+                synchronized (this)
+                {
+                    runChange(update);
+                }
                 if (_state.compareAndSet(State.SELECT, State.WAKEUP))
                    wakeup();
             }
         }
-        
+
         /**
          * <p>Submits a change to be executed in the selector thread.</p>
          * <p>Changes may be submitted from any thread, and the selector thread woken up
@@ -419,7 +477,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
             // change to the queue and process the state.
 
             _changes.offer(change);
-            LOG.debug("Queued change {}", change);
+            if (LOG.isDebugEnabled())
+                LOG.debug("Queued change {}", change);
 
             out: while (true)
             {
@@ -463,7 +522,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
         {
             try
             {
-                LOG.debug("Running change {}", change);
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Running change {}", change);
                 change.run();
             }
             catch (Throwable x)
@@ -477,18 +537,27 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
         {
             _thread = Thread.currentThread();
             String name = _thread.getName();
+            int priority = _thread.getPriority();
             try
             {
-                _thread.setName(name + "-selector-" + SelectorManager.this.getClass().getSimpleName()+"@"+Integer.toHexString(SelectorManager.this.hashCode())+"/"+_id);
-                LOG.debug("Starting {} on {}", _thread, this);
+                if (_priorityDelta != 0)
+                    _thread.setPriority(Math.max(Thread.MIN_PRIORITY, Math.min(Thread.MAX_PRIORITY, priority + _priorityDelta)));
+
+                _thread.setName(String.format("%s-selector-%s@%h/%d", name, SelectorManager.this.getClass().getSimpleName(), SelectorManager.this.hashCode(), _id));
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Starting {} on {}", _thread, this);
                 while (isRunning())
                     select();
-                runChanges();
+                while(isStopping())
+                    runChanges();
             }
             finally
             {
-                LOG.debug("Stopped {} on {}", _thread, this);
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Stopped {} on {}", _thread, this);
                 _thread.setName(name);
+                if (_priorityDelta != 0)
+                    _thread.setPriority(priority);
             }
         }
 
@@ -519,7 +588,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
                             _state.set(State.CHANGES);
                             continue;
                         default:
-                            throw new IllegalStateException();    
+                            throw new IllegalStateException();
                     }
                 }
                 // Must check first for SELECT and *then* for WAKEUP
@@ -607,10 +676,16 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
                 boolean connected = finishConnect(channel);
                 if (connected)
                 {
-                    connect.timeout.cancel();
-                    key.interestOps(0);
-                    EndPoint endpoint = createEndPoint(channel, key);
-                    key.attach(endpoint);
+                    if (connect.timeout.cancel())
+                    {
+                        key.interestOps(0);
+                        EndPoint endpoint = createEndPoint(channel, key);
+                        key.attach(endpoint);
+                    }
+                    else
+                    {
+                        throw new SocketTimeoutException("Concurrent Connect Timeout");
+                    }
                 }
                 else
                 {
@@ -622,7 +697,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
                 connect.failed(x);
             }
         }
-        
+
         private void processAccept(SelectionKey key)
         {
             ServerSocketChannel server = (ServerSocketChannel)key.channel();
@@ -671,13 +746,15 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
             Connection connection = newConnection(channel, endPoint, selectionKey.attachment());
             endPoint.setConnection(connection);
             connectionOpened(connection);
-            LOG.debug("Created {}", endPoint);
+            if (LOG.isDebugEnabled())
+                LOG.debug("Created {}", endPoint);
             return endPoint;
         }
 
         public void destroyEndPoint(EndPoint endPoint)
         {
-            LOG.debug("Destroyed {}", endPoint);
+            if (LOG.isDebugEnabled())
+                LOG.debug("Destroyed {}", endPoint);
             Connection connection = endPoint.getConnection();
             if (connection != null)
                 connectionClosed(connection);
@@ -792,7 +869,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
                 try
                 {
                     SelectionKey key = _channel.register(_selector, SelectionKey.OP_ACCEPT, null);
-                    LOG.debug("{} acceptor={}", this, key);
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("{} acceptor={}", this, key);
                 }
                 catch (Throwable x)
                 {
@@ -804,11 +882,13 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
 
         private class Accept implements Runnable
         {
-            private final SocketChannel _channel;
+            private final SocketChannel channel;
+            private final Object attachment;
 
-            public Accept(SocketChannel channel)
+            private Accept(SocketChannel channel, Object attachment)
             {
-                this._channel = channel;
+                this.channel = channel;
+                this.attachment = attachment;
             }
 
             @Override
@@ -816,13 +896,13 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
             {
                 try
                 {
-                    SelectionKey key = _channel.register(_selector, 0, null);
-                    EndPoint endpoint = createEndPoint(_channel, key);
+                    SelectionKey key = channel.register(_selector, 0, attachment);
+                    EndPoint endpoint = createEndPoint(channel, key);
                     key.attach(endpoint);
                 }
                 catch (Throwable x)
                 {
-                    closeNoExceptions(_channel);
+                    closeNoExceptions(channel);
                     LOG.debug(x);
                 }
             }
@@ -835,7 +915,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
             private final Object attachment;
             private final Scheduler.Task timeout;
 
-            public Connect(SocketChannel channel, Object attachment)
+            private Connect(SocketChannel channel, Object attachment)
             {
                 this.channel = channel;
                 this.attachment = attachment;
@@ -855,7 +935,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
                 }
             }
 
-            protected void failed(Throwable failure)
+            private void failed(Throwable failure)
             {
                 if (failed.compareAndSet(false, true))
                 {
@@ -881,8 +961,9 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
                 SocketChannel channel = connect.channel;
                 if (channel.isConnectionPending())
                 {
-                    LOG.debug("Channel {} timed out while connecting, closing it", channel);
-                    connect.failed(new SocketTimeoutException());
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Channel {} timed out while connecting, closing it", channel);
+                    connect.failed(new SocketTimeoutException("Connect Timeout"));
                 }
             }
         }
index 6898ddfb93f6bee534d9be5a04f05672507e1648..928605e1e4b3dfa95b585154d37bc5700182b01c 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -129,7 +129,8 @@ public class UncheckedPrintWriter extends PrintWriter
             _ioException.initCause(th);
         }
 
-        LOG.debug(th);
+        if (LOG.isDebugEnabled())
+            LOG.debug(th);
     }
 
 
index fccc622955218f1f5765e020415d942bc86d4162..ed594c12475b52487ae761acb80fb9e7fc467eb4 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -46,7 +46,7 @@ abstract public class WriteFlusher
 {
     private static final Logger LOG = Log.getLogger(WriteFlusher.class);
     private static final boolean DEBUG = LOG.isDebugEnabled(); // Easy for the compiler to remove the code if DEBUG==false
-    private static final ByteBuffer[] EMPTY_BUFFERS = new ByteBuffer[0];
+    private static final ByteBuffer[] EMPTY_BUFFERS = new ByteBuffer[]{BufferUtil.EMPTY_BUFFER};
     private static final EnumMap<StateType, Set<StateType>> __stateTransitions = new EnumMap<>(StateType.class);
     private static final State __IDLE = new IdleState();
     private static final State __WRITING = new WritingState();
@@ -245,7 +245,7 @@ abstract public class WriteFlusher
         private PendingState(ByteBuffer[] buffers, Callback callback)
         {
             super(StateType.PENDING);
-            _buffers = compact(buffers);
+            _buffers = buffers;
             _callback = callback;
         }
 
@@ -269,41 +269,6 @@ abstract public class WriteFlusher
             if (_callback!=null)
                 _callback.succeeded();
         }
-
-        /**
-         * Compacting the buffers is needed because the semantic of WriteFlusher is
-         * to write the buffers and if the caller sees that the buffer is consumed,
-         * then it can recycle it.
-         * If we do not compact, then it is possible that we store a consumed buffer,
-         * which is then recycled and refilled; when the WriteFlusher is invoked to
-         * complete the write, it will write the refilled bytes, garbling the content.
-         *
-         * @param buffers the buffers to compact
-         * @return the compacted buffers
-         */
-        private ByteBuffer[] compact(ByteBuffer[] buffers)
-        {
-            int length = buffers.length;
-
-            // Just one element, no need to compact
-            if (length < 2)
-                return buffers;
-
-            // How many still have content ?
-            int consumed = 0;
-            while (consumed < length && BufferUtil.isEmpty(buffers[consumed]))
-                ++consumed;
-
-            // All of them still have content, no need to compact
-            if (consumed == 0)
-                return buffers;
-
-            // None has content, return empty
-            if (consumed == length)
-                return EMPTY_BUFFERS;
-
-            return Arrays.copyOfRange(buffers,consumed,length);
-        }
     }
 
     /**
@@ -334,22 +299,19 @@ abstract public class WriteFlusher
 
         try
         {
-            boolean flushed=_endPoint.flush(buffers);
-            if (DEBUG)
-                LOG.debug("flushed {}", flushed);
+            buffers=flush(buffers);
 
-            // Are we complete?
-            for (ByteBuffer b : buffers)
+            // if we are incomplete?
+            if (buffers!=null)
             {
-                if (!flushed||BufferUtil.hasContent(b))
-                {
-                    PendingState pending=new PendingState(buffers, callback);
-                    if (updateState(__WRITING,pending))
-                        onIncompleteFlushed();
-                    else
-                        fail(pending);
-                    return;
-                }
+                if (DEBUG)
+                    LOG.debug("flushed incomplete");
+                PendingState pending=new PendingState(buffers, callback);
+                if (updateState(__WRITING,pending))
+                    onIncompleteFlushed();
+                else
+                    fail(pending);
+                return;
             }
 
             // If updateState didn't succeed, we don't care as our buffers have been written
@@ -382,7 +344,7 @@ abstract public class WriteFlusher
      * {@link #onFail(Throwable)} or {@link #onClose()}
      */
     public void completeWrite()
-    {
+    {         
         if (DEBUG)
             LOG.debug("completeWrite: {}", this);
 
@@ -399,21 +361,20 @@ abstract public class WriteFlusher
         {
             ByteBuffer[] buffers = pending.getBuffers();
 
-            boolean flushed=_endPoint.flush(buffers);
-            if (DEBUG)
-                LOG.debug("flushed {}", flushed);
+            buffers=flush(buffers);
 
-            // Are we complete?
-            for (ByteBuffer b : buffers)
+            // if we are incomplete?
+            if (buffers!=null)
             {
-                if (!flushed || BufferUtil.hasContent(b))
-                {
-                    if (updateState(__COMPLETING,pending))
-                        onIncompleteFlushed();
-                    else
-                        fail(pending);
-                    return;
-                }
+                if (DEBUG)
+                    LOG.debug("flushed incomplete {}",BufferUtil.toDetailString(buffers));
+                if (buffers!=pending.getBuffers())
+                    pending=new PendingState(buffers, pending._callback);
+                if (updateState(__COMPLETING,pending))
+                    onIncompleteFlushed();
+                else
+                    fail(pending);
+                return;
             }
 
             // If updateState didn't succeed, we don't care as our buffers have been written
@@ -432,6 +393,49 @@ abstract public class WriteFlusher
         }
     }
 
+    /* ------------------------------------------------------------ */
+    /** Flush the buffers iteratively until no progress is made
+     * @param buffers The buffers to flush
+     * @return The unflushed buffers, or null if all flushed
+     * @throws IOException
+     */
+    protected ByteBuffer[] flush(ByteBuffer[] buffers) throws IOException
+    {
+        boolean progress=true;
+        while(progress && buffers!=null)
+        {
+            int before=buffers.length==0?0:buffers[0].remaining();
+            boolean flushed=_endPoint.flush(buffers);
+            int r=buffers.length==0?0:buffers[0].remaining();
+            
+            if (flushed)
+                return null;
+            
+            progress=before!=r;
+            
+            int not_empty=0;
+            while(r==0)
+            {
+                if (++not_empty==buffers.length)
+                {
+                    buffers=null;
+                    not_empty=0;
+                    break;
+                }
+                progress=true;
+                r=buffers[not_empty].remaining();
+            }
+
+            if (not_empty>0)
+                buffers=Arrays.copyOfRange(buffers,not_empty,buffers.length);
+        }        
+        
+        // If buffers is null, then flush has returned false but has consumed all the data!
+        // This is probably SSL being unable to flush the encrypted buffer, so return EMPTY_BUFFERS
+        // and that will keep this WriteFlusher pending.
+        return buffers==null?EMPTY_BUFFERS:buffers;
+    }
+    
     /* ------------------------------------------------------------ */
     /** Notify the flusher of a failure
      * @param cause The cause of the failure
index d08b47365841fb05354943497e4b53cf2f7008db..0ee72147081014cc0411ff0bdce680cbc0b16ed9 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 6316823e39c6492f0c5e74bd75ef41399ed9f02c..9db10927f093947aef74fccca2da5c75b55c324a 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index ce3be14a7b6b1812a89d2b105c92a1d0b2f31911..c1ec55fac9f7e5c8eb43f2de11f5ee56742328c2 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index ee9e449b15110bd5e613ca531cda3e2d2600bc8e..c68cc06c48f1c40ea0b7f634d2cf3cefaf18b3e1 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -305,7 +305,7 @@ public class SslConnection extends AbstractConnection
                 {
                     @Override
                     public void succeeded()
-                    {                        
+                    {
                     }
 
                     @Override
@@ -315,7 +315,7 @@ public class SslConnection extends AbstractConnection
                             getFillInterest().onFail(x);
                         getWriteFlusher().onFail(x);
                     }
-                    
+
                 },x);
             }
         };
@@ -352,7 +352,7 @@ public class SslConnection extends AbstractConnection
             // all data could be wrapped. So either we need to write some encrypted data,
             // OR if we are handshaking we need to read some encrypted data OR
             // if neither then we should just try the flush again.
-            boolean flush = false;
+            boolean try_again = false;
             synchronized (DecryptedEndPoint.this)
             {
                 if (DEBUG)
@@ -373,10 +373,17 @@ public class SslConnection extends AbstractConnection
                 }
                 else
                 {
-                    flush = true;
+                    // We can get here because the WriteFlusher might not see progress
+                    // when it has just flushed the encrypted data, but not consumed anymore
+                    // of the application buffers.  This is mostly avoided by another iteration
+                    // within DecryptedEndPoint flush(), but I cannot convince myself that
+                    // this is never ever the case.
+                    try_again = true;
                 }
             }
-            if (flush)
+
+
+            if (try_again)
             {
                 // If the output is closed,
                 if (isOutputShutdown())
@@ -388,7 +395,9 @@ public class SslConnection extends AbstractConnection
                 else
                 {
                     // try to flush what is pending
-                    getWriteFlusher().completeWrite();
+                    // because this is a special case (see above) we could probably
+                    // avoid the dispatch, but best to be sure
+                    getExecutor().execute(_runCompletWrite);
                 }
             }
         }
@@ -505,8 +514,15 @@ public class SslConnection extends AbstractConnection
                         // Let's unwrap even if we have no net data because in that
                         // case we want to fall through to the handshake handling
                         int pos = BufferUtil.flipToFill(app_in);
-                        SSLEngineResult unwrapResult = _sslEngine.unwrap(_encryptedInput, app_in);
-                        BufferUtil.flipToFlush(app_in, pos);
+                        SSLEngineResult unwrapResult;
+                        try
+                        {
+                            unwrapResult = _sslEngine.unwrap(_encryptedInput, app_in);
+                        }
+                        finally
+                        {
+                            BufferUtil.flipToFlush(app_in, pos);
+                        }
                         if (DEBUG)
                             LOG.debug("{} unwrap {}", SslConnection.this, unwrapResult);
 
@@ -514,7 +530,9 @@ public class SslConnection extends AbstractConnection
                         HandshakeStatus unwrapHandshakeStatus = unwrapResult.getHandshakeStatus();
                         Status unwrapResultStatus = unwrapResult.getStatus();
 
-                        _underFlown = unwrapResultStatus == Status.BUFFER_UNDERFLOW;
+                        // Extra check on unwrapResultStatus == OK with zero length buffer is due
+                        // to SSL client on android (see bug #454773)
+                        _underFlown = unwrapResultStatus == Status.BUFFER_UNDERFLOW || unwrapResultStatus == Status.OK && unwrapResult.bytesConsumed()==0 && unwrapResult.bytesProduced()==0;
 
                         if (_underFlown)
                         {
@@ -547,6 +565,12 @@ public class SslConnection extends AbstractConnection
                                         // or shutting down the output.
                                         return -1;
                                     }
+                                    case NEED_UNWRAP:
+                                    {
+                                        // We expected to read more, but we got closed.
+                                        // Return -1 to indicate to the application to drive the close.
+                                        return -1;
+                                    }
                                     default:
                                     {
                                         throw new IllegalStateException();
@@ -640,7 +664,7 @@ public class SslConnection extends AbstractConnection
             }
             catch (Exception e)
             {
-                getEndPoint().close();
+                close();
                 throw e;
             }
             finally
@@ -710,24 +734,26 @@ public class SslConnection extends AbstractConnection
                     // We call sslEngine.wrap to try to take bytes from appOut buffers and encrypt them into the _netOut buffer
                     BufferUtil.compact(_encryptedOutput);
                     int pos = BufferUtil.flipToFill(_encryptedOutput);
-                    SSLEngineResult wrapResult = _sslEngine.wrap(appOuts, _encryptedOutput);
+                    SSLEngineResult wrapResult;
+                    try
+                    {
+                        wrapResult=_sslEngine.wrap(appOuts, _encryptedOutput);
+                    }
+                    finally
+                    {
+                        BufferUtil.flipToFlush(_encryptedOutput, pos);
+                    }
+
                     if (DEBUG)
                         LOG.debug("{} wrap {}", SslConnection.this, wrapResult);
-                    BufferUtil.flipToFlush(_encryptedOutput, pos);
                     if (wrapResult.bytesConsumed()>0)
                         consumed+=wrapResult.bytesConsumed();
+                    Status wrapResultStatus = wrapResult.getStatus();
 
                     boolean allConsumed=true;
-                    // clear empty buffers to prevent position creeping up the buffer
                     for (ByteBuffer b : appOuts)
-                    {
-                        if (BufferUtil.isEmpty(b))
-                            BufferUtil.clear(b);
-                        else
+                        if (BufferUtil.hasContent(b))
                             allConsumed=false;
-                    }
-
-                    Status wrapResultStatus = wrapResult.getStatus();
 
                     // and deal with the results returned from the sslEngineWrap
                     switch (wrapResultStatus)
@@ -774,19 +800,26 @@ public class SslConnection extends AbstractConnection
                             {
                                 if (DEBUG)
                                     LOG.debug("{} renegotiation denied", SslConnection.this);
-                                shutdownOutput();
+                                getEndPoint().shutdownOutput();
                                 return allConsumed;
                             }
 
                             // if we have net bytes, let's try to flush them
                             if (BufferUtil.hasContent(_encryptedOutput))
-                                getEndPoint().flush(_encryptedOutput);
+                                if (!getEndPoint().flush(_encryptedOutput))
+                                    getEndPoint().flush(_encryptedOutput); // one retry
 
                             // But we also might have more to do for the handshaking state.
                             switch (handshakeStatus)
                             {
                                 case NOT_HANDSHAKING:
-                                    // Return with the number of bytes consumed (which may be 0)
+                                    // If we have not consumed all and had just finished handshaking, then we may
+                                    // have just flushed the last handshake in the encrypted buffers, so we should
+                                    // try again.
+                                    if (!allConsumed && wrapResult.getHandshakeStatus()==HandshakeStatus.FINISHED && BufferUtil.isEmpty(_encryptedOutput))
+                                        continue;
+
+                                    // Return true if we consumed all the bytes and encrypted are all flushed
                                     return allConsumed && BufferUtil.isEmpty(_encryptedOutput);
 
                                 case NEED_TASK:
@@ -818,11 +851,6 @@ public class SslConnection extends AbstractConnection
                     }
                 }
             }
-            catch (Exception e)
-            {
-                getEndPoint().close();
-                throw e;
-            }
             finally
             {
                 if (DEBUG)
index f8676c3c8d1356c6d364e33acbd292ff471912d2..2a23b1f045d5fa351782c5e7cca1ab96e31c187f 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index bc049fd57ed2198cb6699bac4776582a0e57b526..d3865832a4331dfd9ad9221cd9102e6d0f99f41e 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index e36a3b30bac9bec916b9cfa3cd64dcb90af851c4..83a965d652725bc08b823f858b2349b990c074ae 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 5cf1348afd7fb4193e01189df34b734feb911a96..bf0e027d573c11778cad486ea5cf17ccc1674bf4 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index dd99c5bfc013c4f6c0be05d13b3a801695bd36bb..9b25c06137b1a252cd67d096335083361aae045c 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 201618d89d1226941afe6d0ea51ffb32ba1ed6ae..47efd2561a73d7e5694eb16e0f8212bb80e41be0 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -46,6 +46,7 @@ import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.Response;
 import org.eclipse.jetty.server.UserIdentity;
 import org.eclipse.jetty.server.handler.ContextHandler;
+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.security.Constraint;
@@ -510,21 +511,6 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
                 mappings.put(ALL_METHODS,roleInfo);
             }
         }
-        else
-        {
-            //combine with any entry that covers all methods
-            if (httpMethod == null)
-            {
-                for (Map.Entry<String, RoleInfo> entry : mappings.entrySet())
-                {
-                    if (entry.getKey() != null)
-                    {
-                        RoleInfo specific = entry.getValue();
-                        specific.combine(roleInfo);
-                    }
-                }
-            }
-        }
     }
 
     /* ------------------------------------------------------------ */
@@ -627,7 +613,7 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
     @Override
     protected RoleInfo prepareConstraintInfo(String pathInContext, Request request)
     {
-        Map<String, RoleInfo> mappings = (Map<String, RoleInfo>)_constraintMap.match(pathInContext);
+        Map<String, RoleInfo> mappings = _constraintMap.match(pathInContext);
 
         if (mappings != null)
         {
@@ -700,11 +686,8 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
             {
                 String scheme = httpConfig.getSecureScheme();
                 int port = httpConfig.getSecurePort();
-                String url = ("https".equalsIgnoreCase(scheme) && port==443)
-                    ? "https://"+request.getServerName()+request.getRequestURI()
-                    : scheme + "://" + request.getServerName() + ":" + port + request.getRequestURI();                    
-                if (request.getQueryString() != null)
-                    url += "?" + request.getQueryString();
+                
+                String url = URIUtil.newURI(scheme, request.getServerName(), port,request.getRequestURI(),request.getQueryString());
                 response.setContentLength(0);
                 response.sendRedirect(url);
             }
index e2de9f7db220b286e715b5e4530833941e96535d..9e82addbead683eb5fe65d310ef0716d4253d0a3 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -23,6 +23,7 @@ import javax.servlet.http.HttpServletResponse;
 
 /**
  * @version $Rev: 4466 $ $Date: 2009-02-10 23:42:54 +0100 (Tue, 10 Feb 2009) $
+ * @deprecated
  */
 public interface CrossContextPsuedoSession<T>
 {
index 534a6d402d0f57d26d5f41c7ed3ba90d5e7db67c..e68dd71b533fd3c311fdd55ed6e81a35f2179541 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index c8ae0c29aa0bfd4120ccd1082b557d010d475cb6..e30011468e730fa736039a0027e0340579defd35 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 65e083d58012a131d2ab889a88034abb277f8d9b..1cdc8ccd9088b26f3ccf58c11970a28286820b31 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 8499a609d3ada1d166e8a628caade60a2d48246e..e205d774d82ac682f9b7823a15fd82cc18358fdf 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -29,6 +29,7 @@ import javax.servlet.http.HttpServletResponse;
 
 /**
  * @version $Rev: 4660 $ $Date: 2009-02-25 17:29:53 +0100 (Wed, 25 Feb 2009) $
+ * @deprecated
  */
 public class HashCrossContextPsuedoSession<T> implements CrossContextPsuedoSession<T>
 {
index 335aabd72b86776f822a9a7bc3bdb24d5dfdbdc0..beb051b621a006875ddf64ec8e5439ace776d294 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -52,7 +52,6 @@ public class HashLoginService extends MappedLoginService implements UserListener
     private PropertyUserStore _propertyUserStore;
     private String _config;
     private Resource _configResource;
-    private Scanner _scanner;
     private int _refreshInterval = 0;// default is not to reload
 
     /* ------------------------------------------------------------ */
@@ -159,9 +158,9 @@ public class HashLoginService extends MappedLoginService implements UserListener
     protected void doStop() throws Exception
     {
         super.doStop();
-        if (_scanner != null)
-            _scanner.stop();
-        _scanner = null;
+        if (_propertyUserStore != null)
+            _propertyUserStore.stop();
+        _propertyUserStore = null;
     }
     
     /* ------------------------------------------------------------ */
index 99094c17a9e6fd567f03da088ea5fed80a602d53..b37cc5ccc6742a9c87bec0914cab492cd3089028 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -22,7 +22,6 @@ import java.security.Principal;
 
 import javax.security.auth.Subject;
 
-import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.UserIdentity;
 
 /* ------------------------------------------------------------ */
index 30b0a8315bd3707e5a7381ad7a25ed78788392d4..98f7664a8891e6635754d93f297b453dea1fc4e4 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -38,8 +38,7 @@ import org.eclipse.jetty.util.security.Credential;
 
 /* ------------------------------------------------------------ */
 /**
- * HashMapped User Realm with JDBC as data source. JDBCLoginService extends
- * HashULoginService and adds a method to fetch user information from database.
+ * HashMapped User Realm with JDBC as data source. 
  * The login() method checks the inherited Map for the user. If the user is not
  * found, it will fetch details from the database and populate the inherited
  * Map. It then calls the superclass login() method to perform the actual
index 1e64141f7d606f7c28c3a15c7c7ff0cf5d4724bd..b1d9aa437c031fecbea61ac3524118f4460a7661 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 480131de0deba7e6ebd4519478556ada863c51b4..4cec9b375df8f2d55402d533e293fbbc18425899 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 7a8b5e753b59d1b3365e4c13a26f4546371a3436..cbd3bfdd74a7f48addc17544b89700623d2c0f65 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -38,6 +38,7 @@ import org.eclipse.jetty.security.MappedLoginService.RolePrincipal;
 import org.eclipse.jetty.server.UserIdentity;
 import org.eclipse.jetty.util.Scanner;
 import org.eclipse.jetty.util.Scanner.BulkListener;
+import org.eclipse.jetty.util.StringUtil;
 import org.eclipse.jetty.util.component.AbstractLifeCycle;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
@@ -153,7 +154,7 @@ public class PropertyUserStore extends AbstractLifeCycle
                 String[] roleArray = IdentityService.NO_ROLES;
                 if (roles != null && roles.length() > 0)
                 {
-                    roleArray = roles.split(",");
+                    roleArray = StringUtil.csvSplit(roles);
                 }
                 known.add(username);
                 Credential credential = Credential.getCredential(credentials);
index 55f1ae2efcebf5a0852d8986c31c4a2d64094b00..d52afd4e187ee45f87cf9c5cff51fb33b7ecfa56 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 13a7ea74cfaa000d0f4f20b34c0d61451a1252c2..493686089a3a38aeb48cb810ec8c63af94c04133 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 639c9726fe47926f4f3d355e4f3a8517cd58c052..afef9fee080ff3b42c5f36be832792af215ad639 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index a6e108e9a704009d727ac11db35a3870da2b3f59..bfcb8fa69557dfa8da20fd54cd239c4335f28501 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -43,7 +43,6 @@ import org.eclipse.jetty.server.handler.ContextHandler;
 import org.eclipse.jetty.server.handler.ContextHandler.Context;
 import org.eclipse.jetty.server.handler.HandlerWrapper;
 import org.eclipse.jetty.server.session.AbstractSession;
-import org.eclipse.jetty.util.component.LifeCycle;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 
index 85f532fae8ad10be3603937f05c53b4dd5651a9d..1cd511981b608346685338b130e2e12f783e1f3a 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index ba160f06cef4832d3b62509be88d7cb74d4941ab..3155b43ca409a42e6117e45dd4d3a47294705686 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 13cf0bb142e6ba805819208578b5f109d8e46d7e..4951ecfd0171f6e4945ddfe521940ac6e1af0ba7 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 3fe9445ffeabba399af2522162969ae94157ed60..ff297b51dd4d7e74c93016bdc90bcb7dec08d6d7 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 9174a06c5ad8db23b200d2b14f0c875c5cdad1e8..2077761658e8755d5aba86dd162c99e306070a11 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index c288e1dcab6a0a46a2b73b45f1568af0fd603396..e8bd171845d997224e1642b8fb80654bd2adefd9 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index caa784f0133157de3fdfcecc0aced2860c94c6c2..c3b3e1134cf4533eb1d40a971b681e089a8161c1 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 9694cf159230b33d88f7204b40f237f0f375c878..bfdeb73b4d0bb289065a49e30888e328905a5a7d 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index df0f7d92f3afa6a35e663a138e598c0e68520123..32f04610a9dc454d0558a95eff7527ec8e86be32 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -331,28 +331,28 @@ public class DeferredAuthentication implements Authentication.Deferred
         }
 
         @Override
-       public Collection<String> getHeaderNames()
-       {
-           return Collections.emptyList();
-       }
+        public Collection<String> getHeaderNames()
+        {
+            return Collections.emptyList();
+        }
 
-       @Override
-       public String getHeader(String arg0)
-       {
-           return null;
-       }
+        @Override
+        public String getHeader(String arg0)
+        {
+            return null;
+        }
 
-       @Override
-       public Collection<String> getHeaders(String arg0)
-       {
+        @Override
+        public Collection<String> getHeaders(String arg0)
+        {
             return Collections.emptyList();
-       }
+        }
 
-       @Override
-       public int getStatus()
-       {
-           return 0;
-       }
+        @Override
+        public int getStatus()
+        {
+            return 0;
+        }
 
 
     };
index 13537e6cb75edfb1e2e444ac286c94a4b5d04892..99a46a37ca63baecb6c169f1e83883ee84ad6587 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -34,7 +34,6 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import org.eclipse.jetty.http.HttpHeader;
-import org.eclipse.jetty.security.SecurityHandler;
 import org.eclipse.jetty.security.ServerAuthException;
 import org.eclipse.jetty.security.UserAuthentication;
 import org.eclipse.jetty.server.Authentication;
index dcfea4168c6a4bf1ac7f3da593229f02a05ada70..6a5b2a617ae4eb9406926a3f7ed42f95d7f3d373 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 9a1940d8f7831091bd1e72e89c6862b0b46d4d11..4f5a9ec94a4f6d20b5815e819c16e134f20701b2 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index e123b221997d2cd7c9259eeef7dba26633052c5f..92eeea33184143501e55cad6ec7dcc3c66c05fcc 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 5939caf78cc4520b6cc6a42fcd5caf5fed5d3206..c9223ab05661b617018c6ea1f722f56a9eeaa337 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index e3be58464c19385da3a44bcb224ec31184cf71e3..6f589472e43ac9571805345c2bc90d2212b423ee 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 8469c0a800d2bdb9ba8aba20a244b25664299ad3..182635a2544962f6be69687deb050119732cab3c 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -50,7 +50,7 @@ public class SpnegoAuthenticator extends LoginAuthenticator
      */
     public SpnegoAuthenticator( String authMethod )
     {
-       _authMethod = authMethod;
+        _authMethod = authMethod;
     }
 
     @Override
@@ -77,10 +77,10 @@ public class SpnegoAuthenticator extends LoginAuthenticator
         {
             try
             {
-                if (DeferredAuthentication.isDeferred(res))
-                {
+                 if (DeferredAuthentication.isDeferred(res))
+                 {
                      return Authentication.UNAUTHENTICATED;
-                }
+                 }
 
                 LOG.debug("SpengoAuthenticator: sending challenge");
                 res.setHeader(HttpHeader.WWW_AUTHENTICATE.asString(), HttpHeader.NEGOTIATE.asString());
index 0e0c617bb1821886038abc0d4a9c9a235607c14b..9f28e68657b53c79c8009c219482394ff110bf95 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index edb5ea4ee7020c180e83481796250c774fc0e477..bda98bc200280921596783edb24faaac6c2f17ff 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 96fb3a2d81e1006ddc4984d10d6b880d17736778..bbbb16583b7733107635896f5920a2e8a81eed3b 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 7d3402fbfa77b37fd014a44a92699ff06591333f..c758addddb3f408c8f42f553fcec6fb495283cde 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -19,8 +19,6 @@
 package org.eclipse.jetty.server;
 
 import java.io.IOException;
-import java.net.Socket;
-import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -37,9 +35,7 @@ import java.util.concurrent.TimeUnit;
 
 import org.eclipse.jetty.io.ArrayByteBufferPool;
 import org.eclipse.jetty.io.ByteBufferPool;
-import org.eclipse.jetty.io.Connection;
 import org.eclipse.jetty.io.EndPoint;
-import org.eclipse.jetty.io.ssl.SslConnection;
 import org.eclipse.jetty.util.FutureCallback;
 import org.eclipse.jetty.util.annotation.ManagedAttribute;
 import org.eclipse.jetty.util.annotation.ManagedObject;
@@ -47,7 +43,6 @@ import org.eclipse.jetty.util.component.ContainerLifeCycle;
 import org.eclipse.jetty.util.component.Dumpable;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
 import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
 import org.eclipse.jetty.util.thread.Scheduler;
 
@@ -145,13 +140,14 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co
     private final Scheduler _scheduler;
     private final ByteBufferPool _byteBufferPool;
     private final Thread[] _acceptors;
-    private final Set<EndPoint> _endpoints = Collections.newSetFromMap(new ConcurrentHashMap());
+    private final Set<EndPoint> _endpoints = Collections.newSetFromMap(new ConcurrentHashMap<EndPoint, Boolean>());
     private final Set<EndPoint> _immutableEndPoints = Collections.unmodifiableSet(_endpoints);
     private volatile CountDownLatch _stopping;
     private long _idleTimeout = 30000;
     private String _defaultProtocol;
     private ConnectionFactory _defaultConnectionFactory;
     private String _name;
+    private int _acceptorPriorityDelta;
 
 
     /**
@@ -159,7 +155,7 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co
      * @param executor An executor for this connector or null to use the servers executor
      * @param scheduler A scheduler for this connector or null to either a {@link Scheduler} set as a server bean or if none set, then a new {@link ScheduledExecutorScheduler} instance.
      * @param pool A buffer pool for this connector or null to either a {@link ByteBufferPool} set as a server bean or none set, the new  {@link ArrayByteBufferPool} instance.
-     * @param acceptors the number of acceptor threads to use, or 0 for a default value.
+     * @param acceptors the number of acceptor threads to use, or -1 for a default value. If 0, then no acceptor threads will be launched and some other mechanism will need to be used to accept new connections.
      * @param factories The Connection Factories to use.
      */
     public AbstractConnector(
@@ -191,9 +187,9 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co
 
         int cores = Runtime.getRuntime().availableProcessors();
         if (acceptors < 0)
-            acceptors = 1 + cores / 16;
-        if (acceptors > 2 * cores)
-            LOG.warn("Acceptors should be <= 2*availableProcessors: " + this);
+            acceptors=Math.max(1, Math.min(4,cores/8));        
+        if (acceptors > cores)
+            LOG.warn("Acceptors should be <= availableProcessors: " + this);
         _acceptors = new Thread[acceptors];
     }
 
@@ -261,7 +257,11 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co
 
         _stopping=new CountDownLatch(_acceptors.length);
         for (int i = 0; i < _acceptors.length; i++)
-            getExecutor().execute(new Acceptor(i));
+        {
+            Acceptor a = new Acceptor(i);
+            addBean(a);
+            getExecutor().execute(a);
+        }
 
         LOG.info("Started {}", this);
     }
@@ -299,6 +299,9 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co
         _stopping=null;
 
         super.doStop();
+        
+        for (Acceptor a : getBeans(Acceptor.class))
+            removeBean(a);
 
         LOG.info("Stopped {}", this);
     }
@@ -397,6 +400,30 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co
         }
     }
 
+    @ManagedAttribute("The priority delta to apply to acceptor threads")
+    public int getAcceptorPriorityDelta()
+    {
+        return _acceptorPriorityDelta;
+    }
+
+    /* ------------------------------------------------------------ */
+    /** Set the acceptor thread priority delta.
+     * <p>This allows the acceptor thread to run at a different priority.
+     * Typically this would be used to lower the priority to give preference 
+     * to handling previously accepted connections rather than accepting 
+     * new connections</p>
+     * @param acceptorPriorityDelta
+     */
+    public void setAcceptorPriorityDelta(int acceptorPriorityDelta)
+    {
+        int old=_acceptorPriorityDelta;
+        _acceptorPriorityDelta = acceptorPriorityDelta;
+        if (old!=acceptorPriorityDelta && isStarted())
+        {
+            for (Thread thread : _acceptors)
+                thread.setPriority(Math.max(Thread.MIN_PRIORITY,Math.min(Thread.MAX_PRIORITY,thread.getPriority()-old+acceptorPriorityDelta)));
+        }
+    }
 
     @Override
     @ManagedAttribute("Protocols supported by this connector")
@@ -440,6 +467,7 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co
     private class Acceptor implements Runnable
     {
         private final int _acceptor;
+        private String _name;
 
         private Acceptor(int id)
         {
@@ -449,13 +477,18 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co
         @Override
         public void run()
         {
-            Thread current = Thread.currentThread();
-            String name = current.getName();
-            current.setName(name + "-acceptor-" + _acceptor + "-" + AbstractConnector.this);
+            final Thread thread = Thread.currentThread();
+            String name=thread.getName();
+            _name=String.format("%s-acceptor-%d@%x-%s",name,_acceptor,hashCode(),AbstractConnector.this.toString());
+            thread.setName(_name);
+            
+            int priority=thread.getPriority();
+            if (_acceptorPriorityDelta!=0)
+                thread.setPriority(Math.max(Thread.MIN_PRIORITY,Math.min(Thread.MAX_PRIORITY,priority+_acceptorPriorityDelta)));
 
             synchronized (AbstractConnector.this)
             {
-                _acceptors[_acceptor] = current;
+                _acceptors[_acceptor] = thread;
             }
 
             try
@@ -477,7 +510,9 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co
             }
             finally
             {
-                current.setName(name);
+                thread.setName(name);
+                if (_acceptorPriorityDelta!=0)
+                    thread.setPriority(priority);
 
                 synchronized (AbstractConnector.this)
                 {
@@ -488,6 +523,16 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co
                     stopping.countDown();
             }
         }
+        
+        @Override
+        public String toString()
+        {
+            String name=_name;
+            if (name==null)
+                return String.format("acceptor-%d@%x", _acceptor, hashCode());
+            return name;
+        }
+        
     }
 
 
index dcaecbe50fbb3ca27035d37e245c808bb49bd360..7861d1a46517412f0b3567f6f275f54c67d1be2b 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -25,7 +25,6 @@ import javax.servlet.http.Cookie;
 
 import org.eclipse.jetty.http.HttpHeader;
 import org.eclipse.jetty.http.PathMap;
-import org.eclipse.jetty.server.handler.StatisticsHandler;
 import org.eclipse.jetty.util.DateCache;
 import org.eclipse.jetty.util.annotation.ManagedAttribute;
 import org.eclipse.jetty.util.component.AbstractLifeCycle;
@@ -121,7 +120,7 @@ public abstract class AbstractNCSARequestLog extends AbstractLifeCycle implement
             if (authentication instanceof Authentication.User)
                 buf.append(((Authentication.User)authentication).getUserIdentity().getUserPrincipal().getName());
             else
-                buf.append(" - ");
+                buf.append("-");
 
             buf.append(" [");
             if (_logDateCache != null)
index 08b65bc4514fff12eb1390a036d0d2d4a900bd6f..c5b8401819c765bf4a13776893aaf3a41bf9bdf9 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index cc0eec89754a81fd9d5f23474829142e95dd28ba..4c8d3fa2630ae2e95306bfac9b709895113dbd9e 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 6503424dd105af97d3202be97206cd152a57534a..40e4a0965406ecf089aa42eeb22f77ea54f632dd 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 33ba21d7776b4482333e0f743483f05cf673c95a..8f639b7fb34521ffd798a1708fe54895116cd8fd 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index ccdf4c0f13141dd44ca1639ba316baf9c200af34..7bacc3e191c1b9066438504c176fcc932c1d8ad0 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index cd2d12e823ab00d01956b0729121d8f185f26ccd..60e62a336d096f705165448be325812349b2cce6 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 466775e4ca4d16c5fa40cc245b482501e351a980..56c3b6d7c78e638160f96e7e506a581d20ee8c0d 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index e23739d899368c4ad10b2120431f54ed061f2d7b..a9599c4b689c256e52a50f180542c646ba3518c5 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index ce4544c90057a087ae01535bd01b5b9ef3a099af..be958adabafc01715acedff23ad4b5447b90d03a 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -24,7 +24,6 @@ import java.util.concurrent.Executor;
 
 import org.eclipse.jetty.io.ByteBufferPool;
 import org.eclipse.jetty.io.EndPoint;
-import org.eclipse.jetty.server.handler.ContextHandler;
 import org.eclipse.jetty.util.annotation.ManagedAttribute;
 import org.eclipse.jetty.util.annotation.ManagedObject;
 import org.eclipse.jetty.util.component.Graceful;
index cae5e6eb350ade3b95dbbeb4308df34dcd1d0fe9..d5d7fcd044c705df0a888b31b527838f4434e97b 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 703f804907355a37f202ffd13d1f9d676978510b..8ccfcbe7f48d2ad22e899ba13077c0c8f161381e 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 25672897948dca2a9286449394c2608d9130a46f..a34a83debf3acf124915e99dba60bd0a7b33641b 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 88301d4b09e5922f22622c2c1c99718166be81e4..e49cb009f3331a07d04ecf59b527fe4d954db58f 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 891e8ee1cf27d5ccdb3ff60f4b16e6eab6f00d59..1e9d17404e16595dc012ffff400c1d963068b3b9 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -20,8 +20,6 @@ package org.eclipse.jetty.server;
 
 import java.net.InetSocketAddress;
 
-import javax.servlet.ServletRequest;
-
 import org.eclipse.jetty.http.HttpFields;
 import org.eclipse.jetty.http.HttpHeader;
 import org.eclipse.jetty.http.HttpScheme;
index cfe7b9a200b33c6e590f5fd5d8a726c983b5c8fb..b32cc821712077bc735be5b23b47072fe92d27a2 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -24,8 +24,6 @@ import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.eclipse.jetty.server.handler.HandlerCollection;
-import org.eclipse.jetty.server.handler.HandlerWrapper;
 import org.eclipse.jetty.util.annotation.ManagedAttribute;
 import org.eclipse.jetty.util.annotation.ManagedObject;
 import org.eclipse.jetty.util.annotation.ManagedOperation;
index 51fd4791776a6c784d355e80faf555b0bec886d8..5f675274f29076fca44c8269f975c76959a427eb 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
diff --git a/lib/jetty/org/eclipse/jetty/server/HomeBaseWarning.java b/lib/jetty/org/eclipse/jetty/server/HomeBaseWarning.java
new file mode 100644 (file)
index 0000000..d3af3cb
--- /dev/null
@@ -0,0 +1,75 @@
+//
+//  ========================================================================
+//  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 java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.eclipse.jetty.util.StringUtil;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+/**
+ * Display an optional Warning Message if the {jetty.home} and {jetty.base} are the same directory.
+ * <p>
+ * This is to warn about not recommended approach to setting up the Jetty Distribution.
+ */
+public class HomeBaseWarning
+{
+    private static final Logger LOG = Log.getLogger(HomeBaseWarning.class);
+
+    public HomeBaseWarning()
+    {
+        boolean showWarn = false;
+        
+        String home = System.getProperty("jetty.home");
+        String base = System.getProperty("jetty.base");
+
+        if (StringUtil.isBlank(base))
+        {
+            // no base defined? then we are likely running
+            // via direct command line.
+            return;
+        }
+
+        Path homePath = new File(home).toPath();
+        Path basePath = new File(base).toPath();
+
+        try
+        {
+            showWarn = Files.isSameFile(homePath,basePath);
+        }
+        catch (IOException e)
+        {
+            LOG.ignore(e);
+            // Can't definitively determine this state
+            return;
+        }
+
+        if (showWarn)
+        {
+            StringBuilder warn = new StringBuilder();
+            warn.append("This instance of Jetty is not running from a separate {jetty.base} directory");
+            warn.append(", this is not recommended.  See documentation at http://www.eclipse.org/jetty/documentation/current/startup.html");
+            LOG.warn("{}",warn.toString());
+        }
+    }
+}
index b39b25dcf404c1ab0ee6f476f14b481659048594..464f1d26a149a6d721091d10731973ce42f80944 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -20,8 +20,6 @@ package org.eclipse.jetty.server;
 
 import java.util.Objects;
 
-import javax.servlet.http.HttpServletRequest;
-
 /**
  * Customizes requests that lack the {@code Host} header (for example, HTTP 1.0 requests).
  * <p />
index 07b09ab7241818080ee352c80f89c23120d03b18..8093f46d7edf2208ac793e8e094029c683516def 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -23,6 +23,7 @@ import java.net.InetSocketAddress;
 import java.nio.ByteBuffer;
 import java.nio.channels.ClosedChannelException;
 import java.nio.charset.StandardCharsets;
+import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -86,10 +87,7 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable, H
     protected static HttpChannel<?> setCurrentHttpChannel(HttpChannel<?> channel)
     {
         HttpChannel<?> last=__currentChannel.get();
-        if (channel==null)
-            __currentChannel.remove();
-        else 
-            __currentChannel.set(channel);
+        __currentChannel.set(channel);
         return last;
     }
 
@@ -120,6 +118,9 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable, H
         input.init(_state);
         _request = new Request(this, input);
         _response = new Response(this, new HttpOutput(this));
+
+        if (LOG.isDebugEnabled())
+            LOG.debug("new {} -> {},{},{}",this,_endPoint,_endPoint.getConnection(),_state);
     }
 
     public HttpChannelState getState()
@@ -148,7 +149,27 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable, H
     {
         return _transport;
     }
-    
+
+    /**
+     * Get the idle timeout.
+     * <p>This is implemented as a call to {@link EndPoint#getIdleTimeout()}, but may be
+     * overridden by channels that have timeouts different from their connections.
+     */
+    public long getIdleTimeout()
+    {
+        return _endPoint.getIdleTimeout();
+    }
+
+    /**
+     * Set the idle timeout.
+     * <p>This is implemented as a call to {@link EndPoint#setIdleTimeout(long)}, but may be
+     * overridden by channels that have timeouts different from their connections.
+     */
+    public void setIdleTimeout(long timeoutMs)
+    {
+        _endPoint.setIdleTimeout(timeoutMs);
+    }
+
     public ByteBufferPool getByteBufferPool()
     {
         return _connector.getByteBufferPool();
@@ -247,7 +268,8 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable, H
      */
     public boolean handle()
     {
-        LOG.debug("{} handle enter", this);
+        if (LOG.isDebugEnabled())
+            LOG.debug("{} handle enter", this);
 
         final HttpChannel<?>last = setCurrentHttpChannel(this);
 
@@ -270,7 +292,8 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable, H
                 boolean error=false;
                 try
                 {
-                    LOG.debug("{} action {}",this,action);
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("{} action {}",this,action);
 
                     switch(action)
                     {
@@ -279,8 +302,12 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable, H
                             _response.getHttpOutput().reopen();
                             _request.setDispatcherType(DispatcherType.REQUEST);
 
-                            for (HttpConfiguration.Customizer customizer : _configuration.getCustomizers())
-                                customizer.customize(getConnector(),_configuration,_request);
+                            List<HttpConfiguration.Customizer> customizers = _configuration.getCustomizers();
+                            if (!customizers.isEmpty())
+                            {
+                                for (HttpConfiguration.Customizer customizer : customizers)
+                                    customizer.customize(getConnector(), _configuration, _request);
+                            }
                             getServer().handle(this);
                             break;
 
@@ -309,8 +336,8 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable, H
 
                             _response.setStatusWithReason(500,reason);
 
-                            
-                            ErrorHandler eh = ErrorHandler.getErrorHandler(getServer(),_state.getContextHandler());                                
+
+                            ErrorHandler eh = ErrorHandler.getErrorHandler(getServer(),_state.getContextHandler());
                             if (eh instanceof ErrorHandler.ErrorPageMapper)
                             {
                                 String error_page=((ErrorHandler.ErrorPageMapper)eh).getErrorPage((HttpServletRequest)_state.getAsyncContextEvent().getSuppliedRequest());
@@ -340,7 +367,7 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable, H
                             else
                                 _response.getHttpOutput().run();
                             break;
-                        }   
+                        }
 
                         default:
                             break loop;
@@ -354,7 +381,10 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable, H
                     else
                     {
                         error=true;
-                        throw e;
+                        LOG.warn(String.valueOf(_uri), e);
+                        _state.error(e);
+                        _request.setHandled(true);
+                        handleException(e);
                     }
                 }
                 catch (Exception e)
@@ -376,6 +406,36 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable, H
                 }
             }
 
+            if (action==Action.COMPLETE)
+            {
+                try
+                {
+                    _state.completed();
+
+                    if (!_response.isCommitted() && !_request.isHandled())
+                    {
+                        _response.sendError(404);
+                    }
+                    else
+                    {
+                        // Complete generating the response
+                        _response.closeOutput();
+                    }
+                }
+                catch(EofException|ClosedChannelException e)
+                {
+                    LOG.debug(e);
+                }
+                catch(Exception e)
+                {
+                    LOG.warn("complete failed",e);
+                }
+                finally
+                {
+                    _request.setHandled(true);
+                    _transport.completed();
+                }
+            }
         }
         finally
         {
@@ -384,34 +444,8 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable, H
                 Thread.currentThread().setName(threadName);
         }
 
-        if (action==Action.COMPLETE)
-        {
-            try
-            {
-                _state.completed();
-
-                if (!_response.isCommitted() && !_request.isHandled())
-                    _response.sendError(404);
-                else
-                    // Complete generating the response
-                    _response.closeOutput();
-            }
-            catch(EofException|ClosedChannelException e)
-            {
-                LOG.debug(e);
-            }
-            catch(Exception e)
-            {
-                LOG.warn("complete failed",e);
-            }
-            finally
-            {
-                _request.setHandled(true);
-                _transport.completed();
-            }
-        }
-
-        LOG.debug("{} handle exit, result {}", this, action);
+        if (LOG.isDebugEnabled())
+            LOG.debug("{} handle exit, result {}", this, action);
 
         return action!=Action.WAIT;
     }
@@ -443,7 +477,7 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable, H
             }
             else if (isCommitted())
             {
-                _transport.abort();
+                abort();
                 if (!(x instanceof EofException))
                     LOG.warn("Could not send response error 500: "+x);
             }
@@ -473,13 +507,13 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable, H
     @Override
     public String toString()
     {
-        return String.format("%s@%x{r=%s,a=%s,uri=%s}",
+        return String.format("%s@%x{r=%s,c=%b,a=%s,uri=%s}",
                 getClass().getSimpleName(),
                 hashCode(),
                 _requests,
+                _committed.get(),
                 _state.getState(),
-                _state.getState()==HttpChannelState.State.IDLE?"-":_request.getRequestURI()
-            );
+                _uri);
     }
 
     @Override
@@ -490,7 +524,7 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable, H
         _request.setServerPort(dPort);
         _request.setRemoteAddr(InetSocketAddress.createUnresolved(sAddr,sPort));
     }
-    
+
     @Override
     public boolean startRequest(HttpMethod httpMethod, String method, ByteBuffer uri, HttpVersion version)
     {
@@ -518,7 +552,7 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable, H
             LOG.ignore(e);
             path = _uri.getDecodedPath(StandardCharsets.ISO_8859_1);
         }
-        
+
         String info = URIUtil.canonicalPath(path);
 
         if (info == null)
@@ -568,7 +602,7 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable, H
 
                             default:
                                 String[] values = value.split(",");
-                                for (int i = 0; values != null && i < values.length; i++)
+                                for (int i = 0; i < values.length; i++)
                                 {
                                     expect = HttpHeaderValue.CACHE.get(values[i].trim());
                                     if (expect == null)
@@ -622,19 +656,20 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable, H
     public boolean headerComplete()
     {
         _requests.incrementAndGet();
+        HttpFields fields = _response.getHttpFields();
         switch (_version)
         {
             case HTTP_0_9:
                 break;
 
             case HTTP_1_0:
-                if (_configuration.getSendDateHeader())
-                    _response.getHttpFields().put(_connector.getServer().getDateField());
+                if (_configuration.getSendDateHeader() && !fields.contains(HttpHeader.DATE))
+                    _response.getHttpFields().add(_connector.getServer().getDateField());
                 break;
 
             case HTTP_1_1:
-                if (_configuration.getSendDateHeader())
-                    _response.getHttpFields().put(_connector.getServer().getDateField());
+                if (_configuration.getSendDateHeader() && !fields.contains(HttpHeader.DATE))
+                    _response.getHttpFields().add(_connector.getServer().getDateField());
 
                 if (_expect)
                 {
@@ -666,7 +701,8 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable, H
     @Override
     public boolean messageComplete()
     {
-        LOG.debug("{} messageComplete", this);
+        if (LOG.isDebugEnabled())
+            LOG.debug("{} messageComplete", this);
         _request.getHttpInput().messageComplete();
         return true;
     }
@@ -705,14 +741,13 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable, H
         {
             if (_state.unhandle()==Action.COMPLETE)
                 _state.completed();
-            else 
+            else
                 throw new IllegalStateException();
         }
     }
 
     protected boolean sendResponse(ResponseInfo info, ByteBuffer content, boolean complete, final Callback callback)
     {
-        // TODO check that complete only set true once by changing _committed to AtomicRef<Enum>
         boolean committing = _committed.compareAndSet(false, true);
         if (committing)
         {
@@ -720,7 +755,7 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable, H
             if (info==null)
                 info = _response.newResponseInfo();
 
-            // wrap callback to process 100 or 500 responses
+            // wrap callback to process 100 responses
             final int status=info.getStatus();
             final Callback committed = (status<200&&status>=100)?new Commit100Callback(callback):new CommitCallback(callback);
 
@@ -787,10 +822,11 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable, H
 
     /**
      * If a write or similar to this channel fails this method should be called. The standard implementation
-     * of {@link #failed()} is a noop. But the different implementations of HttpChannel might want to take actions.
+     * is to call {@link HttpTransport#abort()}
      */
-    public void failed()
+    public void abort()
     {
+        _transport.abort();
     }
 
     private class CommitCallback implements Callback
@@ -851,8 +887,10 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable, H
         @Override
         public void succeeded()
         {
-             _committed.set(false);
-             super.succeeded();
+            if (_committed.compareAndSet(true, false))
+                super.succeeded();
+            else
+                super.failed(new IllegalStateException());
         }
 
     }
index 7ff4d5a2a47a4ed49c0f4805b4552b52c0da0c0e..c0cfa2f06b477e1b1334d0c07732b64b0ec45405 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -40,7 +40,7 @@ public class HttpChannelState
 {
     private static final Logger LOG = Log.getLogger(HttpChannelState.class);
 
-    private final static long DEFAULT_TIMEOUT=30000L;
+    private final static long DEFAULT_TIMEOUT=Long.getLong("org.eclipse.jetty.server.HttpChannelState.DEFAULT_TIMEOUT",30000L);
 
     /** The dispatched state of the HttpChannel, used to control the overall livecycle
      */
@@ -52,7 +52,8 @@ public class HttpChannelState
         ASYNC_WOKEN,      // A thread has been dispatch to handle from ASYNCWAIT
         ASYNC_IO,         // Has been dispatched for async IO
         COMPLETING,       // Request is completable
-        COMPLETED         // Request is complete
+        COMPLETED,        // Request is complete
+        UPGRADED          // Request upgraded the connection
     }
 
     /**
@@ -525,6 +526,8 @@ public class HttpChannelState
                 case DISPATCHED:
                 case ASYNC_IO:
                     throw new IllegalStateException(getStatusString());
+                case UPGRADED:
+                    return;
                 default:
                     break;
             }
@@ -539,6 +542,31 @@ public class HttpChannelState
             _event=null;
         }
     }
+    
+    public void upgrade()
+    {
+        synchronized (this)
+        {
+            switch(_state)
+            {
+                case IDLE:
+                case COMPLETED:
+                    break;
+                default:
+                    throw new IllegalStateException(getStatusString());
+            }
+            _asyncListeners=null;
+            _state=State.UPGRADED;
+            _async=null;
+            _initial=true;
+            _asyncRead=false;
+            _asyncWrite=false;
+            _timeoutMs=DEFAULT_TIMEOUT;
+            cancelTimeout();
+            _event=null;
+        }
+    }
+
 
     protected void scheduleDispatch()
     {
index 352af25c750f35efadd4c9f82c683380816d07c6..f1cce65cd8110a3b16fff110541ea2004b844bd6 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -45,15 +45,33 @@ public class HttpConfiguration
 
     private List<Customizer> _customizers=new CopyOnWriteArrayList<>();
     private int _outputBufferSize=32*1024;
+    private int _outputAggregationSize=_outputBufferSize/4;
     private int _requestHeaderSize=8*1024;
     private int _responseHeaderSize=8*1024;
     private int _headerCacheSize=512;
     private int _securePort;
     private String _secureScheme = HttpScheme.HTTPS.asString();
-    private boolean _sendServerVersion = true; //send Server: header
-    private boolean _sendXPoweredBy = false; //send X-Powered-By: header
-    private boolean _sendDateHeader = true; //send Date: header
+    private boolean _sendServerVersion = true;
+    private boolean _sendXPoweredBy = false;
+    private boolean _sendDateHeader = true;
+    private boolean _delayDispatchUntilContent = false;
 
+    /* ------------------------------------------------------------ */
+    /** 
+     * <p>An interface that allows a request object to be customized 
+     * for a particular HTTP connector configuration.  Unlike Filters, customizer are
+     * applied before the request is submitted for processing and can be specific to the 
+     * connector on which the request was received.
+     * 
+     * <p>Typically Customizers perform tasks such as: <ul>
+     *  <li>process header fields that may be injected by a proxy or load balancer.
+     *  <li>setup attributes that may come from the connection/connector such as SSL Session IDs
+     *  <li>Allow a request to be marked as secure or authenticated if those have been offloaded
+     *  and communicated by header, cookie or other out-of-band mechanism
+     *  <li>Set request attributes/fields that are determined by the connector on which the
+     *  request was received
+     *  </ul>
+     */
     public interface Customizer
     {
         public void customize(Connector connector, HttpConfiguration channelConfig, Request request);
@@ -76,6 +94,7 @@ public class HttpConfiguration
     {
         _customizers.addAll(config._customizers);
         _outputBufferSize=config._outputBufferSize;
+        _outputAggregationSize=config._outputAggregationSize;
         _requestHeaderSize=config._requestHeaderSize;
         _responseHeaderSize=config._responseHeaderSize;
         _securePort=config._securePort;
@@ -103,7 +122,8 @@ public class HttpConfiguration
     {
         return _customizers;
     }
-    
+
+    /* ------------------------------------------------------------ */
     public <T> T getCustomizer(Class<T> type)
     {
         for (Customizer c : _customizers)
@@ -112,82 +132,117 @@ public class HttpConfiguration
         return null;
     }
 
+    /* ------------------------------------------------------------ */
     @ManagedAttribute("The size in bytes of the output buffer used to aggregate HTTP output")
     public int getOutputBufferSize()
     {
         return _outputBufferSize;
     }
-    
+
+    /* ------------------------------------------------------------ */
+    @ManagedAttribute("The maximum size in bytes for HTTP output to be aggregated")
+    public int getOutputAggregationSize()
+    {
+        return _outputAggregationSize;
+    }
+
+    /* ------------------------------------------------------------ */
     @ManagedAttribute("The maximum allowed size in bytes for a HTTP request header")
     public int getRequestHeaderSize()
     {
         return _requestHeaderSize;
     }
-    
+
+    /* ------------------------------------------------------------ */
     @ManagedAttribute("The maximum allowed size in bytes for a HTTP response header")
     public int getResponseHeaderSize()
     {
         return _responseHeaderSize;
     }
 
+    /* ------------------------------------------------------------ */
     @ManagedAttribute("The maximum allowed size in bytes for a HTTP header field cache")
     public int getHeaderCacheSize()
     {
         return _headerCacheSize;
     }
 
+    /* ------------------------------------------------------------ */
     @ManagedAttribute("The port to which Integral or Confidential security constraints are redirected")
     public int getSecurePort()
     {
         return _securePort;
     }
-    
+
+    /* ------------------------------------------------------------ */
     @ManagedAttribute("The scheme with which Integral or Confidential security constraints are redirected")
     public String getSecureScheme()
     {
         return _secureScheme;
     }
 
+    /* ------------------------------------------------------------ */
     public void setSendServerVersion (boolean sendServerVersion)
     {
         _sendServerVersion = sendServerVersion;
     }
 
+    /* ------------------------------------------------------------ */
     @ManagedAttribute("if true, send the Server header in responses")
     public boolean getSendServerVersion()
     {
         return _sendServerVersion;
     }
-    
+
+    /* ------------------------------------------------------------ */
     public void setSendXPoweredBy (boolean sendXPoweredBy)
     {
         _sendXPoweredBy=sendXPoweredBy;
     }
 
+    /* ------------------------------------------------------------ */
     @ManagedAttribute("if true, send the X-Powered-By header in responses")
     public boolean getSendXPoweredBy()
     {
         return _sendXPoweredBy;
     }
 
+    /* ------------------------------------------------------------ */
     public void setSendDateHeader(boolean sendDateHeader)
     {
         _sendDateHeader = sendDateHeader;
     }
 
+    /* ------------------------------------------------------------ */
     @ManagedAttribute("if true, include the date in HTTP headers")
     public boolean getSendDateHeader()
     {
         return _sendDateHeader;
     }
-    
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @param delay if true, delay the application dispatch until content is available
+     */
+    public void setDelayDispatchUntilContent(boolean delay)
+    {
+        _delayDispatchUntilContent = delay;
+    }
+
+    /* ------------------------------------------------------------ */
+    @ManagedAttribute("if true, delay the application dispatch until content is available")
+    public boolean isDelayDispatchUntilContent()
+    {
+        return _delayDispatchUntilContent;
+    }
+
     /* ------------------------------------------------------------ */
     /**
      * <p>Set the {@link Customizer}s that are invoked for every 
      * request received.</p>
-     * <p>Customisers are often used to interpret optional headers (eg {@link ForwardedRequestCustomizer}) or 
+     * <p>Customizers are often used to interpret optional headers (eg {@link ForwardedRequestCustomizer}) or
      * optional protocol semantics (eg {@link SecureRequestCustomizer}). 
-     * @param customizers
+     * @param customizers the list of customizers
      */
     public void setCustomizers(List<Customizer> customizers)
     {
@@ -201,13 +256,27 @@ public class HttpConfiguration
      * before being sent to the client.  A larger buffer can improve performance by allowing
      * a content producer to run without blocking, however larger buffers consume more memory and
      * may induce some latency before a client starts processing the content.
-     * @param responseBufferSize buffer size in bytes.
+     * @param outputBufferSize buffer size in bytes.
      */
-    public void setOutputBufferSize(int responseBufferSize)
+    public void setOutputBufferSize(int outputBufferSize)
     {
-        _outputBufferSize = responseBufferSize;
+        _outputBufferSize = outputBufferSize;
+        setOutputAggregationSize(outputBufferSize / 4);
     }
     
+    /* ------------------------------------------------------------ */
+    /**
+     * Set the max size of the response content write that is copied into the aggregate buffer.
+     * Writes that are smaller of this size are copied into the aggregate buffer, while
+     * writes that are larger of this size will cause the aggregate buffer to be flushed
+     * and the write to be executed without being copied.
+     * @param outputAggregationSize the max write size that is aggregated
+     */
+    public void setOutputAggregationSize(int outputAggregationSize)
+    {
+        _outputAggregationSize = outputAggregationSize;
+    }
+
     /* ------------------------------------------------------------ */
     /** Set the maximum size of a request header.
      * <p>Larger headers will allow for more and/or larger cookies plus larger form content encoded 
@@ -242,28 +311,32 @@ public class HttpConfiguration
     }
 
     /* ------------------------------------------------------------ */
-    /** Set the TCP/IP port used for CONFIDENTIAL and INTEGRAL 
-     * redirections.
-     * @param confidentialPort
+    /** Set the TCP/IP port used for CONFIDENTIAL and INTEGRAL redirections.
+     * @param securePort the secure port to redirect to.
      */
-    public void setSecurePort(int confidentialPort)
+    public void setSecurePort(int securePort)
     {
-        _securePort = confidentialPort;
+        _securePort = securePort;
     }
 
     /* ------------------------------------------------------------ */
-    /** Set the  URI scheme used for CONFIDENTIAL and INTEGRAL 
-     * redirections.
-     * @param confidentialScheme A string like"https"
+    /** Set the  URI scheme used for CONFIDENTIAL and INTEGRAL redirections.
+     * @param secureScheme A scheme string like "https"
      */
-    public void setSecureScheme(String confidentialScheme)
+    public void setSecureScheme(String secureScheme)
     {
-        _secureScheme = confidentialScheme;
+        _secureScheme = secureScheme;
     }
 
     @Override
     public String toString()
     {
-        return String.format("%s@%x{%d,%d/%d,%s://:%d,%s}",this.getClass().getSimpleName(),hashCode(),_outputBufferSize,_requestHeaderSize,_responseHeaderSize,_secureScheme,_securePort,_customizers);
+        return String.format("%s@%x{%d/%d,%d/%d,%s://:%d,%s}",
+                this.getClass().getSimpleName(),
+                hashCode(),
+                _outputBufferSize, _outputAggregationSize,
+                _requestHeaderSize,_responseHeaderSize,
+                _secureScheme,_securePort,
+                _customizers);
     }
 }
index 16cbbf93d6b29f9554926e22ea2e8e075afc872a..c489ae9b3da3c94317e8b8620e67a723583960a2 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -20,6 +20,7 @@ package org.eclipse.jetty.server;
 
 import java.io.IOException;
 import java.nio.ByteBuffer;
+import java.nio.channels.WritePendingException;
 import java.util.concurrent.RejectedExecutionException;
 
 import org.eclipse.jetty.http.HttpGenerator;
@@ -44,7 +45,7 @@ import org.eclipse.jetty.util.log.Logger;
 /**
  * <p>A {@link Connection} that handles the HTTP protocol.</p>
  */
-public class HttpConnection extends AbstractConnection implements Runnable, HttpTransport
+public class HttpConnection extends AbstractConnection implements Runnable, HttpTransport, Connection.UpgradeFrom
 {
     public static final String UPGRADE_CONNECTION_ATTRIBUTE = "org.eclipse.jetty.server.HttpConnection.UPGRADE";
     private static final boolean REQUEST_BUFFER_DIRECT=false;
@@ -61,12 +62,13 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
     private final HttpParser _parser;
     private volatile ByteBuffer _requestBuffer = null;
     private volatile ByteBuffer _chunk = null;
+    private final SendCallback _sendCallback = new SendCallback();
 
 
     /* ------------------------------------------------------------ */
     /** Get the current connection that this thread is dispatched to.
-     * Note that a thread may be processing a request asynchronously and 
-     * thus not be dispatched to the connection.  
+     * Note that a thread may be processing a request asynchronously and
+     * thus not be dispatched to the connection.
      * @see Request#getAttribute(String) for a more general way to access the HttpConnection
      * @return the current HttpConnection or null
      */
@@ -78,10 +80,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
     protected static HttpConnection setCurrentConnection(HttpConnection connection)
     {
         HttpConnection last=__currentConnection.get();
-        if (connection==null)
-            __currentConnection.remove();
-        else 
-            __currentConnection.set(connection);
+        __currentConnection.set(connection);
         return last;
     }
 
@@ -103,24 +102,25 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
         HttpInput<ByteBuffer> input = newHttpInput();
         _channel = newHttpChannel(input);
         _parser = newHttpParser();
-        LOG.debug("New HTTP Connection {}", this);
+        if (LOG.isDebugEnabled())
+            LOG.debug("New HTTP Connection {}", this);
     }
 
     protected HttpGenerator newHttpGenerator()
     {
         return new HttpGenerator(_config.getSendServerVersion(),_config.getSendXPoweredBy());
     }
-    
+
     protected HttpInput<ByteBuffer> newHttpInput()
     {
         return new HttpInputOverHTTP(this);
     }
-    
+
     protected HttpChannelOverHttp newHttpChannel(HttpInput<ByteBuffer> httpInput)
     {
         return new HttpChannelOverHttp(_connector, _config, getEndPoint(), this, httpInput);
     }
-    
+
     protected HttpParser newHttpParser()
     {
         return new HttpParser(newRequestHandler(), getHttpConfiguration().getRequestHeaderSize());
@@ -163,6 +163,18 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
         return getHttpChannel().getRequests();
     }
 
+    @Override
+    public ByteBuffer onUpgradeFrom()
+    {
+        if (BufferUtil.hasContent(_requestBuffer))
+        {
+            ByteBuffer buffer = _requestBuffer;
+            _requestBuffer=null;
+            return buffer;
+        }
+        return null;
+    }
+
     void releaseRequestBuffer()
     {
         if (_requestBuffer != null && !_requestBuffer.hasRemaining())
@@ -172,7 +184,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
             _bufferPool.release(buffer);
         }
     }
-    
+
     public ByteBuffer getRequestBuffer()
     {
         if (_requestBuffer == null)
@@ -191,7 +203,8 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
     @Override
     public void onFillable()
     {
-        LOG.debug("{} onFillable {}", this, _channel.getState());
+        if (LOG.isDebugEnabled())
+            LOG.debug("{} onFillable {}", this, _channel.getState());
 
         final HttpConnection last=setCurrentConnection(this);
         int filled=Integer.MAX_VALUE;
@@ -204,10 +217,10 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
                 // Do we need some data to parse
                 if (BufferUtil.isEmpty(_requestBuffer))
                 {
-                    // If the previous iteration filled 0 bytes or saw a close, then break here 
+                    // If the previous iteration filled 0 bytes or saw a close, then break here
                     if (filled<=0)
                         break;
-                        
+
                     // Can we fill?
                     if(getEndPoint().isInputShutdown())
                     {
@@ -226,13 +239,13 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
                         filled = getEndPoint().fill(_requestBuffer);
                         if (filled==0) // Do a retry on fill 0 (optimization for SSL connections)
                             filled = getEndPoint().fill(_requestBuffer);
-                        
+
                         // tell parser
                         if (filled < 0)
                             _parser.atEOF();
                     }
                 }
-                
+
                 // Parse the buffer
                 if (_parser.parseNext(_requestBuffer==null?BufferUtil.EMPTY_BUFFER:_requestBuffer))
                 {
@@ -265,7 +278,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
             close();
         }
         finally
-        {                        
+        {
             setCurrentConnection(last);
             if (!suspended && getEndPoint().isOpen() && getEndPoint().getConnection()==this)
             {
@@ -282,7 +295,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
     {
         // Not in a race here for the request buffer with #onFillable because an async consumer of
         // content would only be started after onFillable has given up control.
-        // In a little bit of a race with #completed, but then not sure if it is legal to be doing 
+        // In a little bit of a race with #completed, but then not sure if it is legal to be doing
         // async calls to IO and have a completed call at the same time.
         ByteBuffer requestBuffer = getRequestBuffer();
 
@@ -302,7 +315,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
 
             if (parsed)
                 break;
-            
+
             // OK lets read some data
             int filled=getEndPoint().fill(requestBuffer);
             if (LOG.isDebugEnabled()) // Avoid boxing of variable 'filled'
@@ -318,7 +331,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
             }
         }
     }
-    
+
     @Override
     public void completed()
     {
@@ -328,10 +341,8 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
             Connection connection = (Connection)_channel.getRequest().getAttribute(UPGRADE_CONNECTION_ATTRIBUTE);
             if (connection != null)
             {
-                LOG.debug("Upgrade from {} to {}", this, connection);
-                onClose();
-                getEndPoint().setConnection(connection);
-                connection.onOpen();
+                _channel.getState().upgrade();
+                getEndPoint().upgrade(connection);
                 _channel.reset();
                 _parser.reset();
                 _generator.reset();
@@ -339,15 +350,32 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
                 return;
             }
         }
-        
+
         // Finish consuming the request
         // If we are still expecting
         if (_channel.isExpecting100Continue())
+        {
             // close to seek EOF
             _parser.close();
+        }
         else if (_parser.inContentState() && _generator.isPersistent())
-            // Complete reading the request
-            _channel.getRequest().getHttpInput().consumeAll();
+        {
+            // If we are async, then we have problems to complete neatly
+            if (_channel.getRequest().getHttpInput().isAsync())
+            {
+                if (LOG.isDebugEnabled())
+                    LOG.debug("unconsumed async input {}", this);
+                _channel.abort();
+            }
+            else
+            {
+                if (LOG.isDebugEnabled())
+                    LOG.debug("unconsumed input {}", this);
+                // Complete reading the request
+                if (!_channel.getRequest().getHttpInput().consumeAll())
+                    _channel.abort();
+            }
+        }
 
         // Reset the channel, parsers and generator
         _channel.reset();
@@ -355,7 +383,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
             _parser.reset();
         else
             _parser.close();
-        
+
         // Not in a race here with onFillable, because it has given up control before calling handle.
         // in a slight race with #completed, but not sure what to do with that anyway.
         releaseRequestBuffer();
@@ -398,7 +426,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
                     getEndPoint().close();
                 }
             }
-            // else the parser must be closed, so seek the EOF if we are still open 
+            // else the parser must be closed, so seek the EOF if we are still open
             else if (getEndPoint().isOpen())
                 fillInterested();
         }
@@ -418,42 +446,65 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
         fillInterested();
     }
 
+    @Override
+    public void onClose()
+    {
+        _sendCallback.close();
+        super.onClose();
+    }
+
     @Override
     public void run()
     {
         onFillable();
     }
 
-
     @Override
     public void send(ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback)
     {
-        if (info==null)
-            new ContentCallback(content,lastContent,callback).iterate();
-        else
-        {
-            // If we are still expecting a 100 continues
-            if (_channel.isExpecting100Continue())
-                // then we can't be persistent
-                _generator.setPersistent(false);
-            new CommitCallback(info,content,lastContent,callback).iterate();
-        }
+        // If we are still expecting a 100 continues when we commit
+        if (info!=null && _channel.isExpecting100Continue())
+            // then we can't be persistent
+            _generator.setPersistent(false);
+
+        if(_sendCallback.reset(info,content,lastContent,callback))
+            _sendCallback.iterate();
     }
 
     @Override
     public void send(ByteBuffer content, boolean lastContent, Callback callback)
     {
-        new ContentCallback(content,lastContent,callback).iterate();
+        if (!lastContent && BufferUtil.isEmpty(content))
+            callback.succeeded();
+        else if (_sendCallback.reset(null,content,lastContent,callback))
+            _sendCallback.iterate();
+    }
+
+    @Override
+    public void abort()
+    {
+        // Do a direct close of the output, as this may indicate to a client that the
+        // response is bad either with RST or by abnormal completion of chunked response.
+        getEndPoint().close();
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("%s[p=%s,g=%s,c=%s]",
+                super.toString(),
+                _parser,
+                _generator,
+                _channel);
     }
 
-    
     protected class HttpChannelOverHttp extends HttpChannel<ByteBuffer>
     {
         public HttpChannelOverHttp(Connector connector, HttpConfiguration config, EndPoint endPoint, HttpTransport transport, HttpInput<ByteBuffer> input)
         {
             super(connector,config,endPoint,transport,input);
         }
-        
+
         @Override
         public void earlyEOF()
         {
@@ -509,6 +560,12 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
                         getResponse().getHttpFields().add(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE);
                     break;
                 }
+                case HTTP_2:
+                {
+                    persistent=false;
+                    badMessage(400,null);
+                    return true;
+                }
                 default:
                 {
                     throw new IllegalStateException();
@@ -518,7 +575,16 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
             if (!persistent)
                 _generator.setPersistent(false);
 
-            return super.headerComplete();
+            if (!super.headerComplete())
+                return false;
+
+            // Should we delay dispatch until we have some content?
+            // We should not delay if there is no content expect or client is expecting 100 or the response is already committed or the request buffer already has something in it to parse
+            if (getHttpConfiguration().isDelayDispatchUntilContent() && _parser.getContentLength() > 0 &&
+                    !isExpecting100Continue() && !isCommitted() && BufferUtil.isEmpty(_requestBuffer))
+                return false;
+
+            return true;
         }
 
         @Override
@@ -529,11 +595,11 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
         }
 
         @Override
-        public void failed()
+        public void abort()
         {
-            getEndPoint().shutdownOutput();
+            super.abort();
+            _generator.setPersistent(false);
         }
-        
 
         @Override
         public boolean messageComplete()
@@ -543,25 +609,46 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
         }
     }
 
-    private class CommitCallback extends IteratingCallback
+    private class SendCallback extends IteratingCallback
     {
-        final ByteBuffer _content;
-        final boolean _lastContent;
-        final ResponseInfo _info;
-        final Callback _callback;
-        ByteBuffer _header;
+        private ResponseInfo _info;
+        private ByteBuffer _content;
+        private boolean _lastContent;
+        private Callback _callback;
+        private ByteBuffer _header;
+        private boolean _shutdownOut;
+
+        private SendCallback()
+        {
+            super(true);
+        }
 
-        CommitCallback(ResponseInfo info, ByteBuffer content, boolean last, Callback callback)
+        private boolean reset(ResponseInfo info, ByteBuffer content, boolean last, Callback callback)
         {
-            _info=info;
-            _content=content;
-            _lastContent=last;
-            _callback=callback;
+            if (reset())
+            {
+                _info = info;
+                _content = content;
+                _lastContent = last;
+                _callback = callback;
+                _header = null;
+                _shutdownOut = false;
+                return true;
+            }
+
+            if (isClosed())
+                callback.failed(new EofException());
+            else
+                callback.failed(new WritePendingException());
+            return false;
         }
 
         @Override
         public Action process() throws Exception
         {
+            if (_callback==null)
+                throw new IllegalStateException();
+
             ByteBuffer chunk = _chunk;
             while (true)
             {
@@ -579,25 +666,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
                 {
                     case NEED_HEADER:
                     {
-                        // Look for optimisation to avoid allocating a _header buffer
-                        /*
-                         Cannot use this optimisation unless we work out how not to overwrite data in user passed arrays.
-                        if (_lastContent && _content!=null && !_content.isReadOnly() && _content.hasArray() && BufferUtil.space(_content)>_config.getResponseHeaderSize() )
-                        {
-                            // use spare space in content buffer for header buffer
-                            int p=_content.position();
-                            int l=_content.limit();
-                            _content.position(l);
-                            _content.limit(l+_config.getResponseHeaderSize());
-                            _header=_content.slice();
-                            _header.limit(0);
-                            _content.position(p);
-                            _content.limit(l);
-                        }
-                        else
-                        */
-                            _header = _bufferPool.acquire(_config.getResponseHeaderSize(), HEADER_BUFFER_DIRECT);
-                            
+                        _header = _bufferPool.acquire(_config.getResponseHeaderSize(), HEADER_BUFFER_DIRECT);
                         continue;
                     }
                     case NEED_CHUNK:
@@ -607,8 +676,8 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
                     }
                     case FLUSH:
                     {
-                        // Don't write the chunk or the content if this is a HEAD response
-                        if (_channel.getRequest().isHead())
+                        // Don't write the chunk or the content if this is a HEAD response, or any other type of response that should have no content
+                        if (_channel.getRequest().isHead() || _generator.isNoContent())
                         {
                             BufferUtil.clear(chunk);
                             BufferUtil.clear(_content);
@@ -639,22 +708,18 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
                             getEndPoint().write(this, _content);
                         }
                         else
-                            continue;
+                        {
+                            succeeded(); // nothing to write
+                        }
                         return Action.SCHEDULED;
                     }
                     case SHUTDOWN_OUT:
                     {
-                        getEndPoint().shutdownOutput();
+                        _shutdownOut=true;
                         continue;
                     }
                     case DONE:
                     {
-                        if (_header!=null)
-                        {
-                            // don't release header in spare content buffer
-                            if (!_lastContent || _content==null || !_content.hasArray() || !_header.hasArray() ||  _content.array()!=_header.array())
-                                _bufferPool.release(_header);
-                        }
                         return Action.SUCCEEDED;
                     }
                     case CONTINUE:
@@ -669,122 +734,36 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
             }
         }
 
-        @Override
-        protected void completed()
-        {
-            _callback.succeeded();
-        }
-
-        @Override
-        public void failed(final Throwable x)
-        {
-            super.failed(x);
-            failedCallback(_callback,x);
-        }
-    }
-
-    private class ContentCallback extends IteratingCallback
-    {
-        final ByteBuffer _content;
-        final boolean _lastContent;
-        final Callback _callback;
-
-        ContentCallback(ByteBuffer content, boolean last, Callback callback)
+        private void releaseHeader()
         {
-            _content=content;
-            _lastContent=last;
-            _callback=callback;
+            ByteBuffer h=_header;
+            _header=null;
+            if (h!=null)
+                _bufferPool.release(h);
         }
 
         @Override
-        public Action process() throws Exception
+        protected void onCompleteSuccess()
         {
-            ByteBuffer chunk = _chunk;
-            while (true)
-            {
-                HttpGenerator.Result result = _generator.generateResponse(null, null, chunk, _content, _lastContent);
-                if (LOG.isDebugEnabled())
-                    LOG.debug("{} generate: {} ({},{})@{}",
-                        this,
-                        result,
-                        BufferUtil.toSummaryString(_content),
-                        _lastContent,
-                        _generator.getState());
-
-                switch (result)
-                {
-                    case NEED_HEADER:
-                        throw new IllegalStateException();
-                    case NEED_CHUNK:
-                    {
-                        chunk = _chunk = _bufferPool.acquire(HttpGenerator.CHUNK_SIZE, CHUNK_BUFFER_DIRECT);
-                        continue;
-                    }
-                    case FLUSH:
-                    {
-                        // Don't write the chunk or the content if this is a HEAD response
-                        if (_channel.getRequest().isHead())
-                        {
-                            BufferUtil.clear(chunk);
-                            BufferUtil.clear(_content);
-                            continue;
-                        }
-                        else if (BufferUtil.hasContent(chunk))
-                        {
-                            if (BufferUtil.hasContent(_content))
-                                getEndPoint().write(this, chunk, _content);
-                            else
-                                getEndPoint().write(this, chunk);
-                        }
-                        else if (BufferUtil.hasContent(_content))
-                        {
-                            getEndPoint().write(this, _content);
-                        }
-                        else
-                            continue;
-                        return Action.SCHEDULED;
-                    }
-                    case SHUTDOWN_OUT:
-                    {
-                        getEndPoint().shutdownOutput();
-                        continue;
-                    }
-                    case DONE:
-                    {
-                        return Action.SUCCEEDED;
-                    }
-                    case CONTINUE:
-                    {
-                        break;
-                    }
-                    default:
-                    {
-                        throw new IllegalStateException("generateResponse="+result);
-                    }
-                }
-            }
+            releaseHeader();
+            _callback.succeeded();
+            if (_shutdownOut)
+                getEndPoint().shutdownOutput();
         }
 
         @Override
-        protected void completed()
+        public void onCompleteFailure(final Throwable x)
         {
-            _callback.succeeded();
+            releaseHeader();
+            failedCallback(_callback,x);
+            if (_shutdownOut)
+                getEndPoint().shutdownOutput();
         }
 
         @Override
-        public void failed(final Throwable x)
+        public String toString()
         {
-            super.failed(x);
-            failedCallback(_callback,x);
+            return String.format("%s[i=%s,cb=%s]",super.toString(),_info,_callback);
         }
     }
-
-    @Override
-    public void abort()
-    {
-        // Do a direct close of the output, as this may indicate to a client that the 
-        // response is bad either with RST or by abnormal completion of chunked response.
-        getEndPoint().close();
-    }
-
 }
index ce6ffdb7b4b540cd94d7b3fd0d87771df97e5af2..1f402a88f69414996175ac7d6f3e75504e197900 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 833ecdede7f36f09d9dcce8fdf88bcf9cbaa1261..963d66b578f111d80e1e21b4fb6dcebd55683989 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -20,6 +20,7 @@ package org.eclipse.jetty.server;
 
 import java.io.IOException;
 import java.util.Objects;
+
 import javax.servlet.ReadListener;
 import javax.servlet.ServletInputStream;
 
@@ -146,7 +147,8 @@ public abstract class HttpInput<T> extends ServletInputStream implements Runnabl
             {
                 if (_eofState != null)
                 {
-                    LOG.debug("{} eof {}", this, _eofState);
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("{} eof {}", this, _eofState);
                     _contentState = _eofState;
                 }
             }
@@ -237,7 +239,8 @@ public abstract class HttpInput<T> extends ServletInputStream implements Runnabl
         {
             if (!isEOF())
             {
-                LOG.debug("{} early EOF", this);
+                if (LOG.isDebugEnabled())
+                    LOG.debug("{} early EOF", this);
                 _eofState = EARLY_EOF;
                 if (_listener == null)
                     return;
@@ -246,6 +249,15 @@ public abstract class HttpInput<T> extends ServletInputStream implements Runnabl
         _channelState.onReadPossible();
     }
 
+
+    public boolean isEarlyEOF()
+    {
+        synchronized (lock())
+        {
+            return _contentState==EARLY_EOF;
+        }
+    }
+
     /**
      * This method should be called to signal that all the expected
      * content arrived.
@@ -256,7 +268,8 @@ public abstract class HttpInput<T> extends ServletInputStream implements Runnabl
         {
             if (!isEOF())
             {
-                LOG.debug("{} EOF", this);
+                if (LOG.isDebugEnabled())
+                    LOG.debug("{} EOF", this);
                 _eofState = EOF;
                 if (_listener == null)
                     return;
@@ -265,10 +278,14 @@ public abstract class HttpInput<T> extends ServletInputStream implements Runnabl
         _channelState.onReadPossible();
     }
 
-    public void consumeAll()
+    public boolean consumeAll()
     {
         synchronized (lock())
         {
+            // Don't bother reading if we already know there was an error.
+            if (_onError != null)
+                return false;
+
             try
             {
                 while (!isFinished())
@@ -279,10 +296,12 @@ public abstract class HttpInput<T> extends ServletInputStream implements Runnabl
                     else
                         consume(item, remaining(item));
                 }
+                return true;
             }
             catch (IOException e)
             {
                 LOG.debug(e);
+                return false;
             }
         }
     }
@@ -294,7 +313,7 @@ public abstract class HttpInput<T> extends ServletInputStream implements Runnabl
             return _contentState==ASYNC;
         }
     }
-    
+
     /**
      * @return whether an EOF has been detected, even though there may be content to consume.
      */
@@ -315,6 +334,7 @@ public abstract class HttpInput<T> extends ServletInputStream implements Runnabl
         }
     }
 
+
     @Override
     public boolean isReady()
     {
@@ -346,16 +366,30 @@ public abstract class HttpInput<T> extends ServletInputStream implements Runnabl
     @Override
     public void setReadListener(ReadListener readListener)
     {
-        readListener = Objects.requireNonNull(readListener);
-        synchronized (lock())
+        try
         {
-            if (_contentState != STREAM)
-                throw new IllegalStateException("state=" + _contentState);
-            _contentState = ASYNC;
-            _listener = readListener;
-            _notReady = true;
+            readListener = Objects.requireNonNull(readListener);
+            boolean content;
+            synchronized (lock())
+            {
+                if (_contentState != STREAM)
+                    throw new IllegalStateException("state=" + _contentState);
+                _contentState = ASYNC;
+                _listener = readListener;
+                _notReady = true;
+
+                content = getNextContent()!=null || isEOF();
+
+            }
+            if (content)
+                _channelState.onReadPossible();
+            else
+                unready();
+        }
+        catch(IOException e)
+        {
+            throw new RuntimeIOException(e);
         }
-        _channelState.onReadPossible();
     }
 
     public void failed(Throwable x)
@@ -418,6 +452,18 @@ public abstract class HttpInput<T> extends ServletInputStream implements Runnabl
         }
     }
 
+    @Override
+    public String toString()
+    {
+        return String.format("%s@%x[r=%d,s=%s,e=%s,f=%s]",
+                getClass().getSimpleName(),
+                hashCode(),
+                _contentRead,
+                _contentState,
+                _eofState,
+                _onError);
+    }
+
     protected static abstract class State
     {
         public void waitForContent(HttpInput<?> in) throws IOException
@@ -470,7 +516,7 @@ public abstract class HttpInput<T> extends ServletInputStream implements Runnabl
         @Override
         public int noContent() throws IOException
         {
-            throw new EofException();
+            throw new EofException("Early EOF");
         }
 
         @Override
index 35524500492da55d1160e177495b771a05c15e70..f91becc60fb16565bf1c90eaeffd4f4b9a7416da 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -61,7 +61,8 @@ public class HttpInputOverHTTP extends HttpInput<ByteBuffer> implements Callback
             try (Blocker blocker=_readBlocker.acquire())
             {            
                 _httpConnection.fillInterested(blocker);
-                LOG.debug("{} block readable on {}",this,blocker);
+                if (LOG.isDebugEnabled())
+                    LOG.debug("{} block readable on {}",this,blocker);
                 blocker.block();
             }
 
index 7c0fd899a411f9e450f83e478860733feaa5ad79..47346cb1bd1f6fb91c21a32170d1ac6eabc2b025 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -55,7 +55,14 @@ public class HttpOutput extends ServletOutputStream implements Runnable
 {
     private static Logger LOG = Log.getLogger(HttpOutput.class);
     private final HttpChannel<?> _channel;
-    private final SharedBlockingCallback _writeblock=new SharedBlockingCallback();
+    private final SharedBlockingCallback _writeblock=new SharedBlockingCallback()
+    {
+        @Override
+        protected long getIdleTimeout()
+        {
+            return _channel.getIdleTimeout();
+        }
+    };
     private long _written;
     private ByteBuffer _aggregate;
     private int _bufferSize;
@@ -80,8 +87,14 @@ public class HttpOutput extends ServletOutputStream implements Runnable
     public HttpOutput(HttpChannel<?> channel)
     {
         _channel = channel;
-        _bufferSize = _channel.getHttpConfiguration().getOutputBufferSize();
-        _commitSize=_bufferSize/4;
+        HttpConfiguration config = channel.getHttpConfiguration();
+        _bufferSize = config.getOutputBufferSize();
+        _commitSize = config.getOutputAggregationSize();
+        if (_commitSize>_bufferSize)
+        {
+            LOG.warn("OutputAggregationSize {} exceeds bufferSize {}",_commitSize,_bufferSize);
+            _commitSize=_bufferSize;
+        }
     }
     
     public HttpChannel<?> getHttpChannel()
@@ -160,7 +173,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable
                         catch(IOException e)
                         {
                             LOG.debug(e);
-                            _channel.failed();
+                            _channel.abort();
                         }
                         releaseBuffer();
                         return;
@@ -195,7 +208,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable
                         catch(IOException e)
                         {
                             LOG.debug(e);
-                            _channel.failed();
+                            _channel.abort();
                         }
                         releaseBuffer();
                         return;
@@ -342,7 +355,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable
             write(_aggregate, complete && len==0);
 
             // should we fill aggregate again from the buffer?
-            if (len>0 && !complete && len<=_commitSize)
+            if (len>0 && !complete && len<=_commitSize && len<=BufferUtil.space(_aggregate))
             {
                 BufferUtil.append(_aggregate, b, off, len);
                 return;
@@ -616,12 +629,18 @@ public class HttpOutput extends ServletOutputStream implements Runnable
      * @param httpContent The content to send
      * @param callback The callback to use to notify success or failure
      */
-    public void sendContent(HttpContent httpContent, Callback callback) throws IOException
+    public void sendContent(HttpContent httpContent, Callback callback)
     {
         if (BufferUtil.hasContent(_aggregate))
-            throw new IOException("written");
+        {
+            callback.failed(new IOException("cannot sendContent() after write()"));
+            return;
+        }
         if (_channel.isCommitted())
-            throw new IOException("committed");
+        {
+            callback.failed(new IOException("committed"));
+            return;
+        }
 
         while (true)
         {
@@ -632,9 +651,12 @@ public class HttpOutput extends ServletOutputStream implements Runnable
                         continue;
                     break;
                 case ERROR:
-                    throw new EofException(_onError);
+                    callback.failed(new EofException(_onError));
+                    return;
+                    
                 case CLOSED:
-                    throw new EofException("Closed");
+                    callback.failed(new EofException("Closed"));
+                    return;
                 default:
                     throw new IllegalStateException();
             }
@@ -646,22 +668,37 @@ public class HttpOutput extends ServletOutputStream implements Runnable
 
         if (buffer!=null)
         {
+            if (LOG.isDebugEnabled())
+                LOG.debug("sendContent({}=={},{},direct={})",httpContent,BufferUtil.toDetailString(buffer),callback,_channel.useDirectBuffers());
+            
             sendContent(buffer,callback);
             return;
         }
 
-        ReadableByteChannel rbc=httpContent.getReadableByteChannel();
-        if (rbc!=null)
+        try
         {
-            // Close of the rbc is done by the async sendContent
-            sendContent(rbc,callback);
-            return;
-        }
+            ReadableByteChannel rbc=httpContent.getReadableByteChannel();
+            if (rbc!=null)
+            {
+                if (LOG.isDebugEnabled())
+                    LOG.debug("sendContent({}=={},{},direct={})",httpContent,rbc,callback,_channel.useDirectBuffers());
+                // Close of the rbc is done by the async sendContent
+                sendContent(rbc,callback);
+                return;
+            }
 
-        InputStream in = httpContent.getInputStream();
-        if ( in!=null )
+            InputStream in = httpContent.getInputStream();
+            if ( in!=null )
+            {
+                if (LOG.isDebugEnabled())
+                    LOG.debug("sendContent({}=={},{},direct={})",httpContent,in,callback,_channel.useDirectBuffers());
+                sendContent(in,callback);
+                return;
+            }
+        }
+        catch(Throwable th)
         {
-            sendContent(in,callback);
+            callback.failed(th);
             return;
         }
 
@@ -755,7 +792,8 @@ public class HttpOutput extends ServletOutputStream implements Runnable
                         {
                             Throwable th=_onError;
                             _onError=null;
-                            LOG.debug("onError",th);
+                            if (LOG.isDebugEnabled())
+                                LOG.debug("onError",th);
                             _writeListener.onError(th);
                             close();
 
@@ -763,16 +801,17 @@ public class HttpOutput extends ServletOutputStream implements Runnable
                         }
 
                 }
-                continue loop;
+                continue;
             }
-
+            
             switch(_state.get())
             {
-                case READY:
                 case CLOSED:
                     // even though a write is not possible, because a close has 
                     // occurred, we need to call onWritePossible to tell async
                     // producer that the last write completed.
+                    // so fall through
+                case READY:
                     try
                     {
                         _writeListener.onWritePossible();
@@ -783,8 +822,9 @@ public class HttpOutput extends ServletOutputStream implements Runnable
                         _onError=e;
                     }
                     break;
+                    
                 default:
-
+                    _onError=new IllegalStateException("state="+_state.get());
             }
         }
     }
@@ -798,7 +838,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable
     private abstract class AsyncICB extends IteratingCallback
     {
         @Override
-        protected void completed()
+        protected void onCompleteSuccess()
         {
             while(true)
             {
@@ -827,10 +867,9 @@ public class HttpOutput extends ServletOutputStream implements Runnable
         }
 
         @Override
-        public void failed(Throwable e)
+        public void onCompleteFailure(Throwable e)
         {
-            super.failed(e);
-            _onError=e;
+            _onError=e==null?new IOException():e;
             _channel.getState().onWritePossible();
         }
     }
@@ -949,9 +988,9 @@ public class HttpOutput extends ServletOutputStream implements Runnable
         }
 
         @Override
-        protected void completed()
+        protected void onCompleteSuccess()
         {
-            super.completed();
+            super.onCompleteSuccess();
             if (_complete)
                 closed();
         }
@@ -1014,9 +1053,9 @@ public class HttpOutput extends ServletOutputStream implements Runnable
         }
 
         @Override
-        public void failed(Throwable x)
+        public void onCompleteFailure(Throwable x)
         {
-            super.failed(x);
+            super.onCompleteFailure(x);
             _channel.getByteBufferPool().release(_buffer);
             try
             {
@@ -1078,9 +1117,9 @@ public class HttpOutput extends ServletOutputStream implements Runnable
         }
 
         @Override
-        public void failed(Throwable x)
+        public void onCompleteFailure(Throwable x)
         {
-            super.failed(x);
+            super.onCompleteFailure(x);
             _channel.getByteBufferPool().release(_buffer);
             try
             {
@@ -1092,5 +1131,4 @@ public class HttpOutput extends ServletOutputStream implements Runnable
             }
         }
     }
-
 }
index 7058425f659793d0e110bfb0122b25b3d99d973a..d3922467b2472b4962db10b423bdb1f012700714 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -24,7 +24,7 @@ import org.eclipse.jetty.http.HttpGenerator;
 import org.eclipse.jetty.util.Callback;
 
 public interface HttpTransport
-{
+{    
     void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback);
 
     void send(ByteBuffer content, boolean lastContent, Callback callback);
index d02a8c4b682f29f04e2440a7fc16d91f6534c384..bdef4f845c3fac76bfc5cec6845e82af80e2fed4 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index cb81d3c95e0a308e22906fdc897b6ef4ef3f3733..4340cabba65d1a4b3e67fd6e746e5ceb448e648a 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -81,7 +81,7 @@ public class InclusiveByteRange
      * @param size Size of the resource.
      * @return LazyList of satisfiable ranges
      */
-    public static List<InclusiveByteRange> satisfiableRanges(Enumeration headers, long size)
+    public static List<InclusiveByteRange> satisfiableRanges(Enumeration<String> headers, long size)
     {
         Object satRanges=null;
         
@@ -89,7 +89,7 @@ public class InclusiveByteRange
     headers:
         while (headers.hasMoreElements())
         {
-            String header = (String) headers.nextElement();
+            String header = headers.nextElement();
             StringTokenizer tok = new StringTokenizer(header,"=,",false);
             String t=null;
             try
index b4cdf8ff04deef2093b4c1cef64b9f1177a206cc..3baac05d2a6ada096c41c2c4f460568e53a89ef4 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 5796226362e7183a763879cffed30f05fd1caf1f..b41891c5fbdd0a2eb7dd2b712bd859b86260977d 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -133,12 +133,15 @@ public class LocalConnector extends AbstractConnector
      */
     public ByteBuffer getResponses(ByteBuffer requestsBuffer,long idleFor,TimeUnit units) throws Exception
     {
-        LOG.debug("requests {}", BufferUtil.toUTF8String(requestsBuffer));
+        if (LOG.isDebugEnabled())
+            LOG.debug("requests {}", BufferUtil.toUTF8String(requestsBuffer));
         LocalEndPoint endp = executeRequest(requestsBuffer);
         endp.waitUntilClosedOrIdleFor(idleFor,units);
         ByteBuffer responses = endp.takeOutput();
-        endp.getConnection().close();
-        LOG.debug("responses {}", BufferUtil.toUTF8String(responses));
+        if (endp.isOutputShutdown())
+            endp.close();
+        if (LOG.isDebugEnabled())
+            LOG.debug("responses {}", BufferUtil.toUTF8String(responses));
         return responses;
     }
 
@@ -155,6 +158,8 @@ public class LocalConnector extends AbstractConnector
 
     private LocalEndPoint executeRequest(ByteBuffer rawRequest)
     {
+        if (!isStarted())
+            throw new IllegalStateException("!STARTED");
         LocalEndPoint endp = new LocalEndPoint();
         endp.setInput(rawRequest);
         _connects.add(endp);
@@ -164,7 +169,8 @@ public class LocalConnector extends AbstractConnector
     @Override
     protected void accept(int acceptorID) throws IOException, InterruptedException
     {
-        LOG.debug("accepting {}", acceptorID);
+        if (LOG.isDebugEnabled())
+            LOG.debug("accepting {}", acceptorID);
         LocalEndPoint endPoint = _connects.take();
         endPoint.onOpen();
         onEndPointOpened(endPoint);
@@ -249,7 +255,8 @@ public class LocalConnector extends AbstractConnector
                     {
                         if (size==getOutput().remaining())
                         {
-                            LOG.debug("idle for {} {}",idleFor,units);
+                            if (LOG.isDebugEnabled())
+                                LOG.debug("idle for {} {}",idleFor,units);
                             return;
                         }
                         size=getOutput().remaining();
index 1aad488e707d9c45d57168132ecd5adc969af776..4c379916232190535b3198d8225cec554b68c663 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 2c2286e254842f9c5ccd1b12765d9e87687961f7..0aa5aade69a4a099bd49850ccfc6e519fd08929b 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 3d010699e2acc55c086aa7414bc195b0af6d2001..be4149df909da2256d3fe077bfa8316749f8c1c3 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
 package org.eclipse.jetty.server;
 
 import java.io.IOException;
+import java.nio.ByteBuffer;
 import java.util.List;
+
 import javax.net.ssl.SSLEngine;
 import javax.net.ssl.SSLEngineResult;
 
 import org.eclipse.jetty.io.AbstractConnection;
 import org.eclipse.jetty.io.Connection;
 import org.eclipse.jetty.io.EndPoint;
-import org.eclipse.jetty.server.ConnectionFactory;
-import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.util.BufferUtil;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
@@ -95,7 +95,8 @@ public abstract class NegotiatingServerConnection extends AbstractConnection
                 if (engine.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING)
                 {
                     // Here the SSL handshake is finished, but the protocol has not been negotiated.
-                    LOG.debug("{} could not negotiate protocol, SSLEngine: {}", this, engine);
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("{} could not negotiate protocol, SSLEngine: {}", this, engine);
                     close();
                 }
                 else
@@ -110,26 +111,24 @@ public abstract class NegotiatingServerConnection extends AbstractConnection
                 ConnectionFactory connectionFactory = connector.getConnectionFactory(protocol);
                 if (connectionFactory == null)
                 {
-                    LOG.debug("{} application selected protocol '{}', but no correspondent {} has been configured",
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("{} application selected protocol '{}', but no correspondent {} has been configured",
                             this, protocol, ConnectionFactory.class.getName());
                     close();
                 }
                 else
                 {
                     EndPoint endPoint = getEndPoint();
-                    Connection oldConnection = endPoint.getConnection();
                     Connection newConnection = connectionFactory.newConnection(connector, endPoint);
-                    LOG.debug("{} switching from {} to {}", this, oldConnection, newConnection);
-                    oldConnection.onClose();
-                    endPoint.setConnection(newConnection);
-                    getEndPoint().getConnection().onOpen();
+                    endPoint.upgrade(newConnection);
                 }
             }
         }
         else if (filled < 0)
         {
             // Something went bad, we need to close.
-            LOG.debug("{} closing on client close", this);
+            if (LOG.isDebugEnabled())
+                LOG.debug("{} closing on client close", this);
             close();
         }
         else
index f826d7115294a9a39459d78ed2692413a6c1f0bb..10547c2ef3598f68d32589d51ac8d3bc3f7a84d1 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 58fdc9881c6380f92b4ca6c59f0e752fc6afb420..7e6ecee4a25ea3eec64d4432eea332170ee8b034 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 34de615be581d50f9eb8423314199eca7d544331..9bf0dee42d6709a646d3d7168588f893b36c7cd7 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 881fbfa08420e00e6f3dc252479e9a1902305e70..e0888979bea2db157fe28342f5c8f71366b036ac 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -55,7 +55,8 @@ public abstract class QueuedHttpInput<T> extends HttpInput<T>
         {
             boolean wasEmpty = _inputQ.isEmpty();
             _inputQ.add(item);
-            LOG.debug("{} queued {}", this, item);
+            if (LOG.isDebugEnabled())
+                LOG.debug("{} queued {}", this, item);
             if (wasEmpty)
             {
                 if (!onAsyncRead())
@@ -90,7 +91,8 @@ public abstract class QueuedHttpInput<T> extends HttpInput<T>
             {
                 _inputQ.pollUnsafe();
                 onContentConsumed(item);
-                LOG.debug("{} consumed {}", this, item);
+                if (LOG.isDebugEnabled())
+                    LOG.debug("{} consumed {}", this, item);
                 item = _inputQ.peekUnsafe();
             }
             return item;
@@ -105,7 +107,8 @@ public abstract class QueuedHttpInput<T> extends HttpInput<T>
             {
                 try
                 {
-                    LOG.debug("{} waiting for content", this);
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("{} waiting for content", this);
                     lock().wait();
                 }
                 catch (InterruptedException e)
index 5221d638ca7a17df95a436c9571aa9cc70adbc03..fe64bf675f8121d0e00a351ad8da23b1eecc20c7 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 77c80abc2930f0b8474d69a227b638ff9f8eb23e..a39a13978887b6d97821c2b37211d89b6b9cfde1 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -40,6 +40,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+
 import javax.servlet.AsyncContext;
 import javax.servlet.AsyncListener;
 import javax.servlet.DispatcherType;
@@ -130,7 +131,7 @@ public class Request implements HttpServletRequest
     private final HttpFields _fields=new HttpFields();
     private final List<ServletRequestAttributeListener>  _requestAttributeListeners=new ArrayList<>();
     private final HttpInput<?> _input;
-    
+
     public static class MultiPartCleanerListener implements ServletRequestListener
     {
         @Override
@@ -162,10 +163,10 @@ public class Request implements HttpServletRequest
         {
             //nothing to do, multipart config set up by ServletHolder.handle()
         }
-        
+
     }
-    
-    
+
+
 
     private boolean _secure;
     private boolean _asyncSupported = true;
@@ -208,7 +209,7 @@ public class Request implements HttpServletRequest
     private HttpURI _uri;
     private MultiPartInputStreamParser _multiPartInputStream; //if the request is a multi-part mime
     private AsyncContextState _async;
-    
+
     /* ------------------------------------------------------------ */
     public Request(HttpChannel<?> channel, HttpInput<?> input)
     {
@@ -386,10 +387,8 @@ public class Request implements HttpServletRequest
         }
         catch (IOException | ServletException e)
         {
-            if (LOG.isDebugEnabled())
-                LOG.warn(e);
-            else
-                LOG.warn(e.toString());
+            LOG.warn(e);
+            throw new RuntimeException(e);
         }
     }
 
@@ -398,9 +397,9 @@ public class Request implements HttpServletRequest
     public AsyncContext getAsyncContext()
     {
         HttpChannelState state = getHttpChannelState();
-        if (_async==null || state.isInitial() && !state.isAsync())
+        if (_async==null || !state.isAsyncStarted())
             throw new IllegalStateException(state.getStatusString());
-        
+
         return _async;
     }
 
@@ -533,7 +532,7 @@ public class Request implements HttpServletRequest
     {
         return _input.getContentRead();
     }
-    
+
     /* ------------------------------------------------------------ */
     /*
      * @see javax.servlet.ServletRequest#getContentType()
@@ -574,7 +573,7 @@ public class Request implements HttpServletRequest
         {
             if (_cookies == null || _cookies.getCookies().length == 0)
                 return null;
-            
+
             return _cookies.getCookies();
         }
 
@@ -598,7 +597,7 @@ public class Request implements HttpServletRequest
         //Javadoc for Request.getCookies() stipulates null for no cookies
         if (_cookies == null || _cookies.getCookies().length == 0)
             return null;
-        
+
         return _cookies.getCookies();
     }
 
@@ -1018,7 +1017,7 @@ public class Request implements HttpServletRequest
     /* ------------------------------------------------------------ */
     /**
      * Access the underlying Remote {@link InetSocketAddress} for this request.
-     * 
+     *
      * @return the remote {@link InetSocketAddress} for this request, or null if the request has no remote (see {@link ServletRequest#getRemoteAddr()} for
      *         conditions that result in no remote address)
      */
@@ -1041,14 +1040,14 @@ public class Request implements HttpServletRequest
         InetSocketAddress remote=_remote;
         if (remote==null)
             remote=_channel.getRemoteAddress();
-        
+
         if (remote==null)
             return "";
-        
+
         InetAddress address = remote.getAddress();
         if (address==null)
             return remote.getHostString();
-        
+
         return address.getHostAddress();
     }
 
@@ -1209,7 +1208,7 @@ public class Request implements HttpServletRequest
 
         // Return host from header field
         String hostPort = _fields.getStringField(HttpHeader.HOST);
-        
+
         _port=0;
         if (hostPort != null)
         {
@@ -1240,14 +1239,14 @@ public class Request implements HttpServletRequest
             }
             if (hostPort.charAt(0)=='[')
             {
-                if (hostPort.charAt(len-1)!=']') 
+                if (hostPort.charAt(len-1)!=']')
                 {
                     LOG.warn("Bad IPv6 "+hostPort);
                     _serverName=hostPort;
                     _port=0;
                     return _serverName;
                 }
-                _serverName = hostPort.substring(1,len-1);
+                _serverName = hostPort.substring(0,len);
             }
             else if (len==hostPort.length())
                 _serverName=hostPort;
@@ -1396,7 +1395,7 @@ public class Request implements HttpServletRequest
 
         if (!create)
             return null;
-        
+
         if (getResponse().isCommitted())
             throw new IllegalStateException("Response is committed");
 
@@ -1484,7 +1483,7 @@ public class Request implements HttpServletRequest
             UserIdentity user = ((Authentication.User)_authentication).getUserIdentity();
             return user.getUserPrincipal();
         }
-        
+
         return null;
     }
 
@@ -1597,7 +1596,7 @@ public class Request implements HttpServletRequest
     {
         if (_context != null)
             throw new IllegalStateException("Request in context!");
-        
+
         if (_inputState == __READER)
         {
             try
@@ -1720,7 +1719,7 @@ public class Request implements HttpServletRequest
             setQueryEncoding(value == null?null:value.toString());
         else if ("org.eclipse.jetty.server.sendContent".equals(name))
             LOG.warn("Deprecated: org.eclipse.jetty.server.sendContent");
-        
+
         if (_attributes == null)
             _attributes = new AttributesMap();
         _attributes.setAttribute(name,value);
@@ -1865,9 +1864,6 @@ public class Request implements HttpServletRequest
     public void setHandled(boolean h)
     {
         _handled = h;
-        Response r=getResponse();
-        if (_handled && r.getStatus()==0)
-            r.setStatus(200);
     }
 
     /* ------------------------------------------------------------ */
@@ -1942,7 +1938,7 @@ public class Request implements HttpServletRequest
     {
         _remote = addr;
     }
-    
+
     /* ------------------------------------------------------------ */
     /**
      * @param requestedSessionId
@@ -2089,7 +2085,13 @@ public class Request implements HttpServletRequest
     @Override
     public String toString()
     {
-        return (_handled?"[":"(") + getMethod() + " " + _uri + (_handled?"]@":")@") + hashCode() + " " + super.toString();
+        return String.format("%s%s%s %s%s@%x",
+                getClass().getSimpleName(),
+                _handled ? "[" : "(",
+                getMethod(),
+                _uri,
+                _handled ? "]" : ")",
+                hashCode());
     }
 
     /* ------------------------------------------------------------ */
@@ -2131,14 +2133,14 @@ public class Request implements HttpServletRequest
         if (_multiPartInputStream == null)
         {
             MultipartConfigElement config = (MultipartConfigElement)getAttribute(__MULTIPART_CONFIG_ELEMENT);
-            
+
             if (config == null)
                 throw new IllegalStateException("No multipart config for servlet");
-            
+
             _multiPartInputStream = new MultiPartInputStreamParser(getInputStream(),
-                                                             getContentType(), config, 
+                                                             getContentType(), config,
                                                              (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null));
-            
+
             setAttribute(__MULTIPART_INPUT_STREAM, _multiPartInputStream);
             setAttribute(__MULTIPART_CONTEXT, _context);
             Collection<Part> parts = _multiPartInputStream.getParts(); //causes parsing
@@ -2250,9 +2252,9 @@ public class Request implements HttpServletRequest
         {
             //Instantiate an instance and inject it
             T h = getContext().createInstance(handlerClass);
-            
+
             //TODO handle the rest of the upgrade process
-            
+
             return h;
         }
         catch (Exception e)
index 0cb1a5306b35021e1fce74144b8c0c0339553b63..4391e2720ccdfb305f636af2836df7d66839573d 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index e39c4a60fb3a874aab7af80193858eee07ea32e9..187f89f37d2b4d67cd21e8b12776d26bf95dd1c3 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -33,7 +33,6 @@ import java.util.concurrent.atomic.AtomicReference;
 
 import org.eclipse.jetty.http.DateGenerator;
 import org.eclipse.jetty.http.HttpContent;
-import org.eclipse.jetty.http.HttpContent.ResourceAsHttpContent;
 import org.eclipse.jetty.http.MimeTypes;
 import org.eclipse.jetty.util.BufferUtil;
 import org.eclipse.jetty.util.log.Log;
@@ -59,9 +58,9 @@ public class ResourceCache
     private final boolean _etagSupported;
     private final boolean  _useFileMappedBuffer;
     
-    private int _maxCachedFileSize =4*1024*1024;
+    private int _maxCachedFileSize =128*1024*1024;
     private int _maxCachedFiles=2048;
-    private int _maxCacheSize =32*1024*1024;
+    private int _maxCacheSize =256*1024*1024;
     
     /* ------------------------------------------------------------ */
     /** Constructor.
@@ -298,7 +297,7 @@ public class ResourceCache
     {
         try
         {
-            if (_useFileMappedBuffer && resource.getFile()!=null) 
+            if (_useFileMappedBuffer && resource.getFile()!=null && resource.length()<Integer.MAX_VALUE
                 return BufferUtil.toMappedBuffer(resource.getFile());
             
             return BufferUtil.toBuffer(resource,true);
@@ -505,7 +504,7 @@ public class ResourceCache
         @Override
         public String toString()
         {
-            return String.format("%s %s %d %s %s",_resource,_resource.exists(),_resource.lastModified(),_contentType,_lastModifiedBytes);
+            return String.format("CachedContent@%x{r=%s,e=%b,lm=%s,ct=%s}",hashCode(),_resource,_resource.exists(),BufferUtil.toString(_lastModifiedBytes),_contentType);
         }   
     }
 }
index 0408c8825ca4701ddb38bdf6d931c2c9ba3b482c..3f5ca27c95b5297a54c9253733f559f4b14d311e 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -112,7 +112,7 @@ public class Response implements HttpServletResponse
     private final HttpFields _fields = new HttpFields();
     private final AtomicInteger _include = new AtomicInteger();
     private HttpOutput _out;
-    private int _status = HttpStatus.NOT_SET_000;
+    private int _status = HttpStatus.OK_200;
     private String _reason;
     private Locale _locale;
     private MimeTypes.Type _mimeType;
@@ -137,7 +137,7 @@ public class Response implements HttpServletResponse
 
     protected void recycle()
     {
-        _status = HttpStatus.NOT_SET_000;
+        _status = HttpStatus.OK_200;
         _reason = null;
         _locale = null;
         _mimeType = null;
@@ -541,10 +541,7 @@ public class Response implements HttpServletResponse
     @Override
     public void sendError(int sc) throws IOException
     {
-        if (sc == 102)
-            sendProcessing();
-        else
-            sendError(sc, null);
+        sendError(sc, null);
     }
 
     @Override
@@ -553,6 +550,17 @@ public class Response implements HttpServletResponse
         if (isIncluding())
             return;
 
+        switch(code)
+        {
+            case -1:
+                _channel.abort();
+                return;
+            case 102:
+                sendProcessing();
+                return;
+            default:
+        }
+
         if (isCommitted())
             LOG.warn("Committed before "+code+" "+message);
 
@@ -594,19 +602,9 @@ public class Response implements HttpServletResponse
                 setContentType(MimeTypes.Type.TEXT_HTML_8859_1.toString());
                 try (ByteArrayISO8859Writer writer= new ByteArrayISO8859Writer(2048);)
                 {
-                    if (message != null)
-                    {
-                        message= StringUtil.replace(message, "&", "&amp;");
-                        message= StringUtil.replace(message, "<", "&lt;");
-                        message= StringUtil.replace(message, ">", "&gt;");
-                    }
+                    message=StringUtil.sanitizeXmlString(message);
                     String uri= request.getRequestURI();
-                    if (uri!=null)
-                    {
-                        uri= StringUtil.replace(uri, "&", "&amp;");
-                        uri= StringUtil.replace(uri, "<", "&lt;");
-                        uri= StringUtil.replace(uri, ">", "&gt;");
-                    }
+                    uri=StringUtil.sanitizeXmlString(uri);
 
                     writer.write("<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html;charset=ISO-8859-1\"/>\n");
                     writer.write("<title>Error ");
@@ -682,58 +680,26 @@ public class Response implements HttpServletResponse
         if (!URIUtil.hasScheme(location))
         {
             StringBuilder buf = _channel.getRequest().getRootURL();
-            if (location.startsWith("//"))
+            if (location.startsWith("/"))
             {
-                buf.delete(0, buf.length());
-                buf.append(_channel.getRequest().getScheme());
-                buf.append(":");
-                buf.append(location);
+                // absolute in context
+                location=URIUtil.canonicalPath(location);
             }
-            else if (location.startsWith("/"))
-                buf.append(location);
             else
             {
-                String path = _channel.getRequest().getRequestURI();
-                String parent = (path.endsWith("/")) ? path : URIUtil.parentPath(path);
-                location = URIUtil.addPaths(parent, location);
-                if (location == null)
-                    throw new IllegalStateException("path cannot be above root");
+                // relative to request
+                String path=_channel.getRequest().getRequestURI();
+                String parent=(path.endsWith("/"))?path:URIUtil.parentPath(path);
+                location=URIUtil.canonicalPath(URIUtil.addPaths(parent,location));
                 if (!location.startsWith("/"))
                     buf.append('/');
-                buf.append(location);
-            }
-
-            location = buf.toString();
-            HttpURI uri = new HttpURI(location);
-            String path = uri.getDecodedPath();
-            String canonical = URIUtil.canonicalPath(path);
-            if (canonical == null)
-                throw new IllegalArgumentException();
-            if (!canonical.equals(path))
-            {
-                buf = _channel.getRequest().getRootURL();
-                buf.append(URIUtil.encodePath(canonical));
-                String param=uri.getParam();
-                if (param!=null)
-                {
-                    buf.append(';');
-                    buf.append(param);
-                }
-                String query=uri.getQuery();
-                if (query!=null)
-                {
-                    buf.append('?');
-                    buf.append(query);
-                }
-                String fragment=uri.getFragment();
-                if (fragment!=null)
-                {
-                    buf.append('#');
-                    buf.append(fragment);
-                }
-                location = buf.toString();
             }
+            
+            if(location==null)
+                throw new IllegalStateException("path cannot be above root");
+            buf.append(location);
+            
+            location=buf.toString();
         }
 
         resetBuffer();
@@ -1221,10 +1187,9 @@ public class Response implements HttpServletResponse
         String connection = _channel.getRequest().getHttpFields().getStringField(HttpHeader.CONNECTION);
         if (connection != null)
         {
-            String[] values = connection.split(",");
-            for (int i = 0; values != null && i < values.length; i++)
+            for (String value: StringUtil.csvSplit(null,connection,0,connection.length()))
             {
-                HttpHeaderValue cb = HttpHeaderValue.CACHE.get(values[0].trim());
+                HttpHeaderValue cb = HttpHeaderValue.CACHE.get(value);
 
                 if (cb != null)
                 {
@@ -1290,8 +1255,6 @@ public class Response implements HttpServletResponse
 
     protected ResponseInfo newResponseInfo()
     {
-        if (_status == HttpStatus.NOT_SET_000)
-            _status = HttpStatus.OK_200;
         return new ResponseInfo(_channel.getRequest().getHttpVersion(), _fields, getLongContentLength(), getStatus(), getReason(), _channel.getRequest().isHead());
     }
 
index b017461310eecebf5bbfc64a840df72860d6d3cf..bf36446511a3277b9c1ea2db7baac161e8488a19 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -20,8 +20,10 @@ package org.eclipse.jetty.server;
 
 import java.security.cert.X509Certificate;
 
+import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLEngine;
 import javax.net.ssl.SSLSession;
+import javax.servlet.ServletRequest;
 
 import org.eclipse.jetty.http.HttpScheme;
 import org.eclipse.jetty.io.ssl.SslConnection;
@@ -31,6 +33,12 @@ import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.util.ssl.SslContextFactory;
 
+
+/* ------------------------------------------------------------ */
+/** Customizer that extracts the attribute from an {@link SSLContext}
+ * and sets them on the request with {@link ServletRequest#setAttribute(String, Object)}
+ * according to Servlet Specification Requirements.
+ */
 public class SecureRequestCustomizer implements HttpConfiguration.Customizer
 {
     private static final Logger LOG = Log.getLogger(SecureRequestCustomizer.class);
@@ -40,6 +48,7 @@ public class SecureRequestCustomizer implements HttpConfiguration.Customizer
      */
     public static final String CACHED_INFO_ATTR = CachedInfo.class.getName();
 
+    private String sslSessionAttribute = "org.eclipse.jetty.servlet.request.ssl_session";
 
     @Override
     public void customize(Connector connector, HttpConfiguration channelConfig, Request request)
@@ -53,14 +62,11 @@ public class SecureRequestCustomizer implements HttpConfiguration.Customizer
             SSLEngine sslEngine=sslConnection.getSSLEngine();
             customize(sslEngine,request);
         }
-
     }
 
     /* ------------------------------------------------------------ */
     /*
-     * Allow the Listener a chance to customise the request. before the server
-     * does its stuff. <br>
-     * This allows the required attributes to be set for SSL requests. <br>
+     * Customise the request attributes to be set for SSL requests. <br>
      * The requirements of the Servlet specs are:
      * <ul>
      * <li> an attribute named "javax.servlet.request.ssl_session_id" of type
@@ -114,12 +120,23 @@ public class SecureRequestCustomizer implements HttpConfiguration.Customizer
             request.setAttribute("javax.servlet.request.cipher_suite",cipherSuite);
             request.setAttribute("javax.servlet.request.key_size",keySize);
             request.setAttribute("javax.servlet.request.ssl_session_id", idStr);
+            request.setAttribute(getSslSessionAttribute(), sslSession);
         }
         catch (Exception e)
         {
             LOG.warn(Log.EXCEPTION,e);
         }
     }
+    
+    public void setSslSessionAttribute(String attribute)
+    {
+        this.sslSessionAttribute = attribute;
+    }
+
+    public String getSslSessionAttribute()
+    {
+        return sslSessionAttribute;
+    }
 
     @Override
     public String toString()
index b1437d6d98db29451bc23caa67fa80a8d7c4baa7..ba0655e5ef8782839f6dc644f3f24107c8a0ca2a 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -19,7 +19,6 @@
 package org.eclipse.jetty.server;
 
 import java.io.IOException;
-import java.lang.management.ManagementFactory;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.URI;
@@ -32,6 +31,7 @@ import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
+
 import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
@@ -46,11 +46,13 @@ import org.eclipse.jetty.http.HttpStatus;
 import org.eclipse.jetty.http.HttpURI;
 import org.eclipse.jetty.server.handler.ContextHandler;
 import org.eclipse.jetty.server.handler.HandlerWrapper;
+import org.eclipse.jetty.server.handler.StatisticsHandler;
 import org.eclipse.jetty.util.Attributes;
 import org.eclipse.jetty.util.AttributesMap;
 import org.eclipse.jetty.util.Jetty;
 import org.eclipse.jetty.util.MultiException;
 import org.eclipse.jetty.util.URIUtil;
+import org.eclipse.jetty.util.Uptime;
 import org.eclipse.jetty.util.annotation.ManagedAttribute;
 import org.eclipse.jetty.util.annotation.ManagedObject;
 import org.eclipse.jetty.util.annotation.Name;
@@ -141,8 +143,28 @@ public class Server extends HandlerWrapper implements Attributes
     {
         return _stopAtShutdown;
     }
+   
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * Set a graceful stop time.
+     * The {@link StatisticsHandler} must be configured so that open connections can
+     * be tracked for a graceful shutdown.
+     * @see org.eclipse.jetty.util.component.ContainerLifeCycle#setStopTimeout(long)
+     */
+    @Override
+    public void setStopTimeout(long stopTimeout)
+    {
+        super.setStopTimeout(stopTimeout);
+    }
 
     /* ------------------------------------------------------------ */
+    /** Set stop server at shutdown behaviour.
+     * @param stop If true, this server instance will be explicitly stopped when the
+     * JVM is shutdown. Otherwise the JVM is stopped with the server running.
+     * @see Runtime#addShutdownHook(Thread)
+     * @see ShutdownThread
+     */
     public void setStopAtShutdown(boolean stop)
     {
         //if we now want to stop
@@ -290,11 +312,16 @@ public class Server extends HandlerWrapper implements Attributes
     @Override
     protected void doStart() throws Exception
     {
+        //If the Server should be stopped when the jvm exits, register
+        //with the shutdown handler thread.
         if (getStopAtShutdown())
-        {
             ShutdownThread.register(this);
-        }
 
+        //Register the Server with the handler thread for receiving
+        //remote stop commands
+        ShutdownMonitor.register(this);
+        
+        //Start a thread waiting to receive "stop" commands.
         ShutdownMonitor.getInstance().start(); // initialize
 
         LOG.info("jetty-" + getVersion());
@@ -304,20 +331,23 @@ public class Server extends HandlerWrapper implements Attributes
         // check size of thread pool
         SizedThreadPool pool = getBean(SizedThreadPool.class);
         int max=pool==null?-1:pool.getMaxThreads();
-        int needed=1;
+        int selectors=0;
+        int acceptors=0;
         if (mex.size()==0)
         {
             for (Connector connector : _connectors)
             {
                 if (connector instanceof AbstractConnector)
-                    needed+=((AbstractConnector)connector).getAcceptors();
+                    acceptors+=((AbstractConnector)connector).getAcceptors();
+                    
                 if (connector instanceof ServerConnector)
-                    needed+=((ServerConnector)connector).getSelectorManager().getSelectorCount();
+                    selectors+=((ServerConnector)connector).getSelectorManager().getSelectorCount();
             }
         }
 
+        int needed=1+selectors+acceptors;
         if (max>0 && needed>max)
-            throw new IllegalStateException("Insufficient max threads in ThreadPool: max="+max+" < needed="+needed);
+            throw new IllegalStateException(String.format("Insufficient threads: max=%d < needed(acceptors=%d + selectors=%d + request=1)",max,acceptors,selectors));
         
         try
         {
@@ -346,7 +376,7 @@ public class Server extends HandlerWrapper implements Attributes
 
         mex.ifExceptionThrow();
 
-        LOG.info(String.format("Started @%dms",ManagementFactory.getRuntimeMXBean().getUptime()));
+        LOG.info(String.format("Started @%dms",Uptime.getUptime()));
     }
 
     @Override
@@ -384,7 +414,8 @@ public class Server extends HandlerWrapper implements Attributes
         if (stopTimeout>0)
         {
             long stop_by=System.currentTimeMillis()+stopTimeout;
-            LOG.debug("Graceful shutdown {} by ",this,new Date(stop_by));
+            if (LOG.isDebugEnabled())
+                LOG.debug("Graceful shutdown {} by ",this,new Date(stop_by));
 
             // Wait for shutdowns
             for (Future<Void> future: futures)
@@ -396,7 +427,7 @@ public class Server extends HandlerWrapper implements Attributes
                 }
                 catch (Exception e)
                 {
-                    mex.add(e.getCause());
+                    mex.add(e);
                 }
             }
         }
@@ -431,6 +462,11 @@ public class Server extends HandlerWrapper implements Attributes
 
         if (getStopAtShutdown())
             ShutdownThread.deregister(this);
+        
+        //Unregister the Server with the handler thread for receiving
+        //remote stop commands as we are stopped already
+        ShutdownMonitor.deregister(this);
+        
 
         mex.ifExceptionThrow();
 
@@ -449,10 +485,12 @@ public class Server extends HandlerWrapper implements Attributes
         final Response response=connection.getResponse();
 
         if (LOG.isDebugEnabled())
-            LOG.debug(request.getDispatcherType()+" "+target+" on "+connection);
+            LOG.debug(request.getDispatcherType()+" "+request.getMethod()+" "+target+" on "+connection);
 
-        if ("*".equals(target))
+        if (HttpMethod.OPTIONS.is(request.getMethod()) || "*".equals(target))
         {
+            if (!HttpMethod.OPTIONS.is(request.getMethod()))
+                response.sendError(HttpStatus.BAD_REQUEST_400);
             handleOptions(request,response);
             if (!request.isHandled())
                 handle(target, request, request, response);
@@ -469,13 +507,6 @@ public class Server extends HandlerWrapper implements Attributes
      */
     protected void handleOptions(Request request,Response response) throws IOException
     {
-        if (!HttpMethod.OPTIONS.is(request.getMethod()))
-            response.sendError(HttpStatus.BAD_REQUEST_400);
-        request.setHandled(true);
-        response.setStatus(200);
-        response.getHttpFields().put(HttpHeader.ALLOW,"GET,POST,HEAD,OPTIONS");
-        response.setContentLength(0);
-        response.closeOutput();
     }
 
     /* ------------------------------------------------------------ */
@@ -491,15 +522,15 @@ public class Server extends HandlerWrapper implements Attributes
 
         final Request baseRequest=connection.getRequest();
         final String path=event.getPath();
-
+        
         if (path!=null)
         {
             // this is a dispatch with a path
             ServletContext context=event.getServletContext();
-            HttpURI uri = new HttpURI(context==null?path:URIUtil.addPaths(context.getContextPath(),path));
+            HttpURI uri = new HttpURI(URIUtil.addPaths(context==null?null:context.getContextPath(), path));            
             baseRequest.setUri(uri);
             baseRequest.setRequestURI(null);
-            baseRequest.setPathInfo(baseRequest.getRequestURI());
+            baseRequest.setPathInfo(uri.getDecodedPath());
             if (uri.getQuery()!=null)
                 baseRequest.mergeQueryParameters(uri.getQuery(), true); //we have to assume dispatch path and query are UTF8
         }
@@ -510,7 +541,7 @@ public class Server extends HandlerWrapper implements Attributes
 
         if (LOG.isDebugEnabled())
         {
-            LOG.debug(request.getDispatcherType()+" "+target+" on "+connection);
+            LOG.debug(request.getDispatcherType()+" "+request.getMethod()+" "+target+" on "+connection);
             handle(target, baseRequest, request, response);
             LOG.debug("RESPONSE "+target+"  "+connection.getResponse().getStatus());
         }
@@ -605,6 +636,7 @@ public class Server extends HandlerWrapper implements Attributes
     /**
      * @return The URI of the first {@link NetworkConnector} and first {@link ContextHandler}, or null
      */
+    @SuppressWarnings("resource")
     public URI getURI()
     {
         NetworkConnector connector=null;
@@ -651,6 +683,7 @@ public class Server extends HandlerWrapper implements Attributes
         return this.getClass().getName()+"@"+Integer.toHexString(hashCode());
     }
 
+    /* ------------------------------------------------------------ */
     @Override
     public void dump(Appendable out,String indent) throws IOException
     {
index a7d5fe0f2d8ee32579f393d22de736f29a6ea11c..2766a89f1bf988732b401628438d172474995f19 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -20,12 +20,10 @@ package org.eclipse.jetty.server;
 
 import java.io.IOException;
 import java.net.InetSocketAddress;
-import java.net.ServerSocket;
 import java.net.Socket;
 import java.net.SocketException;
 import java.nio.channels.Channel;
 import java.nio.channels.SelectionKey;
-import java.nio.channels.Selector;
 import java.nio.channels.ServerSocketChannel;
 import java.nio.channels.SocketChannel;
 import java.util.concurrent.Executor;
@@ -37,7 +35,6 @@ import org.eclipse.jetty.io.EndPoint;
 import org.eclipse.jetty.io.SelectChannelEndPoint;
 import org.eclipse.jetty.io.SelectorManager;
 import org.eclipse.jetty.io.SelectorManager.ManagedSelector;
-import org.eclipse.jetty.util.Callback;
 import org.eclipse.jetty.util.annotation.ManagedAttribute;
 import org.eclipse.jetty.util.annotation.ManagedObject;
 import org.eclipse.jetty.util.annotation.Name;
@@ -107,7 +104,7 @@ public class ServerConnector extends AbstractNetworkConnector
      *          the number of acceptor threads to use, or -1 for a default value. Acceptors accept new TCP/IP connections.  If 0, then 
      *          the selector threads are used to accept connections.
      * @param selectors
-     *          the number of selector threads, or -1 for a default value. Selectors notice and schedule established connection that can make IO progress.
+     *          the number of selector threads, or <=0 for a default value. Selectors notice and schedule established connection that can make IO progress.
      */
     public ServerConnector(
         @Name("server") Server server,
@@ -116,6 +113,26 @@ public class ServerConnector extends AbstractNetworkConnector
     {
         this(server,null,null,null,acceptors,selectors,new HttpConnectionFactory());
     }
+    
+    /* ------------------------------------------------------------ */
+    /** HTTP Server Connection.
+     * <p>Construct a ServerConnector with a private instance of {@link HttpConnectionFactory} as the only factory.</p>
+     * @param server The {@link Server} this connector will accept connection for. 
+     * @param acceptors 
+     *          the number of acceptor threads to use, or -1 for a default value. Acceptors accept new TCP/IP connections.  If 0, then 
+     *          the selector threads are used to accept connections.
+     * @param selectors
+     *          the number of selector threads, or <=0 for a default value. Selectors notice and schedule established connection that can make IO progress.
+     * @param factories Zero or more {@link ConnectionFactory} instances used to create and configure connections.
+     */
+    public ServerConnector(
+        @Name("server") Server server,
+        @Name("acceptors") int acceptors,
+        @Name("selectors") int selectors,
+        @Name("factories") ConnectionFactory... factories)
+    {
+        this(server,null,null,null,acceptors,selectors,factories);
+    }
 
     /* ------------------------------------------------------------ */
     /** Generic Server Connection with default configuration.
@@ -154,7 +171,7 @@ public class ServerConnector extends AbstractNetworkConnector
      *          the number of acceptor threads to use, or -1 for a default value. Acceptors accept new TCP/IP connections.  If 0, then 
      *          the selector threads are used to accept connections.
      * @param selectors
-     *          the number of selector threads, or -1 for a default value. Selectors notice and schedule established connection that can make IO progress.
+     *          the number of selector threads, or <=0 for a default value. Selectors notice and schedule established connection that can make IO progress.
      */
     public ServerConnector(
         @Name("server") Server server,
@@ -184,7 +201,7 @@ public class ServerConnector extends AbstractNetworkConnector
      * @param server    
      *          The server this connector will be accept connection for.  
      * @param executor  
-     *          An executor used to run tasks for handling requests, acceptors and selectors. I
+     *          An executor used to run tasks for handling requests, acceptors and selectors.
      *          If null then use the servers executor
      * @param scheduler 
      *          A scheduler used to schedule timeouts. If null then use the servers scheduler
@@ -194,7 +211,7 @@ public class ServerConnector extends AbstractNetworkConnector
      *          the number of acceptor threads to use, or -1 for a default value. Acceptors accept new TCP/IP connections.  If 0, then 
      *          the selector threads are used to accept connections.
      * @param selectors
-     *          the number of selector threads, or -1 for a default value. Selectors notice and schedule established connection that can make IO progress.
+     *          the number of selector threads, or <=0 for a default value. Selectors notice and schedule established connection that can make IO progress.
      * @param factories 
      *          Zero or more {@link ConnectionFactory} instances used to create and configure connections.
      */
@@ -208,7 +225,8 @@ public class ServerConnector extends AbstractNetworkConnector
         @Name("factories") ConnectionFactory... factories)
     {
         super(server,executor,scheduler,bufferPool,acceptors,factories);
-        _manager = new ServerConnectorManager(getExecutor(), getScheduler(), selectors > 0 ? selectors : Runtime.getRuntime().availableProcessors());
+        _manager = new ServerConnectorManager(getExecutor(), getScheduler(), 
+            selectors>0?selectors:Math.max(1,Math.min(4,Runtime.getRuntime().availableProcessors()/2)));
         addBean(_manager, true);
     }
 
@@ -231,6 +249,29 @@ public class ServerConnector extends AbstractNetworkConnector
         return channel!=null && channel.isOpen();
     }
 
+
+    @ManagedAttribute("The priority delta to apply to selector threads")
+    public int getSelectorPriorityDelta()
+    {
+        return _manager.getSelectorPriorityDelta();
+    }
+
+    /**
+     * Sets the selector thread priority delta to the given amount.
+     * <p>This allows the selector threads to run at a different priority.
+     * Typically this would be used to lower the priority to give preference 
+     * to handling previously accepted connections rather than accepting
+     * new connections.</p>
+     *
+     * @param selectorPriorityDelta the amount to set the thread priority delta to
+     *                              (may be negative)
+     * @see Thread#getPriority()
+     */
+    public void setSelectorPriorityDelta(int selectorPriorityDelta)
+    {
+        _manager.setSelectorPriorityDelta(selectorPriorityDelta);
+    }
+    
     /**
      * @return whether this connector uses a channel inherited from the JVM.
      * @see System#inheritedChannel()
@@ -276,8 +317,8 @@ public class ServerConnector extends AbstractNetworkConnector
                 serverChannel = ServerSocketChannel.open();
 
                 InetSocketAddress bindAddress = getHost() == null ? new InetSocketAddress(getPort()) : new InetSocketAddress(getHost(), getPort());
-                serverChannel.socket().bind(bindAddress, getAcceptQueueSize());
                 serverChannel.socket().setReuseAddress(getReuseAddress());
+                serverChannel.socket().bind(bindAddress, getAcceptQueueSize());
 
                 _localPort = serverChannel.socket().getLocalPort();
                 if (_localPort <= 0)
index 11f249e139d20ff8f4b430d68808920f524d6a84..e0d5a6fa2592e6a07074b1554e47074d4c7949ac 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -48,126 +48,151 @@ public class ServletRequestHttpWrapper extends ServletRequestWrapper implements
         super(request);
     }
 
+    @Override
     public String getAuthType()
     {
         return null;
     }
 
+    @Override
     public Cookie[] getCookies()
     {
         return null;
     }
 
+    @Override
     public long getDateHeader(String name)
     {
         return 0;
     }
 
+    @Override
     public String getHeader(String name)
     {
         return null;
     }
 
-    public Enumeration getHeaders(String name)
+    @Override
+    public Enumeration<String> getHeaders(String name)
     {
         return null;
     }
 
-    public Enumeration getHeaderNames()
+    @Override
+    public Enumeration<String> getHeaderNames()
     {
         return null;
     }
 
+    @Override
     public int getIntHeader(String name)
     {
         return 0;
     }
 
+    @Override
     public String getMethod()
     {
         return null;
     }
 
+    @Override
     public String getPathInfo()
     {
         return null;
     }
 
+    @Override
     public String getPathTranslated()
     {
         return null;
     }
 
+    @Override
     public String getContextPath()
     {
         return null;
     }
 
+    @Override
     public String getQueryString()
     {
         return null;
     }
 
+    @Override
     public String getRemoteUser()
     {
         return null;
     }
 
+    @Override
     public boolean isUserInRole(String role)
     {
         return false;
     }
 
+    @Override
     public Principal getUserPrincipal()
     {
         return null;
     }
 
+    @Override
     public String getRequestedSessionId()
     {
         return null;
     }
 
+    @Override
     public String getRequestURI()
     {
         return null;
     }
 
+    @Override
     public StringBuffer getRequestURL()
     {
         return null;
     }
 
+    @Override
     public String getServletPath()
     {
         return null;
     }
 
+    @Override
     public HttpSession getSession(boolean create)
     {
         return null;
     }
 
+    @Override
     public HttpSession getSession()
     {
         return null;
     }
 
+    @Override
     public boolean isRequestedSessionIdValid()
     {
         return false;
     }
 
+    @Override
     public boolean isRequestedSessionIdFromCookie()
     {
         return false;
     }
 
+    @Override
     public boolean isRequestedSessionIdFromURL()
     {
         return false;
     }
 
+    @Override
     public boolean isRequestedSessionIdFromUrl()
     {
         return false;
@@ -176,6 +201,7 @@ public class ServletRequestHttpWrapper extends ServletRequestWrapper implements
     /**
      * @see javax.servlet.http.HttpServletRequest#authenticate(javax.servlet.http.HttpServletResponse)
      */
+    @Override
     public boolean authenticate(HttpServletResponse response) throws IOException, ServletException
     {
         return false;
@@ -184,6 +210,7 @@ public class ServletRequestHttpWrapper extends ServletRequestWrapper implements
     /**
      * @see javax.servlet.http.HttpServletRequest#getPart(java.lang.String)
      */
+    @Override
     public Part getPart(String name) throws IOException, ServletException
     {
         return null;
@@ -192,6 +219,7 @@ public class ServletRequestHttpWrapper extends ServletRequestWrapper implements
     /**
      * @see javax.servlet.http.HttpServletRequest#getParts()
      */
+    @Override
     public Collection<Part> getParts() throws IOException, ServletException
     {
         return null;
@@ -200,6 +228,7 @@ public class ServletRequestHttpWrapper extends ServletRequestWrapper implements
     /**
      * @see javax.servlet.http.HttpServletRequest#login(java.lang.String, java.lang.String)
      */
+    @Override
     public void login(String username, String password) throws ServletException
     {
 
@@ -208,6 +237,7 @@ public class ServletRequestHttpWrapper extends ServletRequestWrapper implements
     /**
      * @see javax.servlet.http.HttpServletRequest#logout()
      */
+    @Override
     public void logout() throws ServletException
     {
 
index 076ab1b2f43d8bbb06975e3ab69309434db1a356..39c7711687569dbd6d53264252234a21a21db9ad 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index ef7ee6233802baf7f215332f869a2b6f310b5568..13e6c80b35308d2414169da246b4e4165275315b 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 267391b56dafa29ee40474a55f3a0b52e4a40d95..d7f7f33274ac8af8ca843384c4e68811e7ba8cfd 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -23,7 +23,6 @@ import java.util.Set;
 
 import javax.servlet.SessionCookieConfig;
 import javax.servlet.SessionTrackingMode;
-import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
 
index abc6d61ef87dc87b1f690012ceb09a853cb7173d..d49b28882c74d4c4089eaeded7101c7135a8eb6f 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -23,18 +23,24 @@ import java.io.InputStreamReader;
 import java.io.LineNumberReader;
 import java.io.OutputStream;
 import java.net.InetAddress;
+import java.net.InetSocketAddress;
 import java.net.ServerSocket;
 import java.net.Socket;
 import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
 import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
 
+import org.eclipse.jetty.util.component.Destroyable;
+import org.eclipse.jetty.util.component.LifeCycle;
 import org.eclipse.jetty.util.thread.ShutdownThread;
 
 /**
  * Shutdown/Stop Monitor thread.
  * <p>
- * This thread listens on the port specified by the STOP.PORT system parameter (defaults to -1 for not listening) for request authenticated with the key given
- * by the STOP.KEY system parameter (defaults to "eclipse") for admin requests.
+ * This thread listens on the host/port specified by the STOP.HOST/STOP.PORT system parameter (defaults to 127.0.0.1/-1 for not listening) for 
+ * request authenticated with the key given by the STOP.KEY system parameter (defaults to "eclipse") for admin requests.
  * <p>
  * If the stop port is set to zero, then a random port is assigned and the port number is printed to stdout.
  * <p>
@@ -42,6 +48,8 @@ import org.eclipse.jetty.util.thread.ShutdownThread;
  */
 public class ShutdownMonitor 
 {
+    private final Set<LifeCycle> _lifeCycles = new CopyOnWriteArraySet<LifeCycle>();
+    
     // Implementation of safe lazy init, using Initialization on Demand Holder technique.
     static class Holder
     {
@@ -52,22 +60,40 @@ public class ShutdownMonitor
     {
         return Holder.instance;
     }
+    
+    /* ------------------------------------------------------------ */
+    public static synchronized void register(LifeCycle... lifeCycles)
+    {
+        getInstance()._lifeCycles.addAll(Arrays.asList(lifeCycles));
+    }
 
+   
+    /* ------------------------------------------------------------ */
+    public static synchronized void deregister(LifeCycle lifeCycle)
+    {
+        getInstance()._lifeCycles.remove(lifeCycle);
+    }
+    
+    /* ------------------------------------------------------------ */
+    public static synchronized boolean isRegistered(LifeCycle lifeCycle)
+    {
+        return getInstance()._lifeCycles.contains(lifeCycle);
+    }
+    
+    /* ------------------------------------------------------------ */
     /**
-     * ShutdownMonitorThread
+     * ShutdownMonitorRunnable
      *
      * Thread for listening to STOP.PORT for command to stop Jetty.
      * If ShowndownMonitor.exitVm is true, then Sytem.exit will also be
      * called after the stop.
      *
      */
-    public class ShutdownMonitorThread extends Thread
+    private class ShutdownMonitorRunnable implements Runnable
     {
-
-        public ShutdownMonitorThread ()
+        public ShutdownMonitorRunnable()
         {
-            setDaemon(true);
-            setName("ShutdownMonitor");
+            startListenSocket();
         }
         
         @Override
@@ -97,29 +123,38 @@ public class ShutdownMonitor
 
                     String cmd = lin.readLine();
                     debug("command=%s",cmd);
-                    if ("stop".equals(cmd))
+                    if ("stop".equalsIgnoreCase(cmd)) //historic, for backward compatibility
                     {
-                        // Graceful Shutdown
-                        debug("Issuing graceful shutdown..");
-                        ShutdownThread.getInstance().run();
-                        
-                        //Stop accepting any more
-                        close(serverSocket);
-                        serverSocket = null;
+                        //Stop the lifecycles, only if they are registered with the ShutdownThread, only destroying if vm is exiting
+                        debug("Issuing stop...");
                         
-                        //Shutdown input from client
-                        shutdownInput(socket);
+                        for (LifeCycle l:_lifeCycles)
+                        {
+                            try
+                            {
+                                if (l.isStarted() && ShutdownThread.isRegistered(l))
+                                {
+                                    l.stop();
+                                }
+                                
+                                if ((l instanceof Destroyable) && exitVm)
+                                    ((Destroyable)l).destroy();
+                            }
+                            catch (Exception e)
+                            {
+                                debug(e);
+                            }
+                        }
+
+                        //Stop accepting any more commands
+                        stopInput(socket);
 
                         // Reply to client
                         debug("Informing client that we are stopped.");
-                        out.write("Stopped\r\n".getBytes(StandardCharsets.UTF_8));
-                        out.flush();
+                        informClient(out, "Stopped\r\n");
 
-                        // Shutdown Monitor
-                        socket.shutdownOutput();
-                        close(socket);
-                        socket = null;                        
-                        debug("Shutting down monitor");
+                        //Stop the output and close the monitor socket
+                        stopOutput(socket);
 
                         if (exitVm)
                         {
@@ -128,11 +163,59 @@ public class ShutdownMonitor
                             System.exit(0);
                         }
                     }
-                    else if ("status".equals(cmd))
+                    else if ("forcestop".equalsIgnoreCase(cmd))
                     {
+                        debug("Issuing force stop...");
+                        
+                        //Ensure that objects are stopped, destroyed only if vm is forcibly exiting
+                        stopLifeCycles(exitVm);
+
+                        //Stop accepting any more commands
+                        stopInput(socket);
+
                         // Reply to client
-                        out.write("OK\r\n".getBytes(StandardCharsets.UTF_8));
-                        out.flush();
+                        debug("Informing client that we are stopped.");
+                        informClient(out, "Stopped\r\n");
+
+                        //Stop the output and close the monitor socket
+                        stopOutput(socket);
+                        
+                        //Honour any pre-setup config to stop the jvm when this command is given
+                        if (exitVm)
+                        {
+                            // Kill JVM
+                            debug("Killing JVM");
+                            System.exit(0);
+                        }
+                    }
+                    else if ("stopexit".equalsIgnoreCase(cmd))
+                    {
+                        debug("Issuing stop and exit...");
+                        //Make sure that objects registered with the shutdown thread will be stopped
+                        stopLifeCycles(true);
+                        
+                        //Stop accepting any more input
+                        stopInput(socket);
+
+                        // Reply to client
+                        debug("Informing client that we are stopped.");                       
+                        informClient(out, "Stopped\r\n");              
+
+                        //Stop the output and close the monitor socket
+                        stopOutput(socket);
+                        
+                        debug("Killing JVM");
+                        System.exit(0);
+                    }
+                    else if ("exit".equalsIgnoreCase(cmd))
+                    {
+                        debug("Killing JVM");
+                        System.exit(0);
+                    }
+                    else if ("status".equalsIgnoreCase(cmd))
+                    {
+                        // Reply to client
+                        informClient(out, "OK\r\n");
                     }
                 }
                 catch (Exception e)
@@ -148,28 +231,58 @@ public class ShutdownMonitor
             }
         }
         
-        public void start()
+        public void stopInput (Socket socket)
         {
-            if (isAlive())
-            {
-                // TODO why are we reentrant here?
-                if (DEBUG)
-                    System.err.printf("ShutdownMonitorThread already started");
-                return; // cannot start it again
-            }
+            //Stop accepting any more input
+            close(serverSocket);
+            serverSocket = null;
+            //Shutdown input from client
+            shutdownInput(socket);  
+        }
+        
+        public void stopOutput (Socket socket) throws IOException
+        {
+            socket.shutdownOutput();
+            close(socket);
+            socket = null;                        
+            debug("Shutting down monitor");
+            serverSocket = null;
+        }
+        
+        public void informClient (OutputStream out, String message) throws IOException
+        {
+            out.write(message.getBytes(StandardCharsets.UTF_8));
+            out.flush();
+        }
 
-            startListenSocket();
-            
-            if (serverSocket == null)
+        /**
+         * Stop the registered lifecycles, optionally
+         * calling destroy on them.
+         * 
+         * @param destroy
+         */
+        public void stopLifeCycles (boolean destroy)
+        {
+            for (LifeCycle l:_lifeCycles)
             {
-                return;
+                try
+                {
+                    if (l.isStarted())
+                    {
+                        l.stop();
+                    }
+                    
+                    if ((l instanceof Destroyable) && destroy)
+                        ((Destroyable)l).destroy();
+                }
+                catch (Exception e)
+                {
+                    debug(e);
+                }
             }
-            if (DEBUG)
-                System.err.println("Starting ShutdownMonitorThread");
-            super.start();
         }
-        
-        private void startListenSocket()
+
+        public void startListenSocket()
         {
             if (port < 0)
             {            
@@ -180,7 +293,9 @@ public class ShutdownMonitor
 
             try
             {
-                serverSocket = new ServerSocket(port,1,InetAddress.getByName("127.0.0.1"));
+                serverSocket = new ServerSocket();
+                serverSocket.setReuseAddress(true);
+                serverSocket.bind(new InetSocketAddress(InetAddress.getByName(host), port), 1);
                 if (port == 0)
                 {
                     // server assigned port in use
@@ -213,13 +328,12 @@ public class ShutdownMonitor
     }
     
     private boolean DEBUG;
+    private String host;
     private int port;
     private String key;
     private boolean exitVm;
     private ServerSocket serverSocket;
-    private ShutdownMonitorThread thread;
-    
-    
+    private Thread thread;
 
     /**
      * Create a ShutdownMonitor using configuration from the System properties.
@@ -231,13 +345,12 @@ public class ShutdownMonitor
      */
     private ShutdownMonitor()
     {
-        Properties props = System.getProperties();
-
-        this.DEBUG = props.containsKey("DEBUG");
+        this.DEBUG = System.getProperty("DEBUG") != null;
 
         // Use values passed thru via /jetty-start/
-        this.port = Integer.parseInt(props.getProperty("STOP.PORT","-1"));
-        this.key = props.getProperty("STOP.KEY",null);
+        this.host = System.getProperty("STOP.HOST","127.0.0.1");
+        this.port = Integer.parseInt(System.getProperty("STOP.PORT","-1"));
+        this.key = System.getProperty("STOP.KEY",null);
         this.exitVm = true;
     }
 
@@ -334,6 +447,9 @@ public class ShutdownMonitor
         this.DEBUG = flag;
     }
 
+    /**
+     * @param exitVm
+     */
     public void setExitVm(boolean exitVm)
     {
         synchronized (this)
@@ -372,18 +488,20 @@ public class ShutdownMonitor
 
     protected void start() throws Exception
     {
-        ShutdownMonitorThread t = null;
+        Thread t = null;
+        
         synchronized (this)
         {
             if (thread != null && thread.isAlive())
             {
-                // TODO why are we reentrant here?
                 if (DEBUG)
                     System.err.printf("ShutdownMonitorThread already started");
                 return; // cannot start it again
             }
          
-            thread = new ShutdownMonitorThread();
+            thread = new Thread(new ShutdownMonitorRunnable());
+            thread.setDaemon(true);
+            thread.setName("ShutdownMonitor");
             t = thread;
         }
          
index 5fcc1038da68ad0b9b25f33094b9320f13f05ea6..eafa594a069d614457618ea59d378c37fc7b0394 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 4e20331dc7dc1d50e4736558be7ce8a80313ec66..3b67f2c7bc4161b21e8ed7965cc414b803a69648 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index cbd1adb91aa3061e53d4223710f133e14fc982c8..2ff311901c23baa413d8206fef4a2a9e306a9b50 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 3d92512ca2b2ec249cfa53e4593cb9284059392c..107f5c98df0242a5a5e00e842f0328a6c619e139 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -54,7 +54,8 @@ public abstract class AbstractHandler extends ContainerLifeCycle implements Hand
     @Override
     protected void doStart() throws Exception
     {
-        LOG.debug("starting {}",this);
+        if (LOG.isDebugEnabled())
+            LOG.debug("starting {}",this);
         if (_server==null)
             LOG.warn("No Server set for {}",this);
         super.doStart();
@@ -67,7 +68,8 @@ public abstract class AbstractHandler extends ContainerLifeCycle implements Hand
     @Override
     protected void doStop() throws Exception
     {
-        LOG.debug("stopping {}",this);
+        if (LOG.isDebugEnabled())
+            LOG.debug("stopping {}",this);
         super.doStop();
     }
 
index 0d54e536fb307ef19265fb1b6e2147ea97b352f5..1cb75387851008f03f52c0aba1b530b71287cfc1 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -58,6 +58,7 @@ public abstract class AbstractHandlerContainer extends AbstractHandler implement
     }
 
     /* ------------------------------------------------------------ */
+    @SuppressWarnings("unchecked")
     @Override
     public <T extends Handler> T getChildHandlerByClass(Class<T> byclass)
     {
@@ -103,6 +104,7 @@ public abstract class AbstractHandlerContainer extends AbstractHandler implement
         {
             for (Handler h:branches)
             {
+                @SuppressWarnings("unchecked")
                 T container = (T)h;
                 Handler[] candidates = container.getChildHandlersByClass(handler.getClass());
                 if (candidates!=null)
index c3d8b5932d16665e70c8011c55b0da1c54750946..0df51cb8babb14aa6575f13d504486e89bb1f53d 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -56,7 +56,8 @@ public class AllowSymLinkAliasChecker implements AliasCheck
                 URI real = file.toPath().toRealPath().toUri();
                 if (real.equals(resource.getAlias()))
                 {
-                    LOG.debug("Allow symlink {} --> {}",resource,real);
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Allow symlink {} --> {}",resource,real);
                     return true;
                 }
             }
@@ -79,7 +80,8 @@ public class AllowSymLinkAliasChecker implements AliasCheck
                 }
                 if (resource.getAlias().equals(d.toURI()))
                 {
-                    LOG.debug("Allow symlink {} --> {}",resource,d);
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Allow symlink {} --> {}",resource,d);
                     return true;
                 }
             }
diff --git a/lib/jetty/org/eclipse/jetty/server/handler/AsyncDelayHandler.java b/lib/jetty/org/eclipse/jetty/server/handler/AsyncDelayHandler.java
new file mode 100644 (file)
index 0000000..9fd87d3
--- /dev/null
@@ -0,0 +1,153 @@
+//
+//  ========================================================================
+//  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 javax.servlet.AsyncContext;
+import javax.servlet.DispatcherType;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.server.Request;
+
+
+/* ------------------------------------------------------------ */
+/** A handler wrapper that provides the framework to asynchronously
+ * delay the handling of a request.  While it uses standard servlet 
+ * API for asynchronous servlets, it adjusts the dispatch type of the 
+ * request so that it does not appear to be asynchronous during the
+ * delayed dispatch.
+ * 
+ */
+public class AsyncDelayHandler extends HandlerWrapper
+{
+    public final static String AHW_ATTR = "o.e.j.s.h.AsyncHandlerWrapper";
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+    {
+        if (!isStarted() || _handler==null)
+            return;
+        
+        // Get the dispatcher types
+        DispatcherType ctype = baseRequest.getDispatcherType();
+        DispatcherType dtype = (DispatcherType)baseRequest.getAttribute(AHW_ATTR);
+        Object async_context_path=null;
+        Object async_path_info=null;
+        Object async_query_string=null;
+        Object async_request_uri=null;
+        Object async_servlet_path=null;
+        
+        // Is this request a restarted one?
+        boolean restart=false;
+        if (dtype!=null)
+        {
+            // fake the dispatch type to the original
+            baseRequest.setAttribute(AHW_ATTR,null);
+            baseRequest.setDispatcherType(dtype);
+            restart=true;
+            
+            async_context_path=baseRequest.getAttribute(AsyncContext.ASYNC_CONTEXT_PATH);
+            baseRequest.setAttribute(AsyncContext.ASYNC_CONTEXT_PATH,null);
+            async_path_info=baseRequest.getAttribute(AsyncContext.ASYNC_PATH_INFO);
+            baseRequest.setAttribute(AsyncContext.ASYNC_PATH_INFO,null);
+            async_query_string=baseRequest.getAttribute(AsyncContext.ASYNC_QUERY_STRING);
+            baseRequest.setAttribute(AsyncContext.ASYNC_QUERY_STRING,null);
+            async_request_uri=baseRequest.getAttribute(AsyncContext.ASYNC_REQUEST_URI);
+            baseRequest.setAttribute(AsyncContext.ASYNC_REQUEST_URI,null);
+            async_servlet_path=baseRequest.getAttribute(AsyncContext.ASYNC_SERVLET_PATH);
+            baseRequest.setAttribute(AsyncContext.ASYNC_SERVLET_PATH,null);
+        }
+        
+        // Should we handle this request now?
+        if (!startHandling(baseRequest,restart))
+        {
+            // No, so go async and remember dispatch type
+            AsyncContext context = baseRequest.startAsync();
+            baseRequest.setAttribute(AHW_ATTR,ctype);
+
+            delayHandling(baseRequest, context);
+            return;
+        }
+
+        // Handle the request
+        try
+        {
+            _handler.handle(target,baseRequest, request, response);
+        }
+        finally
+        {
+            if(restart)
+            {
+                // reset the request
+                baseRequest.setDispatcherType(ctype);
+                baseRequest.setAttribute(AsyncContext.ASYNC_CONTEXT_PATH,async_context_path);
+                baseRequest.setAttribute(AsyncContext.ASYNC_PATH_INFO,async_path_info);
+                baseRequest.setAttribute(AsyncContext.ASYNC_QUERY_STRING,async_query_string);
+                baseRequest.setAttribute(AsyncContext.ASYNC_REQUEST_URI,async_request_uri);
+                baseRequest.setAttribute(AsyncContext.ASYNC_SERVLET_PATH,async_servlet_path);
+            }
+            
+            // signal the request is leaving the handler
+            endHandling(baseRequest);
+        }
+        
+    }
+    
+    /* ------------------------------------------------------------ */
+    /** Called to indicate that a request has been presented for handling
+     * @param request The request to handle
+     * @param restart True if this request is being restarted after a delay
+     * @return True if the request should be handled now
+     */
+    protected boolean startHandling(Request request, boolean restart)
+    {
+        return true;
+    }
+
+    /* ------------------------------------------------------------ */
+    /** Called to indicate that a requests handling is being delayed/
+     * The implementation should arrange for context.dispatch() to be
+     * called when the request should be handled.  It may also set
+     * timeouts on the context. 
+     * 
+     * @param request The request to be delayed
+     * @param context The AsyncContext of the delayed request
+     */
+    protected void delayHandling(Request request,AsyncContext context)
+    {
+        context.dispatch();
+    }
+    
+    /* ------------------------------------------------------------ */
+    /** Called to indicated the handling of the request is ending.
+     * This is only the end of the current dispatch of the request and
+     * if the request is asynchronous, it may be handled again.
+     * @param request The request
+     */
+    protected void endHandling(Request request)
+    {
+        
+    }
+    
+    
+}
index 397cde1fd13c2d3d4ddd037740c8f61cbd52ae85..928f850b06aaba27004f638a46d29665645fd743 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -36,7 +36,6 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
-import java.util.ListIterator;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
@@ -67,7 +66,6 @@ import javax.servlet.http.HttpServletResponse;
 
 import org.eclipse.jetty.http.MimeTypes;
 import org.eclipse.jetty.server.ClassLoaderDump;
-import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.Dispatcher;
 import org.eclipse.jetty.server.Handler;
 import org.eclipse.jetty.server.HandlerContainer;
@@ -107,8 +105,8 @@ import org.eclipse.jetty.util.resource.Resource;
 public class ContextHandler extends ScopedHandler implements Attributes, Graceful
 {
     public final static int SERVLET_MAJOR_VERSION=3;
-    public final static int SERVLET_MINOR_VERSION=0;
-    public static final Class[] SERVLET_LISTENER_TYPES = new Class[] {ServletContextListener.class,
+    public final static int SERVLET_MINOR_VERSION=1;
+    public static final Class<?>[] SERVLET_LISTENER_TYPES = new Class[] {ServletContextListener.class,
                                                                       ServletContextAttributeListener.class,
                                                                       ServletRequestListener.class,
                                                                       ServletRequestAttributeListener.class};
@@ -510,8 +508,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
     /*
      * @see javax.servlet.ServletContext#getInitParameterNames()
      */
-    @SuppressWarnings("rawtypes")
-    public Enumeration getInitParameterNames()
+    public Enumeration<String> getInitParameterNames()
     {
         return Collections.enumeration(_initParams.keySet());
     }
@@ -771,7 +768,9 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
             _managedAttributes = new HashMap<String, Object>();
             String[] attributes = managedAttributes.split(",");
             for (String attribute : attributes)
-                _managedAttributes.put(attribute,null);
+            {
+                _managedAttributes.put(attribute.trim(),null);
+            }
 
             Enumeration<String> e = _scontext.getAttributeNames();
             while (e.hasMoreElements())
@@ -796,14 +795,16 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
     /* ------------------------------------------------------------ */
     protected void callContextInitialized (ServletContextListener l, ServletContextEvent e)
     {
-        LOG.debug("contextInitialized: {}->{}",e,l);
+        if (LOG.isDebugEnabled())
+            LOG.debug("contextInitialized: {}->{}",e,l);
         l.contextInitialized(e);
     }
 
     /* ------------------------------------------------------------ */
     protected void callContextDestroyed (ServletContextListener l, ServletContextEvent e)
     {
-        LOG.debug("contextDestroyed: {}->{}",e,l);
+        if (LOG.isDebugEnabled())
+            LOG.debug("contextDestroyed: {}->{}",e,l);
         l.contextDestroyed(e);
     }
 
@@ -871,27 +872,8 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
         _scontext.clearAttributes();
     }
 
-    /* ------------------------------------------------------------ */
-    /*
-     * @see org.eclipse.jetty.server.Handler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
-     */
-    public boolean checkContext(final String target, final Request baseRequest, final HttpServletResponse response) throws IOException
+    public boolean checkVirtualHost(final Request baseRequest)
     {
-        DispatcherType dispatch = baseRequest.getDispatcherType();
-
-        switch (_availability)
-        {
-            case SHUTDOWN:
-            case UNAVAILABLE:
-                baseRequest.setHandled(true);
-                response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
-                return false;
-            default:
-                if ((DispatcherType.REQUEST.equals(dispatch) && baseRequest.isHandled()))
-                    return false;
-        }
-
-        // Check the vhosts
         if (_vhosts != null && _vhosts.length > 0)
         {
             String vhost = normalizeHostname(baseRequest.getServerName());
@@ -927,27 +909,61 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
             if (!match || connectorName && !connectorMatch)
                 return false;
         }
-
+        return true;
+    }
+    
+    public boolean checkContextPath(String uri)
+    {
         // Are we not the root context?
         if (_contextPath.length() > 1)
         {
             // reject requests that are not for us
-            if (!target.startsWith(_contextPath))
+            if (!uri.startsWith(_contextPath))
                 return false;
-            if (target.length() > _contextPath.length() && target.charAt(_contextPath.length()) != '/')
+            if (uri.length() > _contextPath.length() && uri.charAt(_contextPath.length()) != '/')
                 return false;
+        }
+        return true;
+    }
+    
+    /* ------------------------------------------------------------ */
+    /*
+     * @see org.eclipse.jetty.server.Handler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+     */
+    public boolean checkContext(final String target, final Request baseRequest, final HttpServletResponse response) throws IOException
+    {
+        DispatcherType dispatch = baseRequest.getDispatcherType();
 
-            // redirect null path infos
-            if (!_allowNullPathInfo && _contextPath.length() == target.length())
-            {
-                // context request must end with /
+        // Check the vhosts
+        if (!checkVirtualHost(baseRequest))
+            return false;
+
+        if (!checkContextPath(target))
+            return false;
+        
+        // Are we not the root context?
+        // redirect null path infos
+        if (!_allowNullPathInfo && _contextPath.length() == target.length() && _contextPath.length()>1)
+        {
+            // context request must end with /
+            baseRequest.setHandled(true);
+            if (baseRequest.getQueryString() != null)
+                response.sendRedirect(URIUtil.addPaths(baseRequest.getRequestURI(),URIUtil.SLASH) + "?" + baseRequest.getQueryString());
+            else
+                response.sendRedirect(URIUtil.addPaths(baseRequest.getRequestURI(),URIUtil.SLASH));
+            return false;
+        }
+
+        switch (_availability)
+        {
+            case SHUTDOWN:
+            case UNAVAILABLE:
                 baseRequest.setHandled(true);
-                if (baseRequest.getQueryString() != null)
-                    response.sendRedirect(URIUtil.addPaths(baseRequest.getRequestURI(),URIUtil.SLASH) + "?" + baseRequest.getQueryString());
-                else
-                    response.sendRedirect(URIUtil.addPaths(baseRequest.getRequestURI(),URIUtil.SLASH));
+                response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
                 return false;
-            }
+            default:
+                if ((DispatcherType.REQUEST.equals(dispatch) && baseRequest.isHandled()))
+                    return false;
         }
 
         return true;
@@ -1127,7 +1143,6 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
 
                 if (!_requestAttributeListeners.isEmpty())
                 {
-                    ListIterator<ServletRequestAttributeListener> iter = _requestAttributeListeners.listIterator(_requestAttributeListeners.size());
                     for (int i=_requestAttributeListeners.size();i-->0;)
                         baseRequest.removeEventListener(_requestAttributeListeners.get(i));
                 }
@@ -1646,10 +1661,15 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
     }
 
     /* ------------------------------------------------------------ */
+    /**
+     * @param path
+     * @param resource
+     * @return True if the alias is OK
+     */
     public boolean checkAlias(String path, Resource resource)
     {
         // Is the resource aliased?
-            if (resource.getAlias() != null)
+        if (resource.getAlias() != null)
         {
             if (LOG.isDebugEnabled())
                 LOG.debug("Aliased resource: " + resource + "~=" + resource.getAlias());
@@ -1878,7 +1898,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
                         matched_path = context_path;
                     }
 
-                    if (matched_path.equals(context_path))
+                    if (matched_path != null && matched_path.equals(context_path))
                         contexts.add(ch);
                 }
             }
@@ -2056,7 +2076,6 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
         /*
          * @see javax.servlet.ServletContext#getInitParameterNames()
          */
-        @SuppressWarnings("unchecked")
         @Override
         public Enumeration<String> getInitParameterNames()
         {
@@ -2193,6 +2212,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
 
             try
             {
+                @SuppressWarnings("unchecked")
                 Class<? extends EventListener> clazz = _classLoader==null?Loader.loadClass(ContextHandler.class,className):_classLoader.loadClass(className);
                 addListener(clazz);
             }
@@ -2287,9 +2307,9 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
                //classloader, or a parent of it
                try
                {
-                   Class reflect = Loader.loadClass(getClass(), "sun.reflect.Reflection");
+                   Class<?> reflect = Loader.loadClass(getClass(), "sun.reflect.Reflection");
                    Method getCallerClass = reflect.getMethod("getCallerClass", Integer.TYPE);
-                   Class caller = (Class)getCallerClass.invoke(null, 2);
+                   Class<?> caller = (Class<?>)getCallerClass.invoke(null, 2);
 
                    boolean ok = false;
                    ClassLoader callerLoader = caller.getClassLoader();
@@ -2428,6 +2448,11 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
         @Override
         public String getServerInfo()
         {
+            // NOTE: DO NOT CHANGE
+            //   this is used by weld to detect Jetty
+            //   implementation version
+            // See: https://github.com/weld/core/blob/master/environments/servlet/core/src/main/java/org/jboss/weld/environment/jetty/JettyContainer.java
+            //   and its touch(ContainerContext) method
             return "jetty/" + Server.getVersion();
         }
 
index 4ade3649030e3db9cd8c46c028f5eb983e58b2ae..b4f359b3da9299c124d4626e8a1863f31fe8b79e 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
 package org.eclipse.jetty.server.handler;
 
 import java.io.IOException;
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
@@ -52,7 +61,8 @@ public class ContextHandlerCollection extends HandlerCollection
 {
     private static final Logger LOG = Log.getLogger(ContextHandlerCollection.class);
 
-    private volatile Trie<ContextHandler[]> _contexts;
+    private final ConcurrentMap<ContextHandler,Handler> _contextBranches = new ConcurrentHashMap<>();
+    private volatile Trie<Map.Entry<String,Branch[]>> _pathBranches;
     private Class<? extends ContextHandler> _contextClass = ContextHandler.class;
 
     /* ------------------------------------------------------------ */
@@ -69,71 +79,70 @@ public class ContextHandlerCollection extends HandlerCollection
     @ManagedOperation("update the mapping of context path to context")
     public void mapContexts()
     {
-        int capacity=512;
+        _contextBranches.clear();
+        
+        if (getHandlers()==null)
+        {
+            _pathBranches=new ArrayTernaryTrie<>(false,16);
+            return;
+        }
+        
+        // Create map of contextPath to handler Branch
+        Map<String,Branch[]> map = new HashMap<>();
+        for (Handler handler:getHandlers())
+        {
+            Branch branch=new Branch(handler);
+            for (String contextPath : branch.getContextPaths())
+            {
+                Branch[] branches=map.get(contextPath);
+                map.put(contextPath, ArrayUtil.addToArray(branches, branch, Branch.class));
+            }
+            
+            for (ContextHandler context : branch.getContextHandlers())
+                _contextBranches.putIfAbsent(context, branch.getHandler());
+        }
+        
+        // Sort the branches so those with virtual hosts are considered before those without
+        for (Map.Entry<String,Branch[]> entry: map.entrySet())
+        {
+            Branch[] branches=entry.getValue();
+            Branch[] sorted=new Branch[branches.length];
+            int i=0;
+            for (Branch branch:branches)
+                if (branch.hasVirtualHost())
+                    sorted[i++]=branch;
+            for (Branch branch:branches)
+                if (!branch.hasVirtualHost())
+                    sorted[i++]=branch;
+            entry.setValue(sorted);
+        }
         
         // Loop until we have a big enough trie to hold all the context paths
-        Trie<ContextHandler[]> trie;
+        int capacity=512;
+        Trie<Map.Entry<String,Branch[]>> trie;
         loop: while(true)
         {
             trie=new ArrayTernaryTrie<>(false,capacity);
-
-            Handler[] branches = getHandlers();
-
-            // loop over each group of contexts
-            for (int b=0;branches!=null && b<branches.length;b++)
+            for (Map.Entry<String,Branch[]> entry: map.entrySet())
             {
-                Handler[] handlers=null;
-
-                if (branches[b] instanceof ContextHandler)
+                if (!trie.put(entry.getKey().substring(1),entry))
                 {
-                    handlers = new Handler[]{ branches[b] };
-                }
-                else if (branches[b] instanceof HandlerContainer)
-                {
-                    handlers = ((HandlerContainer)branches[b]).getChildHandlersByClass(ContextHandler.class);
-                }
-                else
-                    continue;
-
-                // for each context handler in a group
-                for (int i=0;handlers!=null && i<handlers.length;i++)
-                {
-                    ContextHandler handler=(ContextHandler)handlers[i];
-                    String contextPath=handler.getContextPath().substring(1);
-                    ContextHandler[] contexts=trie.get(contextPath);
-                    
-                    if (!trie.put(contextPath,ArrayUtil.addToArray(contexts,handler,ContextHandler.class)))
-                    {
-                        capacity+=512;
-                        continue loop;
-                    }
+                    capacity+=512;
+                    continue loop;
                 }
             }
-            
-            break;
+            break loop;
         }
+            
         
-        // Sort the contexts so those with virtual hosts are considered before those without
-        for (String ctx : trie.keySet())
+        if (LOG.isDebugEnabled())
         {
-            ContextHandler[] contexts=trie.get(ctx);
-            ContextHandler[] sorted=new ContextHandler[contexts.length];
-            int i=0;
-            for (ContextHandler handler:contexts)
-                if (handler.getVirtualHosts()!=null && handler.getVirtualHosts().length>0)
-                    sorted[i++]=handler;
-            for (ContextHandler handler:contexts)
-                if (handler.getVirtualHosts()==null || handler.getVirtualHosts().length==0)
-                    sorted[i++]=handler;
-            trie.put(ctx,sorted);
+            for (String ctx : trie.keySet())
+                LOG.debug("{}->{}",ctx,Arrays.asList(trie.get(ctx).getValue()));
         }
-
-        //for (String ctx : trie.keySet())
-        //    System.err.printf("'%s'->%s%n",ctx,Arrays.asList(trie.get(ctx)));
-        _contexts=trie;
+        _pathBranches=trie;
     }
 
-
     /* ------------------------------------------------------------ */
     /*
      * @see org.eclipse.jetty.server.server.handler.HandlerCollection#setHandlers(org.eclipse.jetty.server.server.Handler[])
@@ -164,60 +173,66 @@ public class ContextHandlerCollection extends HandlerCollection
     {
         Handler[] handlers = getHandlers();
         if (handlers==null || handlers.length==0)
-           return;
+            return;
 
-       HttpChannelState async = baseRequest.getHttpChannelState();
-       if (async.isAsync())
-       {
-           ContextHandler context=async.getContextHandler();
-           if (context!=null)
-           {
-               context.handle(target,baseRequest,request, response);
-               return;
-           }
-       }
-
-       // data structure which maps a request to a context; first-best match wins
-       // { context path => [ context ] }
-       // }
-       if (target.startsWith("/"))
-       {
-           int limit = target.length()-1;
-
-           while (limit>=0)
-           {
-               // Get best match
-               ContextHandler[] contexts = _contexts.getBest(target,1,limit);
-               if (contexts==null)
-                   break;
+        HttpChannelState async = baseRequest.getHttpChannelState();
+        if (async.isAsync())
+        {
+            ContextHandler context=async.getContextHandler();
+            if (context!=null)
+            {
+                Handler branch = _contextBranches.get(context);
+                
+                if (branch==null)
+                    context.handle(target,baseRequest,request, response);
+                else
+                    branch.handle(target, baseRequest, request, response);
+                return;
+            }
+        }
+        
+        // data structure which maps a request to a context; first-best match wins
+        // { context path => [ context ] }
+        // }
+        if (target.startsWith("/"))
+        {
+            int limit = target.length()-1;
 
-               int l=contexts[0].getContextPath().length();
-               if (l==1 || target.length()==l || target.charAt(l)=='/')
-               {
-                   for (ContextHandler handler : contexts)
-                   {
-                       handler.handle(target,baseRequest, request, response);
-                       if (baseRequest.isHandled())
-                           return;
-                   }
-               }
-               
-               limit=l-2;
-           }
-       }
-       else
-       {
+            while (limit>=0)
+            {
+                // Get best match
+                Map.Entry<String,Branch[]> branches = _pathBranches.getBest(target,1,limit);
+                
+                
+                if (branches==null)
+                    break;
+                
+                int l=branches.getKey().length();
+                if (l==1 || target.length()==l || target.charAt(l)=='/')
+                {
+                    for (Branch branch : branches.getValue())
+                    {
+                        branch.getHandler().handle(target,baseRequest, request, response);
+                        if (baseRequest.isHandled())
+                            return;
+                    }
+                }
+                
+                limit=l-2;
+            }
+        }
+        else
+        {
             // This may not work in all circumstances... but then I think it should never be called
-           for (int i=0;i<handlers.length;i++)
-           {
-               handlers[i].handle(target,baseRequest, request, response);
-               if ( baseRequest.isHandled())
-                   return;
-           }
-       }
+            for (int i=0;i<handlers.length;i++)
+            {
+                handlers[i].handle(target,baseRequest, request, response);
+                if ( baseRequest.isHandled())
+                    return;
+            }
+        }
     }
 
-
     /* ------------------------------------------------------------ */
     /** Add a context handler.
      * @param contextPath  The context path to add
@@ -263,5 +278,64 @@ public class ContextHandlerCollection extends HandlerCollection
         _contextClass = contextClass;
     }
 
+    /* ------------------------------------------------------------ */
+    /* ------------------------------------------------------------ */
+    /* ------------------------------------------------------------ */
+    private final static class Branch
+    {
+        private final Handler _handler;
+        private final ContextHandler[] _contexts;
+        
+        Branch(Handler handler)
+        {
+            _handler=handler;
+
+            if (handler instanceof ContextHandler)
+            {
+                _contexts = new ContextHandler[]{(ContextHandler)handler};
+            }
+            else if (handler instanceof HandlerContainer)
+            {
+                Handler[] contexts=((HandlerContainer)handler).getChildHandlersByClass(ContextHandler.class);
+                _contexts = new ContextHandler[contexts.length];
+                System.arraycopy(contexts, 0, _contexts, 0, contexts.length);
+            }
+            else
+                _contexts = new ContextHandler[0];
+        }
+        
+        Set<String> getContextPaths()
+        {
+            Set<String> set = new HashSet<String>();
+            for (ContextHandler context:_contexts)
+                set.add(context.getContextPath());
+            return set;
+        }
+        
+        boolean hasVirtualHost()
+        {
+            for (ContextHandler context:_contexts)
+                if (context.getVirtualHosts()!=null && context.getVirtualHosts().length>0)
+                    return true;
+            return false;
+        }
+        
+        ContextHandler[] getContextHandlers()
+        {
+            return _contexts;
+        }
+        
+        Handler getHandler()
+        {
+            return _handler;
+        }
+        
+        @Override
+        public String toString()
+        {
+            return String.format("{%s,%s}",_handler,Arrays.asList(_contexts));
+        }
+    }
+
 
 }
index 0ed72612fc4b9d0e881aaec5b50b34e6827ef186..651abd8aa774617bb4483a317931d3b8c36356d6 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index f71720af41f4d173b301d46bc52f5797a95ff151..fbc59c27cf54aa9c6d80b1628122b5877dca6e8f 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -117,62 +117,63 @@ public class DefaultHandler extends AbstractHandler
         response.setStatus(HttpServletResponse.SC_NOT_FOUND);
         response.setContentType(MimeTypes.Type.TEXT_HTML.toString());
 
-        ByteArrayISO8859Writer writer = new ByteArrayISO8859Writer(1500);
-
-        writer.write("<HTML>\n<HEAD>\n<TITLE>Error 404 - Not Found");
-        writer.write("</TITLE>\n<BODY>\n<H2>Error 404 - Not Found.</H2>\n");
-        writer.write("No context on this server matched or handled this request.<BR>");
-        writer.write("Contexts known to this server are: <ul>");
+        try (ByteArrayISO8859Writer writer = new ByteArrayISO8859Writer(1500);)
+        {
+            writer.write("<HTML>\n<HEAD>\n<TITLE>Error 404 - Not Found");
+            writer.write("</TITLE>\n<BODY>\n<H2>Error 404 - Not Found.</H2>\n");
+            writer.write("No context on this server matched or handled this request.<BR>");
+            writer.write("Contexts known to this server are: <ul>");
 
-        Server server = getServer();
-        Handler[] handlers = server==null?null:server.getChildHandlersByClass(ContextHandler.class);
+            Server server = getServer();
+            Handler[] handlers = server==null?null:server.getChildHandlersByClass(ContextHandler.class);
 
-        for (int i=0;handlers!=null && i<handlers.length;i++)
-        {
-            ContextHandler context = (ContextHandler)handlers[i];
-            if (context.isRunning())
-            {
-                writer.write("<li><a href=\"");
-                if (context.getVirtualHosts()!=null && context.getVirtualHosts().length>0)
-                    writer.write("http://"+context.getVirtualHosts()[0]+":"+request.getLocalPort());
-                writer.write(context.getContextPath());
-                if (context.getContextPath().length()>1 && context.getContextPath().endsWith("/"))
-                    writer.write("/");
-                writer.write("\">");
-                writer.write(context.getContextPath());
-                if (context.getVirtualHosts()!=null && context.getVirtualHosts().length>0)
-                    writer.write("&nbsp;@&nbsp;"+context.getVirtualHosts()[0]+":"+request.getLocalPort());
-                writer.write("&nbsp;--->&nbsp;");
-                writer.write(context.toString());
-                writer.write("</a></li>\n");
-            }
-            else
+            for (int i=0;handlers!=null && i<handlers.length;i++)
             {
-                writer.write("<li>");
-                writer.write(context.getContextPath());
-                if (context.getVirtualHosts()!=null && context.getVirtualHosts().length>0)
-                    writer.write("&nbsp;@&nbsp;"+context.getVirtualHosts()[0]+":"+request.getLocalPort());
-                writer.write("&nbsp;--->&nbsp;");
-                writer.write(context.toString());
-                if (context.isFailed())
-                    writer.write(" [failed]");
-                if (context.isStopped())
-                    writer.write(" [stopped]");
-                writer.write("</li>\n");
+                ContextHandler context = (ContextHandler)handlers[i];
+                if (context.isRunning())
+                {
+                    writer.write("<li><a href=\"");
+                    if (context.getVirtualHosts()!=null && context.getVirtualHosts().length>0)
+                        writer.write("http://"+context.getVirtualHosts()[0]+":"+request.getLocalPort());
+                    writer.write(context.getContextPath());
+                    if (context.getContextPath().length()>1 && context.getContextPath().endsWith("/"))
+                        writer.write("/");
+                    writer.write("\">");
+                    writer.write(context.getContextPath());
+                    if (context.getVirtualHosts()!=null && context.getVirtualHosts().length>0)
+                        writer.write("&nbsp;@&nbsp;"+context.getVirtualHosts()[0]+":"+request.getLocalPort());
+                    writer.write("&nbsp;--->&nbsp;");
+                    writer.write(context.toString());
+                    writer.write("</a></li>\n");
+                }
+                else
+                {
+                    writer.write("<li>");
+                    writer.write(context.getContextPath());
+                    if (context.getVirtualHosts()!=null && context.getVirtualHosts().length>0)
+                        writer.write("&nbsp;@&nbsp;"+context.getVirtualHosts()[0]+":"+request.getLocalPort());
+                    writer.write("&nbsp;--->&nbsp;");
+                    writer.write(context.toString());
+                    if (context.isFailed())
+                        writer.write(" [failed]");
+                    if (context.isStopped())
+                        writer.write(" [stopped]");
+                    writer.write("</li>\n");
+                }
             }
-        }
 
-        writer.write("</ul><hr>");
-        writer.write("<a href=\"http://eclipse.org/jetty\"><img border=0 src=\"/favicon.ico\"/></a>&nbsp;");
-        writer.write("<a href=\"http://eclipse.org/jetty\">Powered by Jetty:// Java Web Server</a><hr/>\n");
+            writer.write("</ul><hr>");
+            writer.write("<a href=\"http://eclipse.org/jetty\"><img border=0 src=\"/favicon.ico\"/></a>&nbsp;");
+            writer.write("<a href=\"http://eclipse.org/jetty\">Powered by Jetty:// Java Web Server</a><hr/>\n");
 
-        writer.write("\n</BODY>\n</HTML>\n");
-        writer.flush();
-        response.setContentLength(writer.size());
-        try (OutputStream out=response.getOutputStream())
-        {
-            writer.writeTo(out);
-        }
+            writer.write("\n</BODY>\n</HTML>\n");
+            writer.flush();
+            response.setContentLength(writer.size());
+            try (OutputStream out=response.getOutputStream())
+            {
+                writer.writeTo(out);
+            }
+        } 
     }
 
     /* ------------------------------------------------------------ */
index b1af5208a39aad479a13589315de81e6dc3c54f7..f1094317d298e436662a418cf3199bd66818223c 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -39,6 +39,7 @@ import org.eclipse.jetty.server.Response;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.util.BufferUtil;
 import org.eclipse.jetty.util.ByteArrayISO8859Writer;
+import org.eclipse.jetty.util.StringUtil;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
 
@@ -275,29 +276,7 @@ public class ErrorHandler extends AbstractHandler
         if (string==null)
             return;
 
-        for (int i=0;i<string.length();i++)
-        {
-            char c=string.charAt(i);
-
-            switch(c)
-            {
-                case '&' :
-                    writer.write("&amp;");
-                    break;
-                case '<' :
-                    writer.write("&lt;");
-                    break;
-                case '>' :
-                    writer.write("&gt;");
-                    break;
-
-                default:
-                    if (Character.isISOControl(c) && !Character.isWhitespace(c))
-                        writer.write('?');
-                    else
-                        writer.write(c);
-            }
-        }
+        writer.write(StringUtil.sanitizeXmlString(string));
     }
 
     /* ------------------------------------------------------------ */
index c118c7ec1da4cf6763142b9b2f09a87b30d17722..21c3a329e256b89d4a95222b99093d8d214df46f 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -19,6 +19,7 @@
 package org.eclipse.jetty.server.handler;
 
 import java.io.IOException;
+import java.util.Arrays;
 import java.util.List;
 
 import javax.servlet.ServletException;
@@ -185,4 +186,12 @@ public class HandlerCollection extends AbstractHandlerContainer
             child.destroy();
         super.destroy();
     }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public String toString()
+    {
+        Handler[] handlers=getHandlers();
+        return super.toString()+(handlers==null?"[]":Arrays.asList(getHandlers()).toString());
+    }
 }
index 74320b08e780364a72b2c321abcdae07c386b081..06f199458384cfaf996970502a27bf7190ac0e33 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index dcbf6ff5d544c936f7fe4c4c67df8e7bd280e8ab..82f9b34602c68b125bbff19ba4b6bbe85d62a8c4 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -30,7 +30,6 @@ import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.util.annotation.ManagedAttribute;
 import org.eclipse.jetty.util.annotation.ManagedObject;
-import org.eclipse.jetty.util.component.LifeCycle;
 
 /* ------------------------------------------------------------ */
 /** A <code>HandlerWrapper</code> acts as a {@link Handler} but delegates the {@link Handler#handle handle} method and
index 162a719e80681a569d558bcbe0092ddf7a3f4949..6da22cf4adb3fdf269b689dbc18a75210b8aaf59 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 97a3ac8d43e92c4321452a44dac9889d25e1aa01..cec075e9e4f9ba0d9217fc44a2989577083fc4c2 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 04a90f17bc5840d94b5606a4016f84fbda08447b..9cbc84c45867d0d50240a0e01ac6d6e1ae9f68ac 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -27,6 +27,7 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.server.HttpChannel;
 import org.eclipse.jetty.server.HttpConnection;
 import org.eclipse.jetty.server.Request;
 
@@ -79,17 +80,9 @@ public class IdleTimeoutHandler extends HandlerWrapper
     @Override
     public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
     {
-        HttpConnection connection = HttpConnection.getCurrentConnection();
-        final EndPoint endp = connection==null?null:connection.getEndPoint();
-        
-        final long idle_timeout;
-        if (endp==null)
-            idle_timeout=-1;
-        else
-        {
-            idle_timeout=endp.getIdleTimeout();
-            endp.setIdleTimeout(_idleTimeoutMs);
-        }
+        final HttpChannel<?> channel = baseRequest.getHttpChannel();
+        final long idle_timeout=baseRequest.getHttpChannel().getIdleTimeout();
+        channel.setIdleTimeout(_idleTimeoutMs);
         
         try
         {
@@ -97,8 +90,6 @@ public class IdleTimeoutHandler extends HandlerWrapper
         }
         finally
         {
-            if (endp!=null)
-            {
                 if (_applyToAsync && request.isAsyncStarted())
                 {
                     request.getAsyncContext().addListener(new AsyncListener()
@@ -116,19 +107,18 @@ public class IdleTimeoutHandler extends HandlerWrapper
                         @Override
                         public void onError(AsyncEvent event) throws IOException
                         {
-                            endp.setIdleTimeout(idle_timeout);
+                            channel.setIdleTimeout(idle_timeout);
                         }
                         
                         @Override
                         public void onComplete(AsyncEvent event) throws IOException
                         {
-                            endp.setIdleTimeout(idle_timeout);
+                            channel.setIdleTimeout(idle_timeout);
                         }
                     });
                 }
                 else 
-                    endp.setIdleTimeout(idle_timeout);
-            }
+                    channel.setIdleTimeout(idle_timeout);
         }
     }
 }
index 5e9fd85466e94ac0ae066e8b0330d93338408652..2a90f712f18e2bbd113c4a6b8aeb603e9303ba8a 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 706b988bffc4398688488cffe787781d461cdd32..00ec275c377400c7f2cb973edfe318b0f6eac766 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -66,6 +66,9 @@ public class RequestLogHandler extends HandlerWrapper
         @Override
         public void onError(AsyncEvent event) throws IOException
         {
+            HttpServletResponse response = (HttpServletResponse)event.getAsyncContext().getResponse();
+            if (!response.isCommitted())
+                response.setStatus(500);
             
         }
         
@@ -91,6 +94,12 @@ public class RequestLogHandler extends HandlerWrapper
         {
             super.handle(target, baseRequest, request, response);
         }
+        catch(Error|IOException|ServletException|RuntimeException e)
+        {
+            if (!response.isCommitted() && !baseRequest.getHttpChannelState().isAsync())
+                response.setStatus(500);
+            throw e;
+        }
         finally
         {
             if (_requestLog != null && baseRequest.getDispatcherType().equals(DispatcherType.REQUEST))
index 10d1e051301e1fad820d9d051f58460458e8acf7..286284d9c73ac992b45795706254b95b2e1d1615 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -72,7 +72,7 @@ public class ResourceHandler extends HandlerWrapper
     String _cacheControl;
     boolean _directory;
     boolean _etags;
-    int _minMemoryMappedContentLength=-1;
+    int _minMemoryMappedContentLength=1024;
     int _minAsyncContentLength=0;
 
     /* ------------------------------------------------------------ */
@@ -240,18 +240,18 @@ public class ResourceHandler extends HandlerWrapper
      */
     public Resource getStylesheet()
     {
-       if(_stylesheet != null)
-       {
-           return _stylesheet;
-       }
-       else
-       {
-           if(_defaultStylesheet == null)
-           {
-               _defaultStylesheet =  Resource.newResource(this.getClass().getResource("/jetty-dir.css"));
-           }
-           return _defaultStylesheet;
-       }
+        if(_stylesheet != null)
+        {
+            return _stylesheet;
+        }
+        else
+        {
+            if(_defaultStylesheet == null)
+            {
+                _defaultStylesheet =  Resource.newResource(this.getClass().getResource("/jetty-dir.css"));
+            }
+            return _defaultStylesheet;
+        }
     }
 
     /* ------------------------------------------------------------ */
@@ -269,12 +269,12 @@ public class ResourceHandler extends HandlerWrapper
                 _stylesheet = null;
             }
         }
-       catch(Exception e)
-       {
-           LOG.warn(e.toString());
-           LOG.debug(e);
-           throw new IllegalArgumentException(stylesheet);
-       }
+        catch(Exception e)
+        {
+            LOG.warn(e.toString());
+            LOG.debug(e);
+            throw new IllegalArgumentException(stylesheet);
+        }
     }
 
     /* ------------------------------------------------------------ */
@@ -303,20 +303,29 @@ public class ResourceHandler extends HandlerWrapper
         if (path==null || !path.startsWith("/"))
             throw new MalformedURLException(path);
 
+        if (LOG.isDebugEnabled())
+            LOG.debug("{} getResource({})",_context==null?_baseResource:_context,_baseResource,path);
+        
         Resource base = _baseResource;
         if (base==null)
         {
             if (_context==null)
                 return null;
-            base=_context.getBaseResource();
-            if (base==null)
-                return null;
+            return _context.getResource(path);
         }
 
         try
         {
             path=URIUtil.canonicalPath(path);
-            return base.addPath(path);
+            Resource r = base.addPath(path);
+            
+            if (r!=null && r.getAlias()!=null && (_context==null || !_context.checkAlias(path, r)))
+            {
+                if (LOG.isDebugEnabled())
+                    LOG.debug("resource={} alias={}",r,r.getAlias());
+                return null;
+            }
+            return r;
         }
         catch(Exception e)
         {
@@ -403,6 +412,16 @@ public class ResourceHandler extends HandlerWrapper
         }
 
         Resource resource = getResource(request);
+        
+        if (LOG.isDebugEnabled())
+        { 
+            if (resource==null)
+                LOG.debug("resource=null");
+            else
+                LOG.debug("resource={} alias={} exists={}",resource,resource.getAlias(),resource.exists());
+        }
+        
+        
         // If resource is not found
         if (resource==null || !resource.exists())
         {
@@ -428,7 +447,9 @@ public class ResourceHandler extends HandlerWrapper
         // handle directories
         if (resource.isDirectory())
         {
-            if (!request.getPathInfo().endsWith(URIUtil.SLASH))
+            String pathInfo = request.getPathInfo();
+            boolean endsWithSlash=(pathInfo==null?request.getServletPath():pathInfo).endsWith(URIUtil.SLASH);
+            if (!endsWithSlash)
             {
                 response.sendRedirect(response.encodeRedirectURL(URIUtil.addPaths(request.getRequestURI(),URIUtil.SLASH)));
                 return;
@@ -503,6 +524,7 @@ public class ResourceHandler extends HandlerWrapper
                 resource.length()>=min_async_size)
             {
                 final AsyncContext async = request.startAsync();
+                async.setTimeout(0);
                 Callback callback = new Callback()
                 {
                     @Override
@@ -523,6 +545,7 @@ public class ResourceHandler extends HandlerWrapper
                 // Can we use a memory mapped file?
                 if (_minMemoryMappedContentLength>0 && 
                     resource.length()>_minMemoryMappedContentLength &&
+                    resource.length()<Integer.MAX_VALUE &&
                     resource instanceof FileResource)
                 {
                     ByteBuffer buffer = BufferUtil.toMappedBuffer(resource.getFile());
index 50998bea28e4ed32640074b5a55404c3a223fdb8..06faa35991d54cdea444560dc36064e047c64237 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
diff --git a/lib/jetty/org/eclipse/jetty/server/handler/SecuredRedirectHandler.java b/lib/jetty/org/eclipse/jetty/server/handler/SecuredRedirectHandler.java
new file mode 100644 (file)
index 0000000..4cea6f8
--- /dev/null
@@ -0,0 +1,76 @@
+//
+//  ========================================================================
+//  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 javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.server.HttpChannel;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConnection;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.util.URIUtil;
+
+/**
+ * Secured Redirect Handler
+ * <p>
+ * Using information present in the {@link HttpConfiguration}, will attempt to redirect to the {@link HttpConfiguration#getSecureScheme()} and
+ * {@link HttpConfiguration#getSecurePort()} for any request that {@link HttpServletRequest#isSecure()} == false.
+ */
+public class SecuredRedirectHandler extends AbstractHandler
+{
+    @Override
+    public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+    {
+        HttpChannel<?> channel = baseRequest.getHttpChannel();
+        if (baseRequest.isSecure() || (channel == null))
+        {
+            // nothing to do
+            return;
+        }
+
+        HttpConfiguration httpConfig = channel.getHttpConfiguration();
+        if (httpConfig == null)
+        {
+            // no config, show error
+            response.sendError(HttpStatus.FORBIDDEN_403,"No http configuration available");
+            return;
+        }
+
+        if (httpConfig.getSecurePort() > 0)
+        {
+            String scheme = httpConfig.getSecureScheme();
+            int port = httpConfig.getSecurePort();
+
+            String url = URIUtil.newURI(scheme,baseRequest.getServerName(),port,baseRequest.getRequestURI(),baseRequest.getQueryString());
+            response.setContentLength(0);
+            response.sendRedirect(url);
+        }
+        else
+        {
+            response.sendError(HttpStatus.FORBIDDEN_403,"Not Secure");
+        }
+        
+        baseRequest.setHandled(true);
+    }
+}
\ No newline at end of file
index e946fb670e704b5822a7431f8335116bbba1e5b2..6a4daa37ef249aaa308d8afa9e3439bb6d114a1a 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -37,8 +37,12 @@ import org.eclipse.jetty.util.log.Logger;
 
 /* ------------------------------------------------------------ */
 /**
- * A handler that shuts the server down on a valid request. Used to do "soft" restarts from Java. If _exitJvm ist set to true a hard System.exit() call is being
- * made.
+ * A handler that shuts the server down on a valid request. Used to do "soft" restarts from Java.
+ * If _exitJvm is set to true a hard System.exit() call is being made.
+ * If _sendShutdownAtStart is set to true, starting the server will try to shut down an existing server at the same port.
+ * If _sendShutdownAtStart is set to true, make a http call to
+ * "http://localhost:" + port + "/shutdown?token=" + shutdownCookie
+ * in order to shut down the server.
  *
  * This handler is a contribution from Johannes Brodwall: https://bugs.eclipse.org/bugs/show_bug.cgi?id=357687
  *
@@ -48,7 +52,7 @@ import org.eclipse.jetty.util.log.Logger;
     Server server = new Server(8080);
     HandlerList handlers = new HandlerList();
     handlers.setHandlers(new Handler[]
-    { someOtherHandler, new ShutdownHandler(&quot;secret password&quot;) });
+    { someOtherHandler, new ShutdownHandler(&quot;secret password&quot;, false, true) });
     server.setHandler(handlers);
     server.start();
    </pre>
@@ -100,9 +104,11 @@ public class ShutdownHandler extends HandlerWrapper
     
     /**
      * @param shutdownToken
+     *            a secret password to avoid unauthorized shutdown attempts
+     * @param exitJVM If true, when the shutdown is executed, the handler class System.exit()
      * @param sendShutdownAtStart If true, a shutdown is sent as a HTTP post
-     * during startup, which will shutdown any previously running instances of
-     * this server with an identically configured ShutdownHandler
+     *            during startup, which will shutdown any previously running instances of
+     *            this server with an identically configured ShutdownHandler
      */
     public ShutdownHandler(String shutdownToken, boolean exitJVM, boolean sendShutdownAtStart)
     {
@@ -120,7 +126,7 @@ public class ShutdownHandler extends HandlerWrapper
             HttpURLConnection connection = (HttpURLConnection)url.openConnection();
             connection.setRequestMethod("POST");
             connection.getResponseCode();
-            LOG.info("Shutting down " + url + ": " + connection.getResponseMessage());
+            LOG.info("Shutting down " + url + ": " + connection.getResponseCode() + " " + connection.getResponseMessage());
         }
         catch (SocketException e)
         {
@@ -133,6 +139,7 @@ public class ShutdownHandler extends HandlerWrapper
         }
     }
 
+    @SuppressWarnings("resource")
     private String getServerUrl()
     {
         NetworkConnector connector=null;
@@ -188,6 +195,16 @@ public class ShutdownHandler extends HandlerWrapper
         }
 
         LOG.info("Shutting down by request from " + request.getRemoteAddr());
+        doShutdown(baseRequest, response);
+    }
+
+    protected void doShutdown(Request baseRequest, HttpServletResponse response) throws IOException {
+        for (Connector connector : getServer().getConnectors()) {
+            connector.shutdown();
+        }
+
+        response.sendError(200, "Connectors closed, commencing full shutdown");
+        baseRequest.setHandled(true);
 
         final Server server=getServer();
         new Thread()
@@ -224,7 +241,8 @@ public class ShutdownHandler extends HandlerWrapper
     private boolean hasCorrectSecurityToken(HttpServletRequest request)
     {
         String tok = request.getParameter("token");
-        LOG.debug("Token: {}", tok);
+        if (LOG.isDebugEnabled())
+            LOG.debug("Token: {}", tok);
         return _shutdownToken.equals(tok);
     }
 
index 98bb413429b62d5ba15f370c05f983dc3d22ed69..d2694eebb0efd03f5776518bec835f69bf4261f0 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -193,35 +193,35 @@ public class StatisticsHandler extends HandlerWrapper implements Graceful
         }
     }
 
-    private void updateResponse(Request request)
+    protected void updateResponse(Request request)
     {
         Response response = request.getResponse();
-        switch (response.getStatus() / 100)
+        if (request.isHandled())
         {
-            case 0:
-                if (request.isHandled())
+            switch (response.getStatus() / 100)
+            {
+                case 1:
+                    _responses1xx.incrementAndGet();
+                    break;
+                case 2:
                     _responses2xx.incrementAndGet();
-                else
+                    break;
+                case 3:
+                    _responses3xx.incrementAndGet();
+                    break;
+                case 4:
                     _responses4xx.incrementAndGet();
-                break;
-            case 1:
-                _responses1xx.incrementAndGet();
-                break;
-            case 2:
-                _responses2xx.incrementAndGet();
-                break;
-            case 3:
-                _responses3xx.incrementAndGet();
-                break;
-            case 4:
-                _responses4xx.incrementAndGet();
-                break;
-            case 5:
-                _responses5xx.incrementAndGet();
-                break;
-            default:
-                break;
+                    break;
+                case 5:
+                    _responses5xx.incrementAndGet();
+                    break;
+                default:
+                    break;
+            }
         }
+        else
+            // will fall through to not found handler
+            _responses4xx.incrementAndGet();
         _responsesTotalBytes.addAndGet(response.getContentCount());
     }
 
index 1571d7b930a6e5985582131be402edfdb0cad52d..eb5a1600c57cf15f84fcf8136ed5948d1b0c7f14 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index f4c595834a8dc0a4a14faaab76a4b9a924b60b12..7857564fa632c60e998b9a065c1fbee8da1217a6 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 8450e18b8cd0290aac7c2655deaf76c48231736b..846b6dc0a8cfd6fd8515eeb95f4976f8d048e0a9 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 468830491fb7ab1206e4f6f1deb45a8e0b2f5f24..5ed92376fe255f94ff2b8307d649118f5f85b5ab 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 809d9d989239284647cb3b1a99fadf4d8a70157c..64718e3171b3f1432c5d92b720ad72e843ae6043 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
 package org.eclipse.jetty.server.session;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.Enumeration;
 import java.util.Iterator;
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
-
 import javax.servlet.ServletContext;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSessionActivationListener;
@@ -335,7 +332,8 @@ public abstract class AbstractSession implements AbstractSessionManager.SessionI
     {
         try
         {
-            LOG.debug("invalidate {}",_clusterId);
+            if (LOG.isDebugEnabled())
+                LOG.debug("invalidate {}",_clusterId);
             if (isValid())
                 clearAttributes();
         }
@@ -399,7 +397,6 @@ public abstract class AbstractSession implements AbstractSessionManager.SessionI
     }
     
     /* ------------------------------------------------------------ */
-    @SuppressWarnings({ "unchecked" })
     @Override
     public Enumeration<String> getAttributeNames()
     {
index 9414408338bc2355fa765e1a554993f01c1f9db9..9d482701ef00458719e976ea888ab6708afebdf7 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -167,7 +167,8 @@ public abstract class AbstractSessionIdManager extends AbstractLifeCycle impleme
             // random chance to reseed
             if (_reseed>0 && (r0%_reseed)== 1L)
             {
-                LOG.debug("Reseeding {}",this);
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Reseeding {}",this);
                 if (_random instanceof SecureRandom)
                 {
                     SecureRandom secure = (SecureRandom)_random;
index 1f966c5957d68b59b39a2a439ddd082cf08b0269..d25394649037f0fb5fb618011484a85c388c81d4 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -227,10 +227,10 @@ public abstract class AbstractSessionManager extends ContainerLifeCycle implemen
         _context=ContextHandler.getCurrentContext();
         _loader=Thread.currentThread().getContextClassLoader();
 
-        if (_sessionIdManager==null)
+        final Server server=getSessionHandler().getServer();
+        synchronized (server)
         {
-            final Server server=getSessionHandler().getServer();
-            synchronized (server)
+            if (_sessionIdManager==null)
             {
                 _sessionIdManager=server.getSessionIdManager();
                 if (_sessionIdManager==null)
@@ -575,6 +575,9 @@ public abstract class AbstractSessionManager extends ContainerLifeCycle implemen
             _sessionAttributeListeners.remove(listener);
         if (listener instanceof HttpSessionListener)
             _sessionListeners.remove(listener);
+        if (listener instanceof HttpSessionIdListener)
+            _sessionIdListeners.remove(listener);
+        removeBean(listener);
     }
     
     /* ------------------------------------------------------------ */
index a17bc06f7683b02cab295cf30fba470eb9b2da48..fd2aa4d9cf6870c9da347e74311ef51d145da262 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -32,8 +32,6 @@ import java.util.Set;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
 
-import org.eclipse.jetty.server.SessionIdManager;
-
 /* ------------------------------------------------------------ */
 /**
  * HashSessionIdManager. An in-memory implementation of the session ID manager.
index 1effd32f94b87979200addce4ad7c50eb94bba49..33962329f7331b3dd67fbe92f1a189cb192ef854 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -19,7 +19,6 @@
 package org.eclipse.jetty.server.session;
 
 import java.io.DataInputStream;
-import java.io.EOFException;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
@@ -34,10 +33,8 @@ import java.util.concurrent.TimeUnit;
 import javax.servlet.ServletContext;
 import javax.servlet.http.HttpServletRequest;
 
-import org.eclipse.jetty.server.SessionIdManager;
 import org.eclipse.jetty.server.handler.ContextHandler;
 import org.eclipse.jetty.util.ClassLoadingObjectInputStream;
-import org.eclipse.jetty.util.IO;
 import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
 import org.eclipse.jetty.util.thread.Scheduler;
@@ -88,8 +85,9 @@ public class HashSessionManager extends AbstractSessionManager
             }
             finally
             {
-                if (_timer != null && _timer.isRunning())
-                    _timer.schedule(this, _scavengePeriodMs, TimeUnit.MILLISECONDS);
+                if (_timer != null && _timer.isRunning()) {
+                    _task = _timer.schedule(this, _scavengePeriodMs, TimeUnit.MILLISECONDS);
+                }
             }
         }
     }
@@ -114,7 +112,7 @@ public class HashSessionManager extends AbstractSessionManager
             finally
             {
                 if (_timer != null && _timer.isRunning())
-                    _timer.schedule(this, _savePeriodMs, TimeUnit.MILLISECONDS);
+                    _saveTask = _timer.schedule(this, _savePeriodMs, TimeUnit.MILLISECONDS);
             }
         }        
     }
@@ -141,7 +139,7 @@ public class HashSessionManager extends AbstractSessionManager
             ServletContext context = ContextHandler.getCurrentContext();
             if (context!=null)
                 _timer = (Scheduler)context.getAttribute("org.eclipse.jetty.server.session.timer");   
-        }         
+        }    
       
         if (_timer == null)
         {
@@ -151,7 +149,7 @@ public class HashSessionManager extends AbstractSessionManager
         }
         else
             addBean(_timer,false);
-            
+        
         super.doStart();
 
         setScavengePeriod(getScavengePeriod());
@@ -180,12 +178,15 @@ public class HashSessionManager extends AbstractSessionManager
         {
             if (_saveTask!=null)
                 _saveTask.cancel();
+
             _saveTask=null;
             if (_task!=null)
                 _task.cancel();
+
             _task=null;
             _timer=null;
         }
+       
 
         // This will callback invalidate sessions - where we decide if we will save
         super.doStop();
@@ -308,15 +309,16 @@ public class HashSessionManager extends AbstractSessionManager
 
         _scavengePeriodMs=period;
     
-        if (_timer!=null && (period!=old_period || _task==null))
+        synchronized (this)
         {
-            synchronized (this)
+            if (_timer!=null && (period!=old_period || _task==null))
             {
                 if (_task!=null)
                 {
                     _task.cancel();
                     _task = null;
                 }
+
                 _task = _timer.schedule(new Scavenger(),_scavengePeriodMs, TimeUnit.MILLISECONDS);
             }
         }
@@ -569,18 +571,22 @@ public class HashSessionManager extends AbstractSessionManager
     {        
         File file = new File(_storeDir,idInCuster);
 
-        FileInputStream in = null;
         Exception error = null;
-        try
+        if (!file.exists())
         {
-            if (file.exists())
+            if (LOG.isDebugEnabled())
             {
-                in = new FileInputStream(file);
-                HashedSession session = restoreSession(in, null);
-                addSession(session, false);
-                session.didActivate();
-                return session;
+                LOG.debug("Not loading: {}",file);
             }
+            return null;
+        }
+        
+        try (FileInputStream in = new FileInputStream(file))
+        {
+            HashedSession session = restoreSession(in,null);
+            addSession(session,false);
+            session.didActivate();
+            return session;
         }
         catch (Exception e)
         {
@@ -588,8 +594,6 @@ public class HashSessionManager extends AbstractSessionManager
         }
         finally
         {
-            if (in != null) IO.close(in);
-            
             if (error != null)
             {
                 if (isDeleteUnrestorableSessions() && file.exists() && file.getParentFile().equals(_storeDir) )
@@ -603,7 +607,10 @@ public class HashSessionManager extends AbstractSessionManager
                 }
             }
             else
-               file.delete(); //delete successfully restored file
+            {
+                // delete successfully restored file
+                file.delete();
+            }
         }
         return null;
     }
@@ -641,8 +648,10 @@ public class HashSessionManager extends AbstractSessionManager
 
         if (session == null)
             session = (HashedSession)newSession(created, accessed, clusterId);
+        
         session.setRequests(requests);
 
+        // Attributes
         int size = di.readInt();
 
         restoreSessionAttributes(di, size, session);
@@ -652,7 +661,7 @@ public class HashSessionManager extends AbstractSessionManager
             int maxIdle = di.readInt();
             session.setMaxInactiveInterval(maxIdle);
         }
-        catch (EOFException e)
+        catch (IOException e)
         {
             LOG.debug("No maxInactiveInterval persisted for session "+clusterId);
             LOG.ignore(e);
@@ -661,12 +670,14 @@ public class HashSessionManager extends AbstractSessionManager
         return session;
     }
 
-    
+
+    @SuppressWarnings("resource")
     private void restoreSessionAttributes (InputStream is, int size, HashedSession session)
     throws Exception
     {
         if (size>0)
         {
+            // input stream should not be closed here
             ClassLoadingObjectInputStream ois =  new ClassLoadingObjectInputStream(is);
             for (int i=0; i<size;i++)
             {
index d36e4277e49aa858e2a1c48ad4de69d5085bbab1..04c02b08cd7eeede4eb0b13d479089d62abd8b90 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -145,24 +145,23 @@ public class HashedSession extends MemSession
     throws Exception
     {   
         File file = null;
-        FileOutputStream fos = null;
         if (!_saveFailed && _hashSessionManager._storeDir != null)
         {
-            try
+            file = new File(_hashSessionManager._storeDir, super.getId());
+            if (file.exists())
+            {
+                file.delete();
+            }
+
+            try(FileOutputStream fos = new FileOutputStream(file,false))
             {
-                file = new File(_hashSessionManager._storeDir, super.getId());
-                if (file.exists())
-                    file.delete();
-                file.createNewFile();
-                fos = new FileOutputStream(file);
                 save(fos);
-                IO.close(fos);
             }
             catch (Exception e)
             {
                 saveFailed(); // We won't try again for this session
-                if (fos != null) IO.close(fos);
-                if (file != null) file.delete(); // No point keeping the file if we didn't save the whole session
+                if (file != null) 
+                    file.delete(); // No point keeping the file if we didn't save the whole session
                 throw e;             
             }
         }
index 4c7227d7717a5323b5e30cf21c8479855458c48d..b5fedd26de72881e992c7935e482a1261394c783 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -297,7 +297,11 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
             if (_dbAdaptor == null)
                 throw new IllegalStateException ("No DBAdaptor");
             String longType = _dbAdaptor.getLongType();
-            return "alter table "+getTableName()+" add "+getMaxIntervalColumn()+" "+longType+" not null default "+MAX_INTERVAL_NOT_SET;
+            String stem = "alter table "+getTableName()+" add "+getMaxIntervalColumn()+" "+longType;
+            if (_dbAdaptor.getDBName().contains("oracle"))
+                return stem + " default "+ MAX_INTERVAL_NOT_SET + " not null";
+            else
+                return stem +" not null default "+ MAX_INTERVAL_NOT_SET;
         }
         
         private void checkNotNull(String s)
@@ -477,7 +481,8 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
         throws SQLException
         {
             _dbName = dbMeta.getDatabaseProductName().toLowerCase(Locale.ENGLISH);
-            LOG.debug ("Using database {}",_dbName);
+            if (LOG.isDebugEnabled())
+                LOG.debug ("Using database {}",_dbName);
             _isLower = dbMeta.storesLowerCaseIdentifiers();
             _isUpper = dbMeta.storesUpperCaseIdentifiers(); 
         }
@@ -603,7 +608,7 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
            finally
            {
                if (_scheduler != null && _scheduler.isRunning())
-                   _scheduler.schedule(this, _scavengeIntervalMs, TimeUnit.MILLISECONDS);
+                   _task = _scheduler.schedule(this, _scavengeIntervalMs, TimeUnit.MILLISECONDS);
            }
         }
     }
@@ -777,10 +782,10 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
         if (LOG.isDebugEnabled())
             LOG.debug("Scavenging every "+_scavengeIntervalMs+" ms");
         
-        //if (_timer!=null && (period!=old_period || _task==null))
-        if (_scheduler != null && (period!=old_period || _task==null))
+        synchronized (this)
         {
-            synchronized (this)
+            //if (_timer!=null && (period!=old_period || _task==null))
+            if (_scheduler != null && (period!=old_period || _task==null))
             {
                 if (_task!=null)
                     _task.cancel();
@@ -991,6 +996,8 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager
              _ownScheduler = true;
              _scheduler.start();
          }
+         else if (!_scheduler.isStarted())
+             throw new IllegalStateException("Shared scheduler not started");
   
         setScavengeInterval(getScavengeInterval());
     }
index dbe95335dae2067acbc3bd18484ee557c313734e..1680c1b8696a0a28be66b5d059a67596646722c6 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -37,10 +37,6 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
 
 import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpSessionEvent;
-import javax.servlet.http.HttpSessionListener;
-
-import org.eclipse.jetty.server.SessionIdManager;
 import org.eclipse.jetty.server.handler.ContextHandler;
 import org.eclipse.jetty.server.session.JDBCSessionIdManager.SessionTableSchema;
 import org.eclipse.jetty.util.ClassLoadingObjectInputStream;
@@ -512,17 +508,20 @@ public class JDBCSessionManager extends AbstractSessionManager
             {
                 if (memSession==null)
                 {
-                    LOG.debug("getSession("+idInCluster+"): no session in session map. Reloading session data from db.");
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("getSession("+idInCluster+"): no session in session map. Reloading session data from db.");
                     session = loadSession(idInCluster, canonicalize(_context.getContextPath()), getVirtualHost(_context));
                 }
                 else if ((now - memSession._lastSaved) >= (_saveIntervalSec * 1000L))
                 {
-                    LOG.debug("getSession("+idInCluster+"): stale session. Reloading session data from db.");
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("getSession("+idInCluster+"): stale session. Reloading session data from db.");
                     session = loadSession(idInCluster, canonicalize(_context.getContextPath()), getVirtualHost(_context));
                 }
                 else
                 {
-                    LOG.debug("getSession("+idInCluster+"): session in session map");
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("getSession("+idInCluster+"): session in session map");
                     session = memSession;
                 }
             }
@@ -562,7 +561,8 @@ public class JDBCSessionManager extends AbstractSessionManager
                     }
                     else
                     {
-                        LOG.debug("getSession ({}): Session has expired", idInCluster);  
+                        if (LOG.isDebugEnabled())
+                            LOG.debug("getSession ({}): Session has expired", idInCluster);
                         //ensure that the session id for the expired session is deleted so that a new session with the 
                         //same id cannot be created (because the idInUse() test would succeed)
                         _jdbcSessionIdMgr.removeSession(idInCluster);
@@ -574,7 +574,8 @@ public class JDBCSessionManager extends AbstractSessionManager
                 {
                     //the session loaded from the db and the one in memory are the same, so keep using the one in memory
                     session = memSession;
-                    LOG.debug("getSession({}): Session not stale {}", idInCluster,session);
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("getSession({}): Session not stale {}", idInCluster,session);
                 }
             }
             else
index 72dbea8fa8a81299498955543971d98afabdf15d..8ebed7ecafaaaab1b1e73b64b94d6766fb7e1435 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index e6aedc5b8c9cd2c3aba0e41df5ff334b04e5b13b..f89aaa46adc6bbfeffccc77f2ccdc13f50e5f15d 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -49,10 +49,12 @@ public class SessionHandler extends ScopedHandler
     final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session");
 
     public final static EnumSet<SessionTrackingMode> DEFAULT_TRACKING = EnumSet.of(SessionTrackingMode.COOKIE,SessionTrackingMode.URL);
-    
-    public static final Class[] SESSION_LISTENER_TYPES = new Class[] {HttpSessionAttributeListener.class,
-                                                                      HttpSessionIdListener.class,
-                                                                      HttpSessionListener.class};
+
+    @SuppressWarnings("unchecked")
+    public static final Class<? extends EventListener>[] SESSION_LISTENER_TYPES = 
+        new Class[] {HttpSessionAttributeListener.class,
+                     HttpSessionIdListener.class,
+                     HttpSessionListener.class};
 
 
 
@@ -262,7 +264,8 @@ public class SessionHandler extends ScopedHandler
                         requested_session_id = cookies[i].getValue();
                         requested_session_id_from_cookie = true;
 
-                        LOG.debug("Got Session ID {} from cookie",requested_session_id);
+                        if (LOG.isDebugEnabled())
+                            LOG.debug("Got Session ID {} from cookie",requested_session_id);
 
                         if (requested_session_id != null)
                         {
index ed180a183605ffd1add4b0b4750d697abd40d11a..fe4ece1f2d7767ddb664e881ff11a269edb60442 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index a32e1a619228081301d8088b087b38060be3157f..f0525b1253c1670a23c416e445d39fe5b221ce49 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index c3787395d38a7af67d0fcfd1d4600563b412c443..3909259eb19681cd532a31059e8b08d2d64da6bb 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -25,8 +25,10 @@ import java.io.OutputStream;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.nio.ByteBuffer;
+import java.util.ArrayList;
 import java.util.Enumeration;
 import java.util.List;
+import java.util.StringTokenizer;
 
 import javax.servlet.AsyncContext;
 import javax.servlet.RequestDispatcher;
@@ -67,6 +69,7 @@ import org.eclipse.jetty.util.resource.ResourceFactory;
 
 /* ------------------------------------------------------------ */
 /** The default servlet.
+ * 
  * This servlet, normally mapped to /, provides the handling for static
  * content, OPTION and TRACE methods for the context.
  * The following initParameters are supported, these can be set either
@@ -121,10 +124,14 @@ import org.eclipse.jetty.util.resource.ResourceFactory;
  *                    If set to true, it will use mapped file buffer to serve static content
  *                    when using NIO connector. Setting this value to false means that
  *                    a direct buffer will be used instead of a mapped file buffer.
- *                    By default, this is set to true.
+ *                    This is set to false by default by this class, but may be overridden
+ *                    by eg webdefault.xml 
  *
  *  cacheControl      If set, all static content will have this value set as the cache-control
  *                    header.
+ *                    
+ * otherGzipFileExtensions
+ *                    Other file extensions that signify that a file is gzip compressed. Eg ".svgz"
  *
  *
  * </PRE>
@@ -164,6 +171,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
     private String _relativeResourceBase;
     private ServletHandler _servletHandler;
     private ServletHolder _defaultHolder;
+    private List<String> _gzipEquivalentFileExtensions;
 
     /* ------------------------------------------------------------ */
     @Override
@@ -249,18 +257,19 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
                 throw new UnavailableException("resourceCache specified with resource bases");
             _cache=(ResourceCache)_servletContext.getAttribute(resourceCache);
 
-            LOG.debug("Cache {}={}",resourceCache,_cache);
+            if (LOG.isDebugEnabled())
+                LOG.debug("Cache {}={}",resourceCache,_cache);
         }
 
         _etags = getInitBoolean("etags",_etags);
         
         try
         {
-            if (_cache==null && max_cached_files>0)
+            if (_cache==null && (max_cached_files!=-2 || max_cache_size!=-2 || max_cached_file_size!=-2))
             {
                 _cache= new ResourceCache(null,this,_mimeTypes,_useFileMappedBuffer,_etags);
 
-                if (max_cache_size>0)
+                if (max_cache_size>=0)
                     _cache.setMaxCacheSize(max_cache_size);
                 if (max_cached_file_size>=-1)
                     _cache.setMaxCachedFileSize(max_cached_file_size);
@@ -273,15 +282,33 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
             LOG.warn(Log.EXCEPTION,e);
             throw new UnavailableException(e.toString());
         }
-
-        _servletHandler= _contextHandler.getChildHandlerByClass(ServletHandler.class);
-        for (ServletHolder h :_servletHandler.getServlets())
-            if (h.getServletInstance()==this)
-                _defaultHolder=h;
-
         
-        if (LOG.isDebugEnabled())
-            LOG.debug("resource base = "+_resourceBase);
+       _gzipEquivalentFileExtensions = new ArrayList<String>();
+       String otherGzipExtensions = getInitParameter("otherGzipFileExtensions");
+       if (otherGzipExtensions != null)
+       {
+           //comma separated list
+           StringTokenizer tok = new StringTokenizer(otherGzipExtensions,",",false);
+           while (tok.hasMoreTokens())
+           {
+               String s = tok.nextToken().trim();
+               _gzipEquivalentFileExtensions.add((s.charAt(0)=='.'?s:"."+s));
+           }
+       }
+       else
+       {
+           //.svgz files are gzipped svg files and must be served with Content-Encoding:gzip
+           _gzipEquivalentFileExtensions.add(".svgz");   
+       }
+
+       _servletHandler= _contextHandler.getChildHandlerByClass(ServletHandler.class);
+       for (ServletHolder h :_servletHandler.getServlets())
+           if (h.getServletInstance()==this)
+               _defaultHolder=h;
+
+
+       if (LOG.isDebugEnabled())
+           LOG.debug("resource base = "+_resourceBase);
     }
 
     /**
@@ -426,6 +453,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
         // Find the resource and content
         Resource resource=null;
         HttpContent content=null;
+        boolean close_content=true;
         try
         {
             // is gzip enabled?
@@ -469,7 +497,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
             }
 
             if (LOG.isDebugEnabled())
-                LOG.debug("uri="+request.getRequestURI()+" resource="+resource+(content!=null?" content":""));
+                LOG.debug(String.format("uri=%s, resource=%s, content=%s",request.getRequestURI(),resource,content));
 
             // Handle resource
             if (resource==null || !resource.exists())
@@ -496,14 +524,14 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
 
                     if (included.booleanValue() || passConditionalHeaders(request,response, resource,content))
                     {
-                        if (gzip)
+                        if (gzip || isGzippedContent(pathInContext))
                         {
                             response.setHeader(HttpHeader.CONTENT_ENCODING.asString(),"gzip");
                             String mt=_servletContext.getMimeType(pathInContext);
                             if (mt!=null)
                                 response.setContentType(mt);
                         }
-                        sendData(request,response,included.booleanValue(),resource,content,reqRanges);
+                        close_content=sendData(request,response,included.booleanValue(),resource,content,reqRanges);
                     }
                 }
             }
@@ -534,7 +562,8 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
                 // else look for a welcome file
                 else if (null!=(welcome=getWelcomeFile(pathInContext)))
                 {
-                    LOG.debug("welcome={}",welcome);
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("welcome={}",welcome);
                     if (_redirectWelcome)
                     {
                         // Redirect to the index
@@ -577,14 +606,31 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
         }
         finally
         {
-            if (content!=null)
-                content.release();
-            else if (resource!=null)
-                resource.close();
+            if (close_content)
+            {
+                if (content!=null)
+                    content.release();
+                else if (resource!=null)
+                    resource.close();
+            }
         }
 
     }
 
+    /**
+     * @param resource
+     * @return
+     */
+    protected boolean isGzippedContent(String path)
+    {
+        if (path == null) return false;
+      
+        for (String suffix:_gzipEquivalentFileExtensions)
+            if (path.endsWith(suffix))
+                return true;
+        return false;
+    }
+
     /* ------------------------------------------------------------ */
     private boolean hasDefinedRange(Enumeration<String> reqRanges)
     {
@@ -814,16 +860,16 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
     }
 
     /* ------------------------------------------------------------ */
-    protected void sendData(HttpServletRequest request,
+    protected boolean sendData(HttpServletRequest request,
             HttpServletResponse response,
             boolean include,
             Resource resource,
-            HttpContent content,
+            final HttpContent content,
             Enumeration<String> reqRanges)
     throws IOException
     {
         final long content_length = (content==null)?resource.length():content.getContentLength();
-
+        
         // Get the output stream (or writer)
         OutputStream out =null;
         boolean written;
@@ -841,6 +887,9 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
             out = new WriterOutputStream(response.getWriter());
             written=true; // there may be data in writer buffer, so assume written
         }
+        
+        if (LOG.isDebugEnabled())
+            LOG.debug(String.format("sendData content=%s out=%s async=%b",content,out,request.isAsyncSupported()));
 
         if ( reqRanges == null || !reqRanges.hasMoreElements() || content_length<0)
         {
@@ -877,6 +926,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
                 if (request.isAsyncSupported())
                 {
                     final AsyncContext context = request.startAsync();
+                    context.setTimeout(0);
 
                     ((HttpOutput)out).sendContent(content,new Callback()
                     {
@@ -884,6 +934,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
                         public void succeeded()
                         {   
                             context.complete();
+                            content.release();
                         }
 
                         @Override
@@ -894,14 +945,20 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
                             else
                                 LOG.warn(x);
                             context.complete();
+                            content.release();
+                        }
+                        
+                        @Override
+                        public String toString() 
+                        {
+                            return String.format("DefaultServlet@%x$CB", DefaultServlet.this.hashCode());
                         }
                     });
+                    return false;
                 }
                 // otherwise write content blocking
-                else
-                {
-                    ((HttpOutput)out).sendContent(content);
-                }
+                ((HttpOutput)out).sendContent(content);
+                
             }
         }
         else
@@ -917,7 +974,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
                 response.setHeader(HttpHeader.CONTENT_RANGE.asString(),
                         InclusiveByteRange.to416HeaderRangeString(content_length));
                 resource.writeTo(out,0,content_length);
-                return;
+                return true;
             }
 
             //  if there is only a single valid range (must be satisfiable
@@ -933,7 +990,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
                 response.setHeader(HttpHeader.CONTENT_RANGE.asString(),
                         singleSatisfiableRange.toHeaderRangeString(content_length));
                 resource.writeTo(out,singleSatisfiableRange.getFirst(content_length),singleLength);
-                return;
+                return true;
             }
 
             //  multiple non-overlapping valid ranges cause a multipart
@@ -1013,12 +1070,20 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
                 in.close();
             multi.close();
         }
-        return;
+        return true;
     }
 
     /* ------------------------------------------------------------ */
     protected void writeHeaders(HttpServletResponse response,HttpContent content,long count)
-    {        
+    {
+        if (content == null)
+        {
+            // No content, then no headers to process
+            // This is possible during bypass write because of wrapping
+            // See .sendData() for more details.
+            return;
+        }
+        
         if (content.getContentType()!=null && response.getContentType()==null)
             response.setContentType(content.getContentType().toString());
 
index b8efeb18d747ce5523fdb00ede0aa3612a4abd1d..976fb34ac2e4e13477e4ebb2facb5cfe4a45c169 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index d9635fae0e3a19780bb7d001b902b979c50c7d92..cb6210c52fc3e34d35ad305c4ce73251183c3ea4 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -133,7 +133,8 @@ public class FilterHolder extends Holder<Filter>
         }
 
         _config=new Config();
-        LOG.debug("Filter.init {}",_filter);
+        if (LOG.isDebugEnabled())
+            LOG.debug("Filter.init {}",_filter);
         _filter.init(_config);
     }
 
index 1d5a9a4205473f69c0b488539cd7a6ffaa5f67ff..749928cb8ff826cc0a557524d3e58f84ea0abb37 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -24,7 +24,6 @@ import java.util.EnumSet;
 import javax.servlet.DispatcherType;
 
 import org.eclipse.jetty.http.PathMap;
-import org.eclipse.jetty.server.Handler;
 import org.eclipse.jetty.util.TypeUtil;
 import org.eclipse.jetty.util.annotation.ManagedAttribute;
 import org.eclipse.jetty.util.annotation.ManagedObject;
@@ -67,19 +66,19 @@ public class FilterMapping implements Dumpable
      */
     public static int dispatch(DispatcherType type)
     {
-       switch(type)
-       {
-         case REQUEST:
-                 return REQUEST;
-         case ASYNC:
-                 return ASYNC;
-         case FORWARD:
-                 return FORWARD;
-         case INCLUDE:
-                 return INCLUDE;
-         case ERROR:
-                 return ERROR;
-       }
+        switch(type)
+        {
+          case REQUEST:
+                  return REQUEST;
+          case ASYNC:
+                  return ASYNC;
+          case FORWARD:
+                  return FORWARD;
+          case INCLUDE:
+                  return INCLUDE;
+          case ERROR:
+                  return ERROR;
+        }
         throw new IllegalArgumentException(type.toString());
     }
 
@@ -124,8 +123,8 @@ public class FilterMapping implements Dumpable
      */
     boolean appliesTo(int type)
     {
-       if (_dispatches==0)
-               return type==REQUEST || type==ASYNC && _holder.isAsyncSupported();
+        if (_dispatches==0)
+                return type==REQUEST || type==ASYNC && _holder.isAsyncSupported();
         return (_dispatches&type)!=0;
     }
 
index 2f690b17b59c6b0c5fd01dfdb3d4eb2f15795bf3..2c8fa7ba085b872a2ee3b0a7e3c98089bd9aafac 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -89,7 +89,7 @@ public class Holder<T> extends BaseHolder<T>
     }
 
     /* ------------------------------------------------------------ */
-    public Enumeration getInitParameterNames()
+    public Enumeration<String> getInitParameterNames()
     {
         if (_initParams==null)
             return Collections.enumeration(Collections.EMPTY_LIST);
@@ -227,7 +227,7 @@ public class Holder<T> extends BaseHolder<T>
         }
 
         /* -------------------------------------------------------- */
-        public Enumeration getInitParameterNames()
+        public Enumeration<String> getInitParameterNames()
         {
             return Holder.this.getInitParameterNames();
         }
index 4613144bafd48f4df20b6236e02583e5777df0cc..52d9bea6a7575d508becce9368e73df708714170 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -72,8 +72,8 @@ public class Invoker extends HttpServlet
 
     private ContextHandler _contextHandler;
     private ServletHandler _servletHandler;
-    private Map.Entry _invokerEntry;
-    private Map _parameters;
+    private Map.Entry<String, ServletHolder> _invokerEntry;
+    private Map<String, String> _parameters;
     private boolean _nonContextServlets;
     private boolean _verbose;
 
@@ -87,10 +87,10 @@ public class Invoker extends HttpServlet
         while (handler!=null && !(handler instanceof ServletHandler) && (handler instanceof HandlerWrapper))
             handler=((HandlerWrapper)handler).getHandler();
         _servletHandler = (ServletHandler)handler;
-        Enumeration e = getInitParameterNames();
+        Enumeration<String> e = getInitParameterNames();
         while(e.hasMoreElements())
         {
-            String param=(String)e.nextElement();
+            String param=e.nextElement();
             String value=getInitParameter(param);
             String lvalue=value.toLowerCase(Locale.ENGLISH);
             if ("nonContextServlets".equals(param))
@@ -104,7 +104,7 @@ public class Invoker extends HttpServlet
             else
             {
                 if (_parameters==null)
-                    _parameters=new HashMap();
+                    _parameters=new HashMap<String, String>();
                 _parameters.put(param,value);
             }
         }
@@ -112,7 +112,7 @@ public class Invoker extends HttpServlet
 
     /* ------------------------------------------------------------ */
     protected void service(HttpServletRequest request, HttpServletResponse response)
-       throws ServletException, IOException
+        throws ServletException, IOException
     {
         // Get the requested path and info
         boolean included=false;
@@ -151,7 +151,7 @@ public class Invoker extends HttpServlet
             ServletMapping mapping = new ServletMapping();
             mapping.setServletName(servlet);
             mapping.setPathSpec(URIUtil.addPaths(servlet_path,servlet)+"/*");
-            _servletHandler.setServletMappings((ServletMapping[])ArrayUtil.addToArray(_servletHandler.getServletMappings(), mapping, ServletMapping.class));
+            _servletHandler.setServletMappings(ArrayUtil.addToArray(_servletHandler.getServletMappings(), mapping, ServletMapping.class));
         }
         else
         {
@@ -171,7 +171,7 @@ public class Invoker extends HttpServlet
 
                 // Check for existing mapping (avoid threaded race).
                 String path=URIUtil.addPaths(servlet_path,servlet);
-                Map.Entry entry = _servletHandler.getHolderEntry(path);
+                Map.Entry<String, ServletHolder> entry = _servletHandler.getHolderEntry(path);
 
                 if (entry!=null && !entry.equals(_invokerEntry))
                 {
index d0fcbfe1c7b34f2af1730137c9baa5e818c44c69..aa14e2c3dd2d23bba2c14490e8e1a5ab39541eb7 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -19,6 +19,7 @@
 package org.eclipse.jetty.servlet;
 
 import java.io.IOException;
+import java.util.Locale;
 
 import javax.servlet.GenericServlet;
 import javax.servlet.ServletException;
@@ -35,37 +36,37 @@ import org.eclipse.jetty.util.resource.Resource;
 /* ------------------------------------------------------------ */
 /** Servlet handling JSP Property Group mappings
  * <p>
- * This servlet is mapped to by any URL pattern for a JSP property group. 
+ * This servlet is mapped to by any URL pattern for a JSP property group.
  * Resources handled by this servlet that are not directories will be passed
- * directly to the JSP servlet.    Resources that are directories will be 
+ * directly to the JSP servlet.    Resources that are directories will be
  * passed directly to the default servlet.
  */
 public class JspPropertyGroupServlet extends GenericServlet
 {
     private static final long serialVersionUID = 3681783214726776945L;
-    
+
     public final static String NAME = "__org.eclipse.jetty.servlet.JspPropertyGroupServlet__";
     private final ServletHandler _servletHandler;
     private final ContextHandler _contextHandler;
     private ServletHolder _dftServlet;
     private ServletHolder _jspServlet;
     private boolean _starJspMapped;
-    
+
     public JspPropertyGroupServlet(ContextHandler context, ServletHandler servletHandler)
     {
         _contextHandler=context;
-        _servletHandler=servletHandler;        
+        _servletHandler=servletHandler;
     }
-    
+
     @Override
     public void init() throws ServletException
-    {            
+    {
         String jsp_name = "jsp";
         ServletMapping servlet_mapping =_servletHandler.getServletMapping("*.jsp");
         if (servlet_mapping!=null)
         {
             _starJspMapped=true;
-           
+
             //now find the jsp servlet, ignoring the mapping that is for ourself
             ServletMapping[] mappings = _servletHandler.getServletMappings();
             for (ServletMapping m:mappings)
@@ -80,11 +81,11 @@ public class JspPropertyGroupServlet extends GenericServlet
                     }
                 }
             }
-            
+
             jsp_name=servlet_mapping.getServletName();
         }
         _jspServlet=_servletHandler.getServlet(jsp_name);
-        
+
         String dft_name="default";
         ServletMapping default_mapping=_servletHandler.getServletMapping("/");
         if (default_mapping!=null)
@@ -94,7 +95,7 @@ public class JspPropertyGroupServlet extends GenericServlet
 
     @Override
     public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException
-    {           
+    {
         HttpServletRequest request = null;
         if (req instanceof HttpServletRequest)
             request = (HttpServletRequest)req;
@@ -118,27 +119,27 @@ public class JspPropertyGroupServlet extends GenericServlet
             servletPath = request.getServletPath();
             pathInfo = request.getPathInfo();
         }
-        
+
         String pathInContext=URIUtil.addPaths(servletPath,pathInfo);
-        
+
         if (pathInContext.endsWith("/"))
         {
             _dftServlet.getServlet().service(req,res);
         }
-        else if (_starJspMapped && pathInContext.toLowerCase().endsWith(".jsp"))
+        else if (_starJspMapped && pathInContext.toLowerCase(Locale.ENGLISH).endsWith(".jsp"))
         {
             _jspServlet.getServlet().service(req,res);
         }
         else
         {
-         
+
             Resource resource = _contextHandler.getResource(pathInContext);
             if (resource!=null && resource.isDirectory())
                 _dftServlet.getServlet().service(req,res);
             else
                 _jspServlet.getServlet().service(req,res);
         }
-        
+
     }
 
 }
index 346d47888dd4fb969a6167ab7807c248d8f46c8b..c306b13f1c98e139f288bc14ea56c47959995495 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index afd066bb181754e6a86a29a08c386930ff9144ae..d4ee4a8c0062cf6d28d338a3c54a17a8852f2664 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index d01ddd2a269f5368b60c53f2faafeedf9a7465c3..013ab5c87fb96adbe02dc00e79142d397cf35268 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -35,8 +35,6 @@ import javax.servlet.Filter;
 import javax.servlet.FilterRegistration;
 import javax.servlet.RequestDispatcher;
 import javax.servlet.Servlet;
-import javax.servlet.ServletContainerInitializer;
-import javax.servlet.ServletContext;
 import javax.servlet.ServletContextEvent;
 import javax.servlet.ServletContextListener;
 import javax.servlet.ServletException;
@@ -290,9 +288,9 @@ public class ServletContextHandler extends ContextHandler
                         decorator.decorate(holder.getListener());
                     }
                 }
-           }
-       }
-       
+            }
+        }
+        
         super.startContext();
 
         // OK to Initialize servlet handler now that all relevant object trees have been started
index 81243e01e78fad2aef2dc1b9c3f607b45b3fb5e5..d5b2add177957fe611546c55e37d8bed88d4c187 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -116,8 +116,6 @@ public class ServletHandler extends ScopedHandler
 
     private ServletHolder[] _servlets=new ServletHolder[0];
     private ServletMapping[] _servletMappings;
-    private Map<String,ServletMapping> _servletPathMappings = new HashMap<String,ServletMapping>();
-
     private final Map<String,FilterHolder> _filterNameMap= new HashMap<>();
     private List<FilterMapping> _filterPathMappings;
     private MultiMap<FilterMapping> _filterNameMappings;
@@ -127,9 +125,12 @@ public class ServletHandler extends ScopedHandler
     
     private ListenerHolder[] _listeners=new ListenerHolder[0];
 
-    protected final ConcurrentMap<?, ?> _chainCache[] = new ConcurrentMap[FilterMapping.ALL];
-    protected final Queue<?>[] _chainLRU = new Queue[FilterMapping.ALL];
-    
+    @SuppressWarnings("unchecked")
+    protected final ConcurrentMap<String, FilterChain> _chainCache[] = new ConcurrentMap[FilterMapping.ALL];
+
+    @SuppressWarnings("unchecked")
+    protected final Queue<String>[] _chainLRU = new Queue[FilterMapping.ALL];
+
 
 
     /* ------------------------------------------------------------ */
@@ -160,7 +161,8 @@ public class ServletHandler extends ScopedHandler
         
         if (getServletMapping("/")==null && _ensureDefaultServlet)
         {
-            LOG.debug("Adding Default404Servlet to {}",this);
+            if (LOG.isDebugEnabled())
+                LOG.debug("Adding Default404Servlet to {}",this);
             addServletWithMapping(Default404Servlet.class,"/");
             updateMappings();  
             getServletMapping("/").setDefault(true);
@@ -339,7 +341,6 @@ public class ServletHandler extends ScopedHandler
         _filterPathMappings=null;
         _filterNameMappings=null;
         _servletPathMap=null;
-        _servletPathMappings=null;
     }
 
     /* ------------------------------------------------------------ */
@@ -414,10 +415,26 @@ public class ServletHandler extends ScopedHandler
      */
     public ServletMapping getServletMapping(String pathSpec)
     {
-        if (pathSpec == null || _servletPathMappings == null)
+        if (pathSpec == null || _servletMappings == null)
             return null;
         
-        return _servletPathMappings.get(pathSpec);
+        ServletMapping mapping = null;
+        for (int i=0; i<_servletMappings.length && mapping == null; i++)
+        {
+            ServletMapping m = _servletMappings[i];
+            if (m.getPathSpecs() != null)
+            {
+                for (String p:m.getPathSpecs())
+                {
+                    if (pathSpec.equals(p))
+                    {
+                        mapping = m;
+                        break;
+                    }
+                }
+            }
+        }
+        return mapping;
     }
     
     /* ------------------------------------------------------------ */
@@ -543,7 +560,9 @@ public class ServletHandler extends ScopedHandler
             }
         }
 
-        LOG.debug("chain={}",chain);
+        if (LOG.isDebugEnabled())
+            LOG.debug("chain={}",chain);
+
         Throwable th=null;
         try
         {
@@ -560,6 +579,8 @@ public class ServletHandler extends ScopedHandler
                     res = ((ServletResponseHttpWrapper)res).getResponse();
 
                 // Do the filter/handling thang
+                servlet_holder.prepare(baseRequest, req, res);
+                
                 if (chain!=null)
                     chain.doFilter(req, res);
                 else
@@ -729,26 +750,26 @@ public class ServletHandler extends ScopedHandler
             if (filters.size() > 0)
                 chain= new CachedChain(filters, servletHolder);
 
-            final Map<String,FilterChain> cache=(Map<String, FilterChain>)_chainCache[dispatch];
-            final Queue<String> lru=(Queue<String>)_chainLRU[dispatch];
-
-               // Do we have too many cached chains?
-               while (_maxFilterChainsCacheSize>0 && cache.size()>=_maxFilterChainsCacheSize)
-               {
-                   // The LRU list is not atomic with the cache map, so be prepared to invalidate if
-                   // a key is not found to delete.
-                   // Delete by LRU (where U==created)
-                   String k=lru.poll();
-                   if (k==null)
-                   {
-                       cache.clear();
-                       break;
-                   }
-                   cache.remove(k);
-               }
-
-               cache.put(key,chain);
-               lru.add(key);
+            final Map<String,FilterChain> cache=_chainCache[dispatch];
+            final Queue<String> lru=_chainLRU[dispatch];
+
+                // Do we have too many cached chains?
+                while (_maxFilterChainsCacheSize>0 && cache.size()>=_maxFilterChainsCacheSize)
+                {
+                    // The LRU list is not atomic with the cache map, so be prepared to invalidate if
+                    // a key is not found to delete.
+                    // Delete by LRU (where U==created)
+                    String k=lru.poll();
+                    if (k==null)
+                    {
+                        cache.clear();
+                        break;
+                    }
+                    cache.remove(k);
+                }
+
+                cache.put(key,chain);
+                lru.add(key);
         }
         else if (filters.size() > 0)
             chain = new Chain(baseRequest,filters, servletHolder);
@@ -846,18 +867,6 @@ public class ServletHandler extends ScopedHandler
             {
                 try
                 {
-                   /* if (servlet.getClassName() == null && servlet.getForcedPath() != null)
-                    {
-                        ServletHolder forced_holder = _servletPathMap.match(servlet.getForcedPath());
-                        if (forced_holder == null || forced_holder.getClassName() == null)
-                        {
-                            mx.add(new IllegalStateException("No forced path servlet for " + servlet.getForcedPath()));
-                            continue;
-                        }
-                        System.err.println("ServletHandler setting forced path classname to "+forced_holder.getClassName()+ " for "+servlet.getForcedPath());
-                        servlet.setClassName(forced_holder.getClassName());
-                    }*/
-                    
                     servlet.start();
                     servlet.initialize();
                 }
@@ -1452,9 +1461,7 @@ public class ServletHandler extends ScopedHandler
                 //for each path, look at the mappings where it is referenced
                 //if a mapping is for a servlet that is not enabled, skip it
                 Set<ServletMapping> mappings = sms.get(pathSpec);
-                
-                
-           
+
                 ServletMapping finalMapping = null;
                 for (ServletMapping mapping : mappings)
                 {
@@ -1492,7 +1499,6 @@ public class ServletHandler extends ScopedHandler
             }
      
             _servletPathMap=pm;
-            _servletPathMappings=servletPathMappings;
         }
 
         // flush filter chain cache
@@ -1528,7 +1534,8 @@ public class ServletHandler extends ScopedHandler
     /* ------------------------------------------------------------ */
     protected void notFound(Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
     {
-        LOG.debug("Not Found {}",request.getRequestURI());
+        if (LOG.isDebugEnabled())
+            LOG.debug("Not Found {}",request.getRequestURI());
         if (getHandler()!=null)
             nextHandle(URIUtil.addPaths(request.getServletPath(),request.getPathInfo()),baseRequest,request,response);
     }
@@ -1550,7 +1557,7 @@ public class ServletHandler extends ScopedHandler
     {
         updateBeans(_filterMappings,filterMappings);
         _filterMappings = filterMappings;
-        updateMappings();
+        if (isStarted()) updateMappings();
         invalidateChainsCache();
     }
 
@@ -1575,7 +1582,7 @@ public class ServletHandler extends ScopedHandler
     {
         updateBeans(_servletMappings,servletMappings);
         _servletMappings = servletMappings;
-        updateMappings();
+        if (isStarted()) updateMappings();
         invalidateChainsCache();
     }
 
@@ -1630,27 +1637,23 @@ public class ServletHandler extends ScopedHandler
             // pass to next filter
             if (_filterHolder!=null)
             {
-                LOG.debug("call filter {}", _filterHolder);
+                if (LOG.isDebugEnabled())
+                    LOG.debug("call filter {}", _filterHolder);
                 Filter filter= _filterHolder.getFilter();
-                if (_filterHolder.isAsyncSupported())
+                
+                //if the request already does not support async, then the setting for the filter
+                //is irrelevant. However if the request supports async but this filter does not
+                //temporarily turn it off for the execution of the filter
+                boolean requestAsyncSupported = baseRequest.isAsyncSupported();
+                try
+                {
+                    if (!_filterHolder.isAsyncSupported() && requestAsyncSupported)
+                        baseRequest.setAsyncSupported(false);
                     filter.doFilter(request, response, _next);
-                else
+                }
+                finally
                 {
-                    final boolean suspendable=baseRequest.isAsyncSupported();
-                    if (suspendable)
-                    {
-                        try
-                        {
-                            baseRequest.setAsyncSupported(false);
-                            filter.doFilter(request, response, _next);
-                        }
-                        finally
-                        {
-                            baseRequest.setAsyncSupported(true);
-                        }
-                    }
-                    else
-                        filter.doFilter(request, response, _next);
+                    baseRequest.setAsyncSupported(requestAsyncSupported);
                 }
                 return;
             }
@@ -1711,23 +1714,20 @@ public class ServletHandler extends ScopedHandler
                     LOG.debug("call filter " + holder);
                 Filter filter= holder.getFilter();
 
-                if (holder.isAsyncSupported() || !_baseRequest.isAsyncSupported())
+                //if the request already does not support async, then the setting for the filter
+                //is irrelevant. However if the request supports async but this filter does not
+                //temporarily turn it off for the execution of the filter
+                boolean requestAsyncSupported = _baseRequest.isAsyncSupported();
+                try
                 {
+                    if (!holder.isAsyncSupported() && requestAsyncSupported)
+                        _baseRequest.setAsyncSupported(false);
                     filter.doFilter(request, response, this);
                 }
-                else
+                finally
                 {
-                    try
-                    {
-                        _baseRequest.setAsyncSupported(false);
-                        filter.doFilter(request, response, this);
-                    }
-                    finally
-                    {
-                        _baseRequest.setAsyncSupported(true);
-                    }
+                    _baseRequest.setAsyncSupported(requestAsyncSupported);
                 }
-
                 return;
             }
 
@@ -1737,7 +1737,8 @@ public class ServletHandler extends ScopedHandler
                 notFound((request instanceof Request)?((Request)request):HttpChannel.getCurrentHttpChannel().getRequest(), srequest, (HttpServletResponse)response);
             else
             {
-                LOG.debug("call servlet {}", _servletHolder);
+                if (LOG.isDebugEnabled())
+                    LOG.debug("call servlet {}", _servletHolder);
                 _servletHolder.handle(_baseRequest,request, response);
             }    
         }
index 1df08b33dc6d793e558a4bc736fe88d8dcad780b..73e1ccf864faa4a0ab62e1e75c5e9a15d82187d6 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -18,6 +18,7 @@
 
 package org.eclipse.jetty.servlet;
 
+import java.io.File;
 import java.io.IOException;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
@@ -69,18 +70,19 @@ import org.eclipse.jetty.util.log.Logger;
 @ManagedObject("Servlet Holder")
 public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope, Comparable<ServletHolder>
 {
-    private static final Logger LOG = Log.getLogger(ServletHolder.class);
 
     /* ---------------------------------------------------------------- */
+    private static final Logger LOG = Log.getLogger(ServletHolder.class);
     private int _initOrder = -1;
     private boolean _initOnStartup=false;
+    private boolean _initialized = false;
     private Map<String, String> _roleMap;
     private String _forcedPath;
     private String _runAsRole;
     private RunAsToken _runAsToken;
     private IdentityService _identityService;
     private ServletRegistration.Dynamic _registration;
-
+    private JspContainer _jspContainer;
 
     private transient Servlet _servlet;
     private transient Config _config;
@@ -88,8 +90,11 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
     private transient boolean _enabled = true;
     private transient UnavailableException _unavailableEx;
 
+    public static final String GLASSFISH_SENTINEL_CLASS = "org.glassfish.jsp.api.ResourceInjector";
+    public static final String APACHE_SENTINEL_CLASS = "org.apache.tomcat.InstanceManager";
     public static final  String JSP_GENERATED_PACKAGE_NAME = "org.eclipse.jetty.servlet.jspPackagePrefix";
     public static final Map<String,String> NO_MAPPED_ROLES = Collections.emptyMap();
+    public static enum JspContainer {GLASSFISH, APACHE, OTHER}; 
 
     /* ---------------------------------------------------------------- */
     /** Constructor .
@@ -289,11 +294,13 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
         {
             // Look for a precompiled JSP Servlet
             String precompiled=getClassNameForJsp(_forcedPath);
-            LOG.debug("Checking for precompiled servlet {} for jsp {}", precompiled, _forcedPath);
+            if (LOG.isDebugEnabled())
+                LOG.debug("Checking for precompiled servlet {} for jsp {}", precompiled, _forcedPath);
             ServletHolder jsp=getServletHandler().getServlet(precompiled);
-            if (jsp!=null)
+            if (jsp!=null && jsp.getClassName() !=  null)
             {
-                LOG.debug("JSP file {} for {} mapped to Servlet {}",_forcedPath, getName(),jsp.getClassName());
+                if (LOG.isDebugEnabled())
+                    LOG.debug("JSP file {} for {} mapped to Servlet {}",_forcedPath, getName(),jsp.getClassName());
                 // set the className for this servlet to the precompiled one
                 setClassName(jsp.getClassName());
             }
@@ -305,7 +312,8 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
                     jsp=getServletHandler().getServlet("jsp");
                     if (jsp!=null)
                     {
-                        LOG.debug("JSP file {} for {} mapped to Servlet {}",_forcedPath, getName(),jsp.getClassName());
+                        if (LOG.isDebugEnabled())
+                            LOG.debug("JSP file {} for {} mapped to Servlet class {}",_forcedPath, getName(),jsp.getClassName());
                         setClassName(jsp.getClassName());
                         //copy jsp init params that don't exist for this servlet
                         for (Map.Entry<String, String> entry:jsp.getInitParameters().entrySet())
@@ -313,9 +321,11 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
                             if (!_initParams.containsKey(entry.getKey()))
                                 setInitParameter(entry.getKey(), entry.getValue());
                         }
-                        //jsp specific: set up the jsp-file on the JspServlet so it can precompile iff load-on-startup is >=0
-                        if (_initOnStartup)
-                            setInitParameter("jspFile", _forcedPath);
+                        //jsp specific: set up the jsp-file on the JspServlet. If load-on-startup is >=0 and the jsp container supports
+                        //precompilation, the jsp will be compiled when this holder is initialized. If not load on startup, or the
+                        //container does not support startup precompilation, it will be compiled at runtime when handling a request for this jsp.
+                        //See also adaptForcedPathToJspContainer
+                        setInitParameter("jspFile", _forcedPath);
                     }                       
                 }
             }
@@ -368,7 +378,7 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
 
         if (_class!=null && javax.servlet.SingleThreadModel.class.isAssignableFrom(_class))
             _servlet = new SingleThreadedWrapper();
-     
+
     }
     
     
@@ -377,21 +387,24 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
     public void initialize ()
     throws Exception
     {
-        super.initialize();
-        if (_extInstance || _initOnStartup)
-        {
-            try
-            {
-                initServlet();
-            }
-            catch(Exception e)
+        if(!_initialized){
+            super.initialize();
+            if (_extInstance || _initOnStartup)
             {
-                if (_servletHandler.isStartWithUnavailable())
-                    LOG.ignore(e);
-                else
-                    throw e;
+                try
+                {
+                    initServlet();
+                }
+                catch(Exception e)
+                {
+                    if (_servletHandler.isStartWithUnavailable())
+                        LOG.ignore(e);
+                    else
+                        throw e;
+                }
             }
         }
+        _initialized = true;
     }
     
     
@@ -424,6 +437,7 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
             _servlet=null;
 
         _config=null;
+        _initialized = false;
     }
 
     /* ------------------------------------------------------------ */
@@ -565,7 +579,7 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
 
     /* ------------------------------------------------------------ */
     private void initServlet()
-       throws ServletException
+        throws ServletException
     {
         Object old_run_as = null;
         try
@@ -587,11 +601,18 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
             if (isJspServlet())
             {
                 initJspServlet();
+                detectJspContainer();
             }
 
             initMultiPart();
 
-            LOG.debug("Filter.init {}",_servlet);
+            if (_forcedPath != null && _jspContainer == null)
+            {
+                detectJspContainer();
+            }
+
+            if (LOG.isDebugEnabled())
+                LOG.debug("Servlet.init {} for {}",_servlet,getName());
             _servlet.init(_config);
         }
         catch (UnavailableException e)
@@ -642,10 +663,23 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
         if ("?".equals(getInitParameter("classpath")))
         {
             String classpath = ch.getClassPath();
-            LOG.debug("classpath=" + classpath);
+            if (LOG.isDebugEnabled())
+                LOG.debug("classpath=" + classpath);
             if (classpath != null)
                 setInitParameter("classpath", classpath);
         }
+        
+        /* ensure scratch dir */
+        File scratch = null;
+        if (getInitParameter("scratchdir") == null)
+        {
+            File tmp = (File)getServletHandler().getServletContext().getAttribute(ServletContext.TEMPDIR);
+            scratch = new File(tmp, "jsp");
+            setInitParameter("scratchdir", scratch.getAbsolutePath());
+        }
+     
+        scratch = new File (getInitParameter("scratchdir"));
+        if (!scratch.exists()) scratch.mkdir();
     }
 
     /* ------------------------------------------------------------ */
@@ -701,9 +735,50 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
     {
         _runAsRole = role;
     }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * Prepare to service a request.
+     * 
+     * @param baseRequest
+     * @param request
+     * @param response
+     * @throws ServletException
+     * @throws UnavailableException
+     */
+    protected void prepare (Request baseRequest, ServletRequest request, ServletResponse response)
+    throws ServletException, UnavailableException
+    {
+        ensureInstance();
+        MultipartConfigElement mpce = ((Registration)getRegistration()).getMultipartConfig();
+        if (mpce != null)
+            baseRequest.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, mpce);
+    }
+    
+    public synchronized Servlet ensureInstance()
+    throws ServletException, UnavailableException
+    {
+        if (_class==null)
+            throw new UnavailableException("Servlet Not Initialized");
+        Servlet servlet=_servlet;
+        if (!isStarted())
+            throw new UnavailableException("Servlet not initialized", -1);
+        if (_unavailable!=0 || (!_initOnStartup && servlet==null))
+            servlet=getServlet();
+        if (servlet==null)
+            throw new UnavailableException("Could not instantiate "+_class);    
+        
+        return servlet;
+    }
 
     /* ------------------------------------------------------------ */
     /** Service a request with this servlet.
+     * @param baseRequest
+     * @param request
+     * @param response
+     * @throws ServletException
+     * @throws UnavailableException
+     * @throws IOException
      */
     public void handle(Request baseRequest,
                        ServletRequest request,
@@ -715,16 +790,7 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
         if (_class==null)
             throw new UnavailableException("Servlet Not Initialized");
 
-        Servlet servlet=_servlet;
-        synchronized(this)
-        {
-            if (!isStarted())
-                throw new UnavailableException("Servlet not initialized", -1);
-            if (_unavailable!=0 || (!_initOnStartup && servlet==null))
-                servlet=getServlet();
-            if (servlet==null)
-                throw new UnavailableException("Could not instantiate "+_class);
-        }
+        Servlet servlet = ensureInstance();
 
         // Service the request
         boolean servlet_error=true;
@@ -734,8 +800,7 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
         {
             // Handle aliased path
             if (_forcedPath!=null)
-                // TODO complain about poor naming to the Jasper folks
-                request.setAttribute("org.apache.catalina.jsp_file",_forcedPath);
+                adaptForcedPathToJspContainer(request);
 
             // Handle run as
             if (_identityService!=null)
@@ -744,10 +809,6 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
             if (!isAsyncSupported())
                 baseRequest.setAsyncSupported(false);
 
-            MultipartConfigElement mpce = ((Registration)getRegistration()).getMultipartConfig();
-            if (mpce != null)
-                request.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, mpce);
-
             servlet.service(request,response);
             servlet_error=false;
         }
@@ -777,7 +838,7 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
         if (_servlet == null)
             return false;
 
-        Class c = _servlet.getClass();
+        Class<?> c = _servlet.getClass();
 
         boolean result = false;
         while (c != null && !result)
@@ -797,8 +858,51 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
             return false;
         return ("org.apache.jasper.servlet.JspServlet".equals(classname));
     }
-    
-    
+
+    /* ------------------------------------------------------------ */
+    private void adaptForcedPathToJspContainer (ServletRequest request)
+    {
+        if (_forcedPath != null && _jspContainer != null && JspContainer.GLASSFISH.equals(_jspContainer))
+        {
+            //if container is glassfish, set the request attribute org.apache.catalina.jsp_file to
+            //ensure the delegate jsp will be compiled
+
+            request.setAttribute("org.apache.catalina.jsp_file",_forcedPath);
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    private void detectJspContainer ()
+    {
+        if (_jspContainer == null)
+        {
+            //check for glassfish
+            try
+            {
+                //if container is glassfish, set the request attribute org.apache.catalina.jsp_file to
+                //ensure the delegate jsp will be compiled
+                Loader.loadClass(Holder.class, GLASSFISH_SENTINEL_CLASS);
+                if (LOG.isDebugEnabled())LOG.debug("Glassfish jasper detected");
+                _jspContainer = JspContainer.GLASSFISH;
+            }
+            catch (ClassNotFoundException e)
+            {
+                try
+                {
+                    //check for apache
+                    Loader.loadClass(Holder.class, APACHE_SENTINEL_CLASS);
+                    if (LOG.isDebugEnabled())LOG.debug("Apache jasper detected");
+                    _jspContainer = JspContainer.APACHE;
+                }
+                catch (ClassNotFoundException x)
+                {
+                    if (LOG.isDebugEnabled())LOG.debug("Other jasper detected");
+                    _jspContainer = JspContainer.OTHER;
+                }
+            }
+        }
+    }
+
     /* ------------------------------------------------------------ */
     private String getNameOfJspClass (String jsp)
     {
@@ -809,7 +913,7 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
         jsp = jsp.substring(i);
         try
         {
-            Class jspUtil = Loader.loadClass(Holder.class, "org.apache.jasper.compiler.JspUtil");
+            Class<?> jspUtil = Loader.loadClass(Holder.class, "org.apache.jasper.compiler.JspUtil");
             Method makeJavaIdentifier = jspUtil.getMethod("makeJavaIdentifier", String.class);
             return (String)makeJavaIdentifier.invoke(null, jsp);
         }
@@ -835,7 +939,7 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
             return "";
         try
         {
-            Class jspUtil = Loader.loadClass(Holder.class, "org.apache.jasper.compiler.JspUtil");
+            Class<?> jspUtil = Loader.loadClass(Holder.class, "org.apache.jasper.compiler.JspUtil");
             Method makeJavaPackage = jspUtil.getMethod("makeJavaPackage", String.class);
             return (String)makeJavaPackage.invoke(null, jsp.substring(0,i));
         } 
index df026df64195dd2a4b29bfe1bade3658d512708c..4d132a653b279620881cf88a27c396fb19233337 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 2317195a183c0b1b854a3ad7aefff94b16af2eb9..4ad1fd9ffd07957b73bbb47f9f54bacdee63f102 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -23,6 +23,7 @@ import java.nio.ByteBuffer;
 import java.util.EnumSet;
 import java.util.Enumeration;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
 import javax.servlet.DispatcherType;
 import javax.servlet.Filter;
@@ -33,11 +34,16 @@ import org.eclipse.jetty.server.LocalConnector;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.ServerConnector;
 import org.eclipse.jetty.util.Attributes;
+import org.eclipse.jetty.util.BufferUtil;
 import org.eclipse.jetty.util.component.ContainerLifeCycle;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.util.resource.Resource;
 
 public class ServletTester extends ContainerLifeCycle
 {
+    private static final Logger LOG = Log.getLogger(ServletTester.class);
+    
     private final Server _server=new Server();
     private final LocalConnector _connector=new LocalConnector(_server);
     private final ServletContextHandler _context;
@@ -97,7 +103,7 @@ public class ServletTester extends ContainerLifeCycle
         return _context.getAttribute(name);
     }
 
-    public Enumeration getAttributeNames()
+    public Enumeration<String> getAttributeNames()
     {
         return _context.getAttributeNames();
     }
@@ -122,7 +128,7 @@ public class ServletTester extends ContainerLifeCycle
         return _context.setInitParameter(name,value);
     }
 
-    public Enumeration getInitParameterNames()
+    public Enumeration<String> getInitParameterNames()
     {
         return _context.getInitParameterNames();
     }
@@ -162,8 +168,6 @@ public class ServletTester extends ContainerLifeCycle
         _context.setResourceBase(resourceBase);
     }
 
-    private final ServletHandler _handler;
-
     public ServletTester()
     {
         this("/",ServletContextHandler.SECURITY|ServletContextHandler.SESSIONS);
@@ -177,7 +181,6 @@ public class ServletTester extends ContainerLifeCycle
     public ServletTester(String contextPath,int options)
     {
         _context=new ServletContextHandler(_server,contextPath,options);
-        _handler=_context.getServletHandler();
         _server.setConnectors(new Connector[]{_connector});
         addBean(_server);
     }
@@ -189,15 +192,40 @@ public class ServletTester extends ContainerLifeCycle
 
     public String getResponses(String request) throws Exception
     {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("Request: {}",request);
+        }
         return _connector.getResponses(request);
     }
-
+    
+    public String getResponses(String request, long idleFor,TimeUnit units) throws Exception
+    {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("Request: {}",request);
+        }
+        return _connector.getResponses(request, idleFor, units);
+    }
+    
     public ByteBuffer getResponses(ByteBuffer request) throws Exception
     {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("Request (Buffer): {}",BufferUtil.toUTF8String(request));
+        }
         return _connector.getResponses(request);
     }
+    
+    public ByteBuffer getResponses(ByteBuffer requestsBuffer,long idleFor,TimeUnit units) throws Exception
+    {
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("Requests (Buffer): {}",BufferUtil.toUTF8String(requestsBuffer));
+        }
+        return _connector.getResponses(requestsBuffer, idleFor, units);
+    }
 
-    /* ------------------------------------------------------------ */
     /** Create a port based connector.
      * This methods adds a port connector to the server
      * @return A URL to access the server via the connector.
index 6d1bf7d4f30635451e4a1bcab9e080f321193a54..09bb2fe08d927dab7c2c70c59fd64c5b1cb6d422 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 81b752887441c3aefac104a1b52d6648f4adab3b..0d07193cf4f698728216517c055619c018752edb 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -20,6 +20,7 @@ package org.eclipse.jetty.servlet.listener;
 
 import java.lang.reflect.Field;
 import java.util.Iterator;
+import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
 import javax.servlet.ServletContextEvent;
@@ -52,7 +53,7 @@ public class ELContextCleaner implements ServletContextListener
         try
         {
             //Check that the BeanELResolver class is on the classpath
-            Class beanELResolver = Loader.loadClass(this.getClass(), "javax.el.BeanELResolver");
+            Class<?> beanELResolver = Loader.loadClass(this.getClass(), "javax.el.BeanELResolver");
 
             //Get a reference via reflection to the properties field which is holding class references
             Field field = getField(beanELResolver);
@@ -60,22 +61,15 @@ public class ELContextCleaner implements ServletContextListener
             //Get rid of references
             purgeEntries(field);
 
-            LOG.debug("javax.el.BeanELResolver purged");
+            if (LOG.isDebugEnabled())
+                LOG.debug("javax.el.BeanELResolver purged");
         }
 
         catch (ClassNotFoundException e)
         {
             //BeanELResolver not on classpath, ignore
         }
-        catch (SecurityException e)
-        {
-            LOG.warn("Cannot purge classes from javax.el.BeanELResolver", e);
-        }
-        catch (IllegalArgumentException e)
-        {
-            LOG.warn("Cannot purge classes from javax.el.BeanELResolver", e);
-        }
-        catch (IllegalAccessException e)
+        catch (SecurityException | IllegalArgumentException | IllegalAccessException e)
         {
             LOG.warn("Cannot purge classes from javax.el.BeanELResolver", e);
         }
@@ -87,7 +81,7 @@ public class ELContextCleaner implements ServletContextListener
     }
 
 
-    protected Field getField (Class beanELResolver)
+    protected Field getField (Class<?> beanELResolver)
     throws SecurityException, NoSuchFieldException
     {
         if (beanELResolver == null)
@@ -105,22 +99,27 @@ public class ELContextCleaner implements ServletContextListener
         if (!properties.isAccessible())
             properties.setAccessible(true);
 
-        ConcurrentHashMap map = (ConcurrentHashMap) properties.get(null);
+        Map map = (Map) properties.get(null);
         if (map == null)
             return;
 
-        Iterator<Class> itor = map.keySet().iterator();
+        Iterator<Class<?>> itor = map.keySet().iterator();
         while (itor.hasNext())
         {
-            Class clazz = itor.next();
-            LOG.debug("Clazz: "+clazz+" loaded by "+clazz.getClassLoader());
+            Class<?> clazz = itor.next();
+            if (LOG.isDebugEnabled())
+                LOG.debug("Clazz: "+clazz+" loaded by "+clazz.getClassLoader());
             if (Thread.currentThread().getContextClassLoader().equals(clazz.getClassLoader()))
             {
                 itor.remove();
-                LOG.debug("removed");
+                if (LOG.isDebugEnabled())
+                    LOG.debug("removed");
             }
             else
-                LOG.debug("not removed: "+"contextclassloader="+Thread.currentThread().getContextClassLoader()+"clazz's classloader="+clazz.getClassLoader());
+            {
+                if (LOG.isDebugEnabled())
+                    LOG.debug("not removed: "+"contextclassloader="+Thread.currentThread().getContextClassLoader()+"clazz's classloader="+clazz.getClassLoader());
+            }
         }
     }
 }
index 72a6f0dd4d03badcee2382ba09506e1ccc68d607..21e13b3b014a0603fc569a2d79ae7337b8322cd2 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 2cb69e3b8b8a17460448f516160197bcbe5d3358..52cca3ac401163fac0569bb9f35237adad146d23 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index f7a9cd5577f91ba882e40d9149492a4e225186fd..1ff7b8b123173984c3de0861fdd8bccd4c328873 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index b49bec11e8a979eb792dc8aa82a608ea222eed41..c9b328665f88b2c1db5fb9509f6f2dd24b99b690 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 671439e5923619ef2013941bd2b8fce469a2ded0..44d35f14ae20c87a3599a7ba23bf361da5a6bb83 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index fdca4ce1350088b77a16ae30bb561b3ccb16fa0a..79f0871805e481a3da8e2e56f109bd534ce1802b 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -25,7 +25,8 @@ import java.util.Set;
 
 
 /* ------------------------------------------------------------ */
-/** A Ternary Trie String lookup data structure.
+/** 
+ * <p>A Ternary Trie String lookup data structure.</p>
  * This Trie is of a fixed size and cannot grow (which can be a good thing with regards to DOS when used as a cache).
  * <p>
  * The Trie is stored in 3 arrays:<dl>
@@ -36,10 +37,21 @@ import java.util.Set;
  * indicates that the _tree row is a complete key rather than an intermediate character of a longer key.</dd>
  * <dt>V[] _value</dt><dd>An array of values corresponding to the _key array</dd>
  * </dl>
+ * </p>
  * <p>The lookup of a value will iterate through the _tree array matching characters. If the equal tree branch is followed,
  * then the _key array is looked up to see if this is a complete match.  If a match is found then the _value array is looked up
  * to return the matching value.
  * </p>
+ * <p>
+ * This Trie may be instantiated either as case sensitive or insensitive.
+ * </p>
+ * <p>This Trie is not Threadsafe and contains no mutual exclusion 
+ * or deliberate memory barriers.  It is intended for an ArrayTrie to be
+ * built by a single thread and then used concurrently by multiple threads
+ * and not mutated during that access.  If concurrent mutations of the
+ * Trie is required external locks need to be applied.
+ * </p>
+ * 
  * @param <V>
  */
 public class ArrayTernaryTrie<V> extends AbstractTrie<V>
@@ -71,34 +83,60 @@ public class ArrayTernaryTrie<V> extends AbstractTrie<V>
      * The value (if any) for a Trie row. 
      * A row may be a leaf, a node or both in the Trie tree.
      */
-    private final Object[] _value;
+    private final V[] _value;
     
     /**
      * The number of rows allocated
      */
     private char _rows;
 
+    /* ------------------------------------------------------------ */
+    /** Create a case insensitive Trie of default capacity.
+     */
     public ArrayTernaryTrie()
     {
         this(128);
     }
     
+    /* ------------------------------------------------------------ */
+    /** Create a Trie of default capacity
+     * @param insensitive true if the Trie is insensitive to the case of the key.
+     */
     public ArrayTernaryTrie(boolean insensitive)
     {
         this(insensitive,128);
     }
 
-    public ArrayTernaryTrie(int capacityInNodes)
+    /* ------------------------------------------------------------ */
+    /** Create a case insensitive Trie
+     * @param capacity  The capacity of the Trie, which is in the worst case
+     * is the total number of characters of all keys stored in the Trie.
+     * The capacity needed is dependent of the shared prefixes of the keys.
+     * For example, a capacity of 6 nodes is required to store keys "foo" 
+     * and "bar", but a capacity of only 4 is required to
+     * store "bar" and "bat".
+     */
+    public ArrayTernaryTrie(int capacity)
     {
-        this(true,capacityInNodes);
+        this(true,capacity);
     }
     
-    public ArrayTernaryTrie(boolean insensitive, int capacityInNodes)
+    /* ------------------------------------------------------------ */
+    /** Create a Trie
+     * @param insensitive true if the Trie is insensitive to the case of the key.
+     * @param capacity The capacity of the Trie, which is in the worst case
+     * is the total number of characters of all keys stored in the Trie.
+     * The capacity needed is dependent of the shared prefixes of the keys.
+     * For example, a capacity of 6 nodes is required to store keys "foo" 
+     * and "bar", but a capacity of only 4 is required to
+     * store "bar" and "bat".
+     */
+    public ArrayTernaryTrie(boolean insensitive, int capacity)
     {
         super(insensitive);
-        _value=new Object[capacityInNodes];
-        _tree=new char[capacityInNodes*ROW_SIZE];
-        _key=new String[capacityInNodes];
+        _value=(V[])new Object[capacity];
+        _tree=new char[capacity*ROW_SIZE];
+        _key=new String[capacity];
     }
 
     /* ------------------------------------------------------------ */
@@ -216,7 +254,7 @@ public class ArrayTernaryTrie<V> extends AbstractTrie<V>
             }
         }
         
-        return (V)_value[t];
+        return _value[t];
     }
 
     
index 73ccc424fd01e16327c5bc1a01c957998d6b7707..9dbf994a551ea4145fb8c621e8d79ea4158afe21 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -24,9 +24,25 @@ import java.util.HashSet;
 import java.util.Set;
 
 /* ------------------------------------------------------------ */
-/** A Trie String lookup data structure using a fixed size array.
+/** 
+ * <p>A Trie String lookup data structure using a fixed size array.</p>
  * <p>This implementation is always case insensitive and is optimal for
- * a small number of fixed strings with few special characters.
+ * a small number of fixed strings with few special characters.  The
+ * Trie is stored in an array of lookup tables, each indexed by the 
+ * next character of the key.   Frequently used characters are directly
+ * indexed in each lookup table, whilst infrequently used characters
+ * must use a big character table.
+ * </p>
+ * <p>This Trie is very space efficient if the key characters are 
+ * from ' ', '+', '-', ':', ';', '.', 'A' to 'Z' or 'a' to 'z'. 
+ * Other ISO-8859-1 characters can be used by the key, but less space
+ * efficiently.
+ * </p>
+ * <p>This Trie is not Threadsafe and contains no mutual exclusion 
+ * or deliberate memory barriers.  It is intended for an ArrayTrie to be
+ * built by a single thread and then used concurrently by multiple threads
+ * and not mutated during that access.  If concurrent mutations of the
+ * Trie is required external locks need to be applied.
  * </p>
  * @param <V>
  */
@@ -47,8 +63,8 @@ public class ArrayTrie<V> extends AbstractTrie<V>
     private static final int[] __lookup = 
     { // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
    /*0*/-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-   /*1*/-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 30
-   /*2*/31, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, -1, 27, -1, -1,
+   /*1*/-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+   /*2*/31, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, -1, 27, 30, -1,
    /*3*/-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 28, 29, -1, -1, -1, -1,
    /*4*/-1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
    /*5*/15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
@@ -79,7 +95,7 @@ public class ArrayTrie<V> extends AbstractTrie<V>
      * The value (if any) for a Trie row. 
      * A row may be a leaf, a node or both in the Trie tree.
      */
-    private final Object[] _value;
+    private final V[] _value;
     
     /**
      * A big index for each row.
@@ -99,12 +115,22 @@ public class ArrayTrie<V> extends AbstractTrie<V>
         this(128);
     }
     
-    public ArrayTrie(int capacityInNodes)
+    /* ------------------------------------------------------------ */
+    /**
+     * @param capacity  The capacity of the trie, which at the worst case
+     * is the total number of characters of all keys stored in the Trie.
+     * The capacity needed is dependent of the shared prefixes of the keys.
+     * For example, a capacity of 6 nodes is required to store keys "foo" 
+     * and "bar", but a capacity of only 4 is required to
+     * store "bar" and "bat".
+     */
+    @SuppressWarnings("unchecked")
+    public ArrayTrie(int capacity)
     {
         super(true);
-        _value=new Object[capacityInNodes];
-        _rowIndex=new char[capacityInNodes*32];
-        _key=new String[capacityInNodes];
+        _value=(V[])new Object[capacity];
+        _rowIndex=new char[capacity*32];
+        _key=new String[capacity];
     }
     
     
@@ -151,8 +177,14 @@ public class ArrayTrie<V> extends AbstractTrie<V>
                 }
             }
         }
+        
+        if (t>=_key.length)
+        {
+            _rows=(char)_key.length;
+            return false;
+        }
+        
         _key[t]=v==null?null:s;
-        V old=(V)_value[t];
         _value[t] = v;
         return true;
     }
@@ -183,7 +215,7 @@ public class ArrayTrie<V> extends AbstractTrie<V>
                     return null;
             }
         }
-        return (V)_value[t];
+        return _value[t];
     }
 
     /* ------------------------------------------------------------ */
@@ -374,7 +406,7 @@ public class ArrayTrie<V> extends AbstractTrie<V>
     }
 
 
-    private <V> void toString(Appendable out, int t)
+    private void toString(Appendable out, int t)
     {
         if (_value[t]!=null)
         {
@@ -440,6 +472,6 @@ public class ArrayTrie<V> extends AbstractTrie<V>
     @Override
     public boolean isFull()
     {
-        return _rows+1==_key.length;
+        return _rows+1>=_key.length;
     }
 }
index 76b195da735a161d79adea6968e517e503912874..f1d3869027bdd34a5b702484d22fb865aa4c882a 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 42fb48902ea4c350dff84b0181223c983aa4f0bb..a3cdff063d806448685a2a2ee927c629d0ace46a 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -27,47 +27,51 @@ public class Atomics
     {
     }
 
-    public static void updateMin(AtomicLong currentMin, long newValue)
+    public static boolean updateMin(AtomicLong currentMin, long newValue)
     {
         long oldValue = currentMin.get();
         while (newValue < oldValue)
         {
             if (currentMin.compareAndSet(oldValue, newValue))
-                break;
+                return true;
             oldValue = currentMin.get();
         }
+        return false;
     }
 
-    public static void updateMax(AtomicLong currentMax, long newValue)
+    public static boolean updateMax(AtomicLong currentMax, long newValue)
     {
         long oldValue = currentMax.get();
         while (newValue > oldValue)
         {
             if (currentMax.compareAndSet(oldValue, newValue))
-                break;
+                return true;
             oldValue = currentMax.get();
         }
+        return false;
     }
 
-    public static void updateMin(AtomicInteger currentMin, int newValue)
+    public static boolean updateMin(AtomicInteger currentMin, int newValue)
     {
         int oldValue = currentMin.get();
         while (newValue < oldValue)
         {
             if (currentMin.compareAndSet(oldValue, newValue))
-                break;
+                return true;
             oldValue = currentMin.get();
         }
+        return false;
     }
 
-    public static void updateMax(AtomicInteger currentMax, int newValue)
+    public static boolean updateMax(AtomicInteger currentMax, int newValue)
     {
         int oldValue = currentMax.get();
         while (newValue > oldValue)
         {
             if (currentMax.compareAndSet(oldValue, newValue))
-                break;
+                return true;
             oldValue = currentMax.get();
         }
+        return false;
     }
 }
index c65abc265f8a4af75f01d1957e28c9e435422b26..159b3611e36bb40da22c0c7f68ce33673d264d5f 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index c605e0995026e02ef03032c38f966a5786f9d8f5..073051e53a26ba6d062838f5ce5552fd41c839b0 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 7fbbb187d327e1c115348bc122f0adc19fcbe648..48bc6d9e171f0911e1751308dcea6fd0516fadd6 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -22,7 +22,6 @@ import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
-import java.nio.charset.UnsupportedCharsetException;
 
 
 /** Fast B64 Encoder/Decoder as described in RFC 1421.
index 7acbdafcdd2648ca3604b69fe8a21edaadf07712..fa2e8dd86c87b0a116902a740a2e2e77cde8f574 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index a3cf9daea8ee54cb6082425f378b1295386c1206..8601d8e9d16dec40f24c55a5a1085ff423b47cc6 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index bd7cb06ecd186f0215fe65d0d6e5517400c67ebb..9964c3abb201091ab21fb43d65c4025520ebb827 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -23,7 +23,6 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.RandomAccessFile;
-import java.nio.Buffer;
 import java.nio.BufferOverflowException;
 import java.nio.ByteBuffer;
 import java.nio.channels.FileChannel;
@@ -390,9 +389,9 @@ public class BufferUtil
     }
 
     /* ------------------------------------------------------------ */
-    /** Appends a byte to a buffer
+    /** Appends a buffer to a buffer
      * @param to Buffer is flush mode
-     * @param b bytes to append
+     * @param b buffer to append
      */
     public static int append(ByteBuffer to, ByteBuffer b)
     {
@@ -465,7 +464,11 @@ public class BufferUtil
     public static void writeTo(ByteBuffer buffer, OutputStream out) throws IOException
     {
         if (buffer.hasArray())
-            out.write(buffer.array(), buffer.arrayOffset() + buffer.position(), buffer.remaining());
+        {
+            out.write(buffer.array(),buffer.arrayOffset() + buffer.position(),buffer.remaining());
+            // update buffer position, in way similar to non-array version of writeTo
+            buffer.position(buffer.position() + buffer.remaining());
+        }
         else
         {
             byte[] bytes = new byte[TEMP_BUFFER_SIZE];
@@ -921,18 +924,54 @@ public class BufferUtil
         return builder.toString();
     }
 
+
+    
+    /* ------------------------------------------------------------ */
+    /** Convert Buffer to string ID independent of content
+     * @param buffer
+     */
+    private static void idString(ByteBuffer buffer, StringBuilder out) 
+    {
+        out.append(buffer.getClass().getSimpleName());
+        out.append("@");
+        if (buffer.hasArray() && buffer.arrayOffset()==4)
+        {
+            out.append('T');
+            byte[] array = buffer.array();
+            TypeUtil.toHex(array[0],out);
+            TypeUtil.toHex(array[1],out);
+            TypeUtil.toHex(array[2],out);
+            TypeUtil.toHex(array[3],out);
+        }
+        else
+            out.append(Integer.toHexString(System.identityHashCode(buffer)));
+    }
+    
+    /* ------------------------------------------------------------ */
+    /** Convert Buffer to string ID independent of content
+     * @param buffer
+     * @return A string showing the buffer ID
+     */
+    public static String toIDString(ByteBuffer buffer)
+    {
+        StringBuilder buf = new StringBuilder();
+        idString(buffer,buf);
+        return buf.toString();
+    }
+    
+    
+    /* ------------------------------------------------------------ */
+    /** Convert Buffer to a detail debug string of pointers and content
+     * @param buffer
+     * @return A string showing the pointers and content of the buffer
+     */
     public static String toDetailString(ByteBuffer buffer)
     {
         if (buffer == null)
             return "null";
 
         StringBuilder buf = new StringBuilder();
-        buf.append(buffer.getClass().getSimpleName());
-        buf.append("@");
-        if (buffer.hasArray())
-            buf.append(Integer.toHexString(((Object)buffer.array()).hashCode()));
-        else
-            buf.append(Integer.toHexString(buf.hashCode()));
+        idString(buffer,buf);
         buf.append("[p=");
         buf.append(buffer.position());
         buf.append(",l=");
@@ -943,15 +982,18 @@ public class BufferUtil
         buf.append(buffer.remaining());
         buf.append("]={");
 
+        appendDebugString(buf,buffer);
+
+        buf.append("}");
+
+        return buf.toString();
+    }
+
+    private static void appendDebugString(StringBuilder buf,ByteBuffer buffer)
+    {
         for (int i = 0; i < buffer.position(); i++)
         {
-            char c = (char)buffer.get(i);
-            if (c >= ' ' && c <= 127)
-                buf.append(c);
-            else if (c == '\r' || c == '\n')
-                buf.append('|');
-            else
-                buf.append('\ufffd');
+            appendContentChar(buf,buffer.get(i));
             if (i == 16 && buffer.position() > 32)
             {
                 buf.append("...");
@@ -961,13 +1003,7 @@ public class BufferUtil
         buf.append("<<<");
         for (int i = buffer.position(); i < buffer.limit(); i++)
         {
-            char c = (char)buffer.get(i);
-            if (c >= ' ' && c <= 127)
-                buf.append(c);
-            else if (c == '\r' || c == '\n')
-                buf.append('|');
-            else
-                buf.append('\ufffd');
+            appendContentChar(buf,buffer.get(i));
             if (i == buffer.position() + 16 && buffer.limit() > buffer.position() + 32)
             {
                 buf.append("...");
@@ -979,13 +1015,7 @@ public class BufferUtil
         buffer.limit(buffer.capacity());
         for (int i = limit; i < buffer.capacity(); i++)
         {
-            char c = (char)buffer.get(i);
-            if (c >= ' ' && c <= 127)
-                buf.append(c);
-            else if (c == '\r' || c == '\n')
-                buf.append('|');
-            else
-                buf.append('\ufffd');
+            appendContentChar(buf,buffer.get(i));
             if (i == limit + 16 && buffer.capacity() > limit + 32)
             {
                 buf.append("...");
@@ -993,11 +1023,23 @@ public class BufferUtil
             }
         }
         buffer.limit(limit);
-        buf.append("}");
-
-        return buf.toString();
     }
 
+    private static void appendContentChar(StringBuilder buf, byte b)
+    {
+        if (b == '\\')
+            buf.append("\\\\");   
+        else if (b >= ' ')
+            buf.append((char)b);
+        else if (b == '\r')
+            buf.append("\\r");
+        else if (b == '\n')
+            buf.append("\\n");
+        else if (b == '\t')
+            buf.append("\\t");
+        else
+            buf.append("\\x").append(TypeUtil.toHexString(b));
+    }
 
     private final static int[] decDivisors =
             {1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1};
index 80df88198be6a386d6667f88b5de266ac249e1cc..d31f7e988691c96bad57ead637fc2eda60cc98c2 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index bfde01868d22c7f390fab6efb46a643d9964a135..56f47cd9e89feb792d3af8f4e5306032238dfce3 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 973d94137cb50c1697bea655268eee5e4d55b8ed..6425e29346e0ed6bf17f2bc904739d41f2671d32 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
 //  ========================================================================
 //
 
-/*
- * Copyright (c) 2012 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
 package org.eclipse.jetty.util;
 
 /**
  * <p>A callback abstraction that handles completed/failed events of asynchronous operations.</p>
  *
- * <p>Semantically this is equivalent to an optimise Promise&lt;Void&gt;, but callback is a more meaningful 
+ * <p>Semantically this is equivalent to an optimise Promise&lt;Void&gt;, but callback is a more meaningful
  * name than EmptyPromise</p>
  */
 public interface Callback
index 5b734db7f4fb68fc37b6048989ef83b74f741ba7..f16e18e620e4ff57da273b7fa8a87a0498f12782 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -71,10 +71,10 @@ public class ClassLoadingObjectInputStream extends ObjectInputStream
         boolean hasNonPublicInterface = false;
 
         // define proxy in class loader of non-public interface(s), if any
-        Class[] classObjs = new Class[interfaces.length];
+        Class<?>[] classObjs = new Class[interfaces.length];
         for (int i = 0; i < interfaces.length; i++) 
         {
-            Class cl = Class.forName(interfaces[i], false, loader);
+            Class<?> cl = Class.forName(interfaces[i], false, loader);
             if ((cl.getModifiers() & Modifier.PUBLIC) == 0) 
             {
                 if (hasNonPublicInterface) 
index ec5a30a84e6f1241bbcc6433aab611ba8ae2f771..674afd5330cb5702d28e839e7f91f5cdac42cef3 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -18,7 +18,7 @@
 
 package org.eclipse.jetty.util;
 
-import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * A callback to be used by driver code that needs to know whether the callback has been
@@ -57,20 +57,71 @@ import java.util.concurrent.atomic.AtomicBoolean;
  */
 public abstract class CompletableCallback implements Callback
 {
-    private final AtomicBoolean completed = new AtomicBoolean();
+    private final AtomicReference<State> state = new AtomicReference<>(State.IDLE);
 
     @Override
     public void succeeded()
     {
-        if (!tryComplete())
-            resume();
+        while (true)
+        {
+            State current = state.get();
+            switch (current)
+            {
+                case IDLE:
+                {
+                    if (state.compareAndSet(current, State.SUCCEEDED))
+                        return;
+                    break;
+                }
+                case COMPLETED:
+                {
+                    if (state.compareAndSet(current, State.SUCCEEDED))
+                    {
+                        resume();
+                        return;
+                    }
+                    break;
+                }
+                case FAILED:
+                {
+                    return;
+                }
+                default:
+                {
+                    throw new IllegalStateException(current.toString());
+                }
+            }
+        }
     }
 
     @Override
     public void failed(Throwable x)
     {
-        if (!tryComplete())
-            abort(x);
+        while (true)
+        {
+            State current = state.get();
+            switch (current)
+            {
+                case IDLE:
+                case COMPLETED:
+                {
+                    if (state.compareAndSet(current, State.FAILED))
+                    {
+                        abort(x);
+                        return;
+                    }
+                    break;
+                }
+                case FAILED:
+                {
+                    return;
+                }
+                default:
+                {
+                    throw new IllegalStateException(current.toString());
+                }
+            }
+        }
     }
 
     /**
@@ -80,8 +131,7 @@ public abstract class CompletableCallback implements Callback
     public abstract void resume();
 
     /**
-     * Callback method invoked when this callback is failed
-     * <em>after</em> a first call to {@link #tryComplete()}.
+     * Callback method invoked when this callback is failed.
      */
     public abstract void abort(Throwable failure);
 
@@ -95,6 +145,32 @@ public abstract class CompletableCallback implements Callback
      */
     public boolean tryComplete()
     {
-        return completed.compareAndSet(false, true);
+        while (true)
+        {
+            State current = state.get();
+            switch (current)
+            {
+                case IDLE:
+                {
+                    if (state.compareAndSet(current, State.COMPLETED))
+                        return true;
+                    break;
+                }
+                case SUCCEEDED:
+                case FAILED:
+                {
+                    return false;
+                }
+                default:
+                {
+                    throw new IllegalStateException(current.toString());
+                }
+            }
+        }
+    }
+
+    private enum State
+    {
+        IDLE, SUCCEEDED, FAILED, COMPLETED
     }
 }
index fc1326d63a64cb3b597753b99c79c0c7ec29d0b9..86a0b36459245fafcc8f7d37b4aab92ef8e3a7e2 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -25,8 +25,6 @@ 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;
@@ -168,6 +166,7 @@ public class ConcurrentArrayQueue<T> extends AbstractQueue<T>
         return _blocks.compareAndSet(TAIL_OFFSET,current,update);
     }
 
+    @SuppressWarnings("unchecked")
     @Override
     public T poll()
     {
@@ -276,7 +275,7 @@ public class ConcurrentArrayQueue<T> extends AbstractQueue<T>
             }
             else
             {
-                Object element = currentHeadBlock.peek(head);
+                T element = currentHeadBlock.peek(head);
                 if (element == REMOVED_ELEMENT)
                 {
                     // Already removed, try next index
@@ -284,7 +283,7 @@ public class ConcurrentArrayQueue<T> extends AbstractQueue<T>
                 }
                 else
                 {
-                    return (T)element;
+                    return element;
                 }
             }
         }
@@ -421,8 +420,11 @@ public class ConcurrentArrayQueue<T> extends AbstractQueue<T>
 
                     advance();
 
-                    if (element != REMOVED_ELEMENT)
-                        return (T)element;
+                    if (element != REMOVED_ELEMENT) {
+                        @SuppressWarnings("unchecked")
+                        T e = (T)element;
+                        return e;
+                    }
                 }
             }
 
@@ -518,9 +520,10 @@ public class ConcurrentArrayQueue<T> extends AbstractQueue<T>
             elements = new AtomicReferenceArray<>(blockSize);
         }
 
-        public Object peek(int index)
+        @SuppressWarnings("unchecked")
+        public E peek(int index)
         {
-            return elements.get(index);
+            return (E)elements.get(index);
         }
 
         public boolean store(int index, E item)
index 4a4c8e62f118b2f0e067bf790e0f814ed7a8a146..1b0bc6f94c017028b0836b88081766ed4b1cb635 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
diff --git a/lib/jetty/org/eclipse/jetty/util/CountingCallback.java b/lib/jetty/org/eclipse/jetty/util/CountingCallback.java
new file mode 100644 (file)
index 0000000..5ca4720
--- /dev/null
@@ -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.util;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * <p>A callback wrapper that succeeds the wrapped callback when the count is
+ * reached, or on first failure.</p>
+ * <p>This callback is particularly useful when an async operation is split
+ * into multiple parts, for example when an original byte buffer that needs
+ * to be written, along with a callback, is split into multiple byte buffers,
+ * since it allows the original callback to be wrapped and notified only when
+ * the last part has been processed.</p>
+ * <p>Example:</p>
+ * <pre>
+ * public void process(EndPoint endPoint, ByteBuffer buffer, Callback callback)
+ * {
+ *     ByteBuffer[] buffers = split(buffer);
+ *     CountCallback countCallback = new CountCallback(callback, buffers.length);
+ *     endPoint.write(countCallback, buffers);
+ * }
+ * </pre>
+ */
+public class CountingCallback implements Callback
+{
+    private final Callback callback;
+    private final AtomicInteger count;
+
+    public CountingCallback(Callback callback, int count)
+    {
+        this.callback = callback;
+        this.count = new AtomicInteger(count);
+    }
+
+    @Override
+    public void succeeded()
+    {
+        // Forward success on the last success.
+        while (true)
+        {
+            int current = count.get();
+
+            // Already completed ?
+            if (current == 0)
+                return;
+
+            if (count.compareAndSet(current, current - 1))
+            {
+                if (current == 1)
+                    callback.succeeded();
+                return;
+            }
+        }
+    }
+
+    @Override
+    public void failed(Throwable failure)
+    {
+        // Forward failure on the first failure.
+        while (true)
+        {
+            int current = count.get();
+
+            // Already completed ?
+            if (current == 0)
+                return;
+
+            if (count.compareAndSet(current, 0))
+            {
+                callback.failed(failure);
+                return;
+            }
+        }
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("%s@%x", getClass().getSimpleName(), hashCode());
+    }
+}
index 31097ee7daa0751a68c9499b75536e731f87d07b..924e7457206baac37434958192c0129e0e742e1b 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 152934de362a619d71f9bb0c8149fa7bdfba35f0..9e9965c7c519b2b707f8bed879cc0751dfd3f8ec 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
diff --git a/lib/jetty/org/eclipse/jetty/util/ForkInvoker.java b/lib/jetty/org/eclipse/jetty/util/ForkInvoker.java
deleted file mode 100644 (file)
index c15b313..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-//
-//  ========================================================================
-//  Copyright (c) 1995-2014 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;
-
-/**
- * Utility class that splits calls to {@link #invoke(Object)} into calls to {@link #fork(Object)} or {@link #call(Object)}
- * depending on the max number of reentrant calls to {@link #invoke(Object)}.
- * <p/>
- * This class prevents {@link StackOverflowError}s in case of methods that end up invoking themselves,
- * such is common for {@link Callback#succeeded()}.
- * <p/>
- * Typical use case is:
- * <pre>
- * public void reentrantMethod(Object param)
- * {
- *     if (condition || tooManyReenters)
- *         fork(param)
- *     else
- *         call(param)
- * }
- * </pre>
- * Calculating {@code tooManyReenters} usually involves using a {@link ThreadLocal} and algebra on the
- * number of reentrant invocations, which is factored out in this class for convenience.
- * <p />
- * The same code using this class becomes:
- * <pre>
- * private final ForkInvoker invoker = ...;
- *
- * public void reentrantMethod(Object param)
- * {
- *     invoker.invoke(param);
- * }
- * </pre>
- *
- */
-public abstract class ForkInvoker<T>
-{
-    private static final ThreadLocal<Integer> __invocations = new ThreadLocal<Integer>()
-    {
-        @Override
-        protected Integer initialValue()
-        {
-            return 0;
-        }
-    };
-    private final int _maxInvocations;
-
-    /**
-     * Creates an instance with the given max number of reentrant calls to {@link #invoke(Object)}
-     * <p/>
-     * If {@code maxInvocations} is zero or negative, it is interpreted
-     * as if the max number of reentrant calls is infinite.
-     *
-     * @param maxInvocations the max number of reentrant calls to {@link #invoke(Object)}
-     */
-    public ForkInvoker(int maxInvocations)
-    {
-        _maxInvocations = maxInvocations;
-    }
-
-    /**
-     * Invokes either {@link #fork(Object)} or {@link #call(Object)}.
-     * If {@link #condition()} returns true, {@link #fork(Object)} is invoked.
-     * Otherwise, if the max number of reentrant calls is positive and the
-     * actual number of reentrant invocations exceeds it, {@link #fork(Object)} is invoked.
-     * Otherwise, {@link #call(Object)} is invoked.
-     * @param arg TODO
-     *
-     * @return true if {@link #fork(Object)} has been called, false otherwise
-     */
-    public boolean invoke(T arg)
-    {
-        boolean countInvocations = _maxInvocations > 0;
-        int invocations = __invocations.get();
-        if (condition() || countInvocations && invocations > _maxInvocations)
-        {
-            fork(arg);
-            return true;
-        }
-        else
-        {
-            if (countInvocations)
-                __invocations.set(invocations + 1);
-            try
-            {
-                call(arg);
-                return false;
-            }
-            finally
-            {
-                if (countInvocations)
-                    __invocations.set(invocations);
-            }
-        }
-    }
-
-    /**
-     * Subclasses should override this method returning true if they want
-     * {@link #invoke(Object)} to call {@link #fork(Object)}.
-     *
-     * @return true if {@link #invoke(Object)} should call {@link #fork(Object)}, false otherwise
-     */
-    protected boolean condition()
-    {
-        return false;
-    }
-
-    /**
-     * Executes the forked invocation
-     * @param arg TODO
-     */
-    public abstract void fork(T arg);
-
-    /**
-     * Executes the direct, non-forked, invocation
-     * @param arg TODO
-     */
-    public abstract void call(T arg);
-}
index 5bad6b2e1113b214e66727285bef64fe29091a5f..247535cb2846bdb98030a72c64db367e97a82eac 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -151,7 +151,7 @@ public class FutureCallback implements Future<Void>,Callback
     @Override
     public String toString()
     {
-        return String.format("FutureCallback@%x{%b,%b}",hashCode(),_done,_cause==COMPLETED);
+        return String.format("FutureCallback@%x{%b,%b}",hashCode(),_done.get(),_cause==COMPLETED);
     }
     
 }
index f781c85004dc88343897bb8d6c271a8d7b6d1141..09a770b2a0ae7662980e4d901c9d0da6b4c54838 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -153,7 +153,7 @@ public class FuturePromise<C> implements Future<C>,Promise<C>
     @Override
     public String toString()
     {
-        return String.format("FutureCallback@%x{%b,%b,%s}",hashCode(),_done,_cause==COMPLETED,_result);
+        return String.format("FutureCallback@%x{%b,%b,%s}",hashCode(),_done.get(),_cause==COMPLETED,_result);
     }
     
 }
index 23e10bb63b06bb98bdff85e92497afcd8932635a..af6dfd4aba8817e003fd562216552e79530d86d1 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 99aa742de03fc585a05df2467799aca589993ad6..a1f3f04d0df4c2fa10f1a6e30cb0cd457a310ce7 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 51fbed94db4978d02d0187f2d62036d55f7dfc59..6e7b4824be22601a12e1cfbfb36f808681597e17 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -29,6 +29,9 @@ import java.io.PrintWriter;
 import java.io.Reader;
 import java.io.StringWriter;
 import java.io.Writer;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.GatheringByteChannel;
 import java.nio.charset.Charset;
 
 import org.eclipse.jetty.util.log.Log;
@@ -366,7 +369,8 @@ public class IO
         {
             if (writer != null)
                 writer.close();
-        } catch (IOException e)
+        } 
+        catch (IOException e)
         {
             LOG.ignore(e);
         }
@@ -380,6 +384,52 @@ public class IO
         copy(in,bout);
         return bout.toByteArray();
     }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * A gathering write utility wrapper.
+     * <p>This method wraps a gather write with a loop that handles the limitations of some operating systems that
+     * have a limit on the number of buffers written.  The method loops on the write until either all the content
+     * is written or no progress is made.
+     * @param out The GatheringgByteChannel to write to
+     * @param buffers The buffers to write
+     * @param offset The offset into the buffers array
+     * @param length The length in buffers to write
+     * @return The total bytes written
+     * @throws IOException
+     */
+    public static long write(GatheringByteChannel out, ByteBuffer[] buffers, int offset, int length) throws IOException
+    {
+        long total=0;
+        write: while (length>0)
+        {
+            // Write as much as we can
+            long wrote=out.write(buffers,offset,length);
+            
+            // If we can't write any more, give up
+            if (wrote==0)
+                break;
+            
+            // count the total
+            total+=wrote;
+            
+            // Look for unwritten content
+            for (int i=offset;i<buffers.length;i++)
+            {
+                if (buffers[i].hasRemaining())
+                {
+                    // loop with new offset and length;
+                    length=length-(i-offset);
+                    offset=i;
+                    continue write;
+                }
+            }
+            length=0;
+        }
+        
+        return total;
+    }
+    
     
     /* ------------------------------------------------------------ */
     /**
@@ -487,6 +537,7 @@ public class IO
     }
     private static NullWrite __nullWriter = new NullWrite();
     private static PrintWriter __nullPrintWriter = new PrintWriter(__nullWriter);
+
 }
 
 
index 7cbbcab9279170f6204823ff6a44e71b1c329ab0..5395724353a10d375cd00e0ca794b551a7124100 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
diff --git a/lib/jetty/org/eclipse/jetty/util/IncludeExclude.java b/lib/jetty/org/eclipse/jetty/util/IncludeExclude.java
new file mode 100644 (file)
index 0000000..80d13c3
--- /dev/null
@@ -0,0 +1,166 @@
+//
+//  ========================================================================
+//  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.Set;
+
+
+/** Utility class to maintain a set of inclusions and exclusions.
+ * <p>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) 
+ * <p>The type of the underlying {@link Set} used may be passed into the 
+ * constructor, so special sets like Servlet PathMap may be used.
+ * <p>
+ * @param <ITEM> The type of element
+ */
+public class IncludeExclude<ITEM> 
+{
+    private final Set<ITEM> _includes;
+    private final Predicate<ITEM> _includePredicate;
+    private final Set<ITEM> _excludes;
+    private final Predicate<ITEM> _excludePredicate;
+    
+    private static class SetContainsPredicate<ITEM> implements Predicate<ITEM>
+    {
+        private final Set<ITEM> set;
+        
+        public SetContainsPredicate(Set<ITEM> set)
+        {
+            this.set = set;
+        }
+        
+        @Override
+        public boolean test(ITEM item)
+        {
+            return set.contains(item);
+        }
+    }
+    
+    /**
+     * Default constructor over {@link HashSet}
+     */
+    public IncludeExclude()
+    {
+        this(HashSet.class);
+    }
+    
+    /**
+     * Construct an IncludeExclude
+     * @param setClass The type of {@link Set} to using internally
+     * @param predicate A predicate function to test if a passed ITEM is matched by the passed SET}
+     */
+    public <SET extends Set<ITEM>> IncludeExclude(Class<SET> setClass)
+    {
+        try
+        {
+            _includes = setClass.newInstance();
+            _excludes = setClass.newInstance();
+            
+            if(_includes instanceof Predicate) {
+                _includePredicate = (Predicate<ITEM>)_includes;
+            } else {
+                _includePredicate = new SetContainsPredicate<>(_includes);
+            }
+            
+            if(_excludes instanceof Predicate) {
+                _excludePredicate = (Predicate<ITEM>)_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)
+     */
+    public <SET extends Set<ITEM>> IncludeExclude(Set<ITEM> includeSet, Predicate<ITEM> includePredicate, Set<ITEM> excludeSet, Predicate<ITEM> excludePredicate)
+    {
+        _includes = includeSet;
+        _includePredicate = includePredicate;
+        _excludes = excludeSet;
+        _excludePredicate = excludePredicate;
+    }
+    
+    public void include(ITEM element)
+    {
+        _includes.add(element);
+    }
+    
+    public void include(ITEM... element)
+    {
+        for (ITEM e: element)
+            _includes.add(e);
+    }
+
+    public void exclude(ITEM element)
+    {
+        _excludes.add(element);
+    }
+    
+    public void exclude(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<ITEM> getIncluded()
+    {
+        return _includes;
+    }
+    
+    public Set<ITEM> 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);
+    }
+}
index 8588675ca66c3fac9249018cb394968649d752e5..5f724cac2e3887a161e0db4a848d7e66e9e13c17 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 1c74d5eaf6535e9d15503686c63ce07cc71dc126..8d24dd9d11cd498f192454f7bf97fc1cf58fec64 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -18,6 +18,7 @@
 
 package org.eclipse.jetty.util;
 
+import java.nio.channels.ClosedChannelException;
 import java.util.concurrent.atomic.AtomicReference;
 
 /**
@@ -50,6 +51,55 @@ import java.util.concurrent.atomic.AtomicReference;
  */
 public abstract class IteratingCallback implements Callback
 {
+    /**
+     * The internal states of this callback
+     */
+    private enum State
+    {
+        /**
+         * This callback is IDLE, ready to iterate.
+         */
+        IDLE,
+
+        /**
+         * This callback is iterating calls to {@link #process()} and is dealing with
+         * the returns.  To get into processing state, it much of held the lock state
+         * and set iterating to true.
+         */
+        PROCESSING,
+        
+        /**
+         * Waiting for a schedule callback
+         */
+        PENDING,
+        
+        /**
+         * Called by a schedule callback
+         */
+        CALLED,
+        
+        /**
+         * The overall job has succeeded as indicated by a {@link Action#SUCCEEDED} return 
+         * from {@link IteratingCallback#process()}
+         */
+        SUCCEEDED,
+        
+        /**
+         * The overall job has failed as indicated by a call to {@link IteratingCallback#failed(Throwable)}
+         */
+        FAILED,
+        
+        /**
+         * This callback has been closed and cannot be reset.
+         */ 
+        CLOSED,
+        
+        /**
+         * State is locked while leaving processing state to check the iterate boolean
+         */
+        LOCKED
+    }
+
     /**
      * The indication of the overall progress of the overall job that
      * implementations of {@link #process()} must return.
@@ -68,18 +118,27 @@ public abstract class IteratingCallback implements Callback
          * may have not yet been invoked.
          */
         SCHEDULED,
+        
         /**
          * Indicates that {@link #process()} has completed the overall job.
          */
-        SUCCEEDED,
-        /**
-         * Indicates that {@link #process()} has failed the overall job.
-         */
-        FAILED
+        SUCCEEDED
     }
 
-    private final AtomicReference<State> _state = new AtomicReference<>(State.INACTIVE);
-
+    private final AtomicReference<State> _state;
+    private boolean _iterate;
+    
+    
+    protected IteratingCallback()
+    {
+        _state = new AtomicReference<>(State.IDLE);
+    }
+    
+    protected IteratingCallback(boolean needReset)
+    {
+        _state = new AtomicReference<>(needReset ? State.SUCCEEDED : State.IDLE);
+    }
+    
     /**
      * Method called by {@link #iterate()} to process the sub task.
      * <p/>
@@ -91,129 +150,197 @@ public abstract class IteratingCallback implements Callback
      * <li>{@link Action#SCHEDULED} when the sub task asynchronous execution
      * has been started</li>
      * <li>{@link Action#SUCCEEDED} when the overall job is completed</li>
-     * <li>{@link Action#FAILED} when the overall job cannot be completed</li>
      * </ul>
      *
      * @throws Exception if the sub task processing throws
      */
     protected abstract Action process() throws Exception;
 
+    /**
+     * @deprecated Use {@link #onCompleteSuccess()} instead.
+     */
+    @Deprecated
+    protected void completed()
+    {
+    }
+
     /**
      * Invoked when the overall task has completed successfully.
+     *
+     * @see #onCompleteFailure(Throwable)
      */
-    protected abstract void completed();
+    protected void onCompleteSuccess()
+    {
+        completed();
+    }
+    
+    /**
+     * Invoked when the overall task has completed with a failure.
+     *
+     * @see #onCompleteSuccess()
+     */
+    protected void onCompleteFailure(Throwable x)
+    {
+    }
 
     /**
      * This method must be invoked by applications to start the processing
-     * of sub tasks.
-     * <p/>
-     * If {@link #process()} returns {@link Action#IDLE}, then this method
-     * should be called again to restart processing.
-     * It is safe to call iterate multiple times from multiple threads since only
-     * the first thread to move the state out of INACTIVE will actually do any iteration
-     * and processing.
+     * of sub tasks.  It can be called at any time by any thread, and it's 
+     * contract is that when called, then the {@link #process()} method will
+     * be called during or soon after, either by the calling thread or by 
+     * another thread.
      */
     public void iterate()
     {
-        try
+        loop: while (true)
         {
-            while (true)
+            State state=_state.get();
+            switch (state)
             {
-                switch (_state.get())
-                {
-                    case INACTIVE:
-                    {
-                        if (processIterations())
-                            return;
-                        break;
-                    }
-                    case ITERATING:
-                    {
-                        if (_state.compareAndSet(State.ITERATING, State.ITERATE_AGAIN))
-                            return;
-                        break;
-                    }
-                    default:
-                    {
-                        return;
-                    }
-                }
+                case PENDING:
+                case CALLED:
+                    // process will be called when callback is handled
+                    break loop;
+                    
+                case IDLE:
+                    if (!_state.compareAndSet(state,State.PROCESSING))
+                        continue;
+                    processing();
+                    break loop;
+                    
+                case PROCESSING:
+                    if (!_state.compareAndSet(state,State.LOCKED))
+                        continue;
+                    // Tell the thread that is processing that it must iterate again
+                    _iterate=true;
+                    _state.set(State.PROCESSING);
+                    break loop;
+                    
+                case LOCKED:
+                    Thread.yield();
+                    continue loop;
+
+                case FAILED:
+                case SUCCEEDED:
+                    break loop;
+
+                case CLOSED:
+                default:
+                    throw new IllegalStateException("state="+state);
             }
         }
-        catch (Throwable x)
-        {
-            failed(x);
-        }
     }
 
-    private boolean processIterations() throws Exception
+    private void processing() 
     {
-        // Keeps iterating as long as succeeded() is called during process().
-        // If we are in INACTIVE state, either this is the first iteration or
-        // succeeded()/failed() were called already.
-        while (_state.compareAndSet(State.INACTIVE, State.ITERATING))
+        // This should only ever be called when in processing state, however a failed or close call
+        // may happen concurrently, so state is not assumed.
+        
+        // While we are processing
+        processing: while (true)
         {
-            // Method process() can only be called by one thread at a time because
-            // it is guarded by the CaS above. However, the case blocks below may
-            // be executed concurrently in this case: T1 calls process() which
-            // executes the asynchronous sub task, which calls succeeded(), which
-            // moves the state into INACTIVE, then returns SCHEDULED; T2 calls
-            // iterate(), state is now INACTIVE and process() is called again and
-            // returns another action. Now we have 2 threads that may execute the
-            // action case blocks below concurrently; therefore each case block
-            // has to be prepared to fail the CaS it's doing.
+            // Call process to get the action that we have to take.
+            Action action;
+            try
+            {
+                action = process();
+            }
+            catch (Throwable x)
+            {
+                failed(x);
+                break processing;
+            }
 
-            Action action = process();
-            switch (action)
+            // loop until we have successfully acted on the action we have just received
+            acting: while(true)
             {
-                case IDLE:
+                // action handling needs to know the state
+                State state=_state.get();
+                
+                switch (state)
                 {
-                    // No more progress can be made.
-                    if (_state.compareAndSet(State.ITERATING, State.INACTIVE))
-                        return true;
+                    case PROCESSING:
+                    {
+                        switch (action)
+                        {
+                            case IDLE:
+                            {
+                                // lock the state
+                                if (!_state.compareAndSet(state,State.LOCKED))
+                                    continue acting;
 
-                    // Was iterate() called again since we already decided to go INACTIVE ?
-                    // If so, try another iteration as more work may have been added
-                    // while the previous call to process() was returning.
-                    if (_state.compareAndSet(State.ITERATE_AGAIN, State.INACTIVE))
-                        continue;
+                                // Has iterate been called while we were processing?
+                                if (_iterate)
+                                {
+                                    // yes, so skip idle and keep processing
+                                    _iterate=false;
+                                    _state.set(State.PROCESSING);
+                                    continue processing;
+                                }
 
-                    // State may have changed concurrently, try again.
-                    continue;
-                }
-                case SCHEDULED:
-                {
-                    // The sub task is executing, and the callback for it may or
-                    // may not have already been called yet, which we figure out below.
-                    // Can double CaS here because state never changes directly ITERATING_AGAIN --> ITERATE.
-                    if (_state.compareAndSet(State.ITERATING, State.ACTIVE) ||
-                            _state.compareAndSet(State.ITERATE_AGAIN, State.ACTIVE))
-                        // Not called back yet, so wait.
-                        return true;
-                    // Call back must have happened, so iterate.
-                    continue;
-                }
-                case SUCCEEDED:
-                {
-                    // The overall job has completed.
-                    if (completeSuccess())
-                        completed();
-                    return true;
-                }
-                case FAILED:
-                {
-                    completeFailure();
-                    return true;
-                }
-                default:
-                {
-                    throw new IllegalStateException(toString());
+                                // No, so we can go idle
+                                _state.set(State.IDLE);
+                                break processing;
+                            }
+                            
+                            case SCHEDULED:
+                            {
+                                if (!_state.compareAndSet(state, State.PENDING))
+                                    continue acting;
+                                // we won the race against the callback, so the callback has to process and we can break processing
+                                break processing;
+                            }
+                            
+                            case SUCCEEDED:
+                            {
+                                if (!_state.compareAndSet(state, State.LOCKED))
+                                    continue acting;
+                                _iterate=false;
+                                _state.set(State.SUCCEEDED);
+                                onCompleteSuccess();
+                                break processing;
+                            }
+
+                            default:
+                                throw new IllegalStateException("state="+state+" action="+action); 
+                        }
+                    }
+                    
+                    case CALLED:
+                    {
+                        switch (action)
+                        {
+                            case SCHEDULED:
+                            {
+                                if (!_state.compareAndSet(state, State.PROCESSING))
+                                    continue acting;
+                                // we lost the race, so we have to keep processing
+                                continue processing;
+                            }
+
+                            default:
+                                throw new IllegalStateException("state="+state+" action="+action); 
+                        }
+                    }
+                        
+                    case LOCKED:
+                        Thread.yield();
+                        continue acting;
+
+                    case SUCCEEDED:
+                    case FAILED:
+                    case CLOSED:
+                        break processing;
+
+                    case IDLE:
+                    case PENDING:
+                    default:
+                        throw new IllegalStateException("state="+state+" action="+action); 
                 }
             }
         }
-        return false;
     }
-
+    
     /**
      * Invoked when the sub task succeeds.
      * Subclasses that override this method must always remember to call
@@ -222,38 +349,38 @@ public abstract class IteratingCallback implements Callback
     @Override
     public void succeeded()
     {
-        while (true)
+        loop: while (true)
         {
-            State current = _state.get();
-            switch (current)
+            State state = _state.get();
+            switch (state)
             {
-                case ITERATE_AGAIN:
-                case ITERATING:
+                case PROCESSING:
                 {
-                    if (_state.compareAndSet(current, State.INACTIVE))
-                        return;
-                    continue;
+                    if (!_state.compareAndSet(state, State.CALLED))
+                        continue loop;
+                    break loop;
                 }
-                case ACTIVE:
+                case PENDING:
                 {
-                    // If we can move from ACTIVE to INACTIVE
-                    // then we are responsible to call iterate().
-                    if (_state.compareAndSet(current, State.INACTIVE))
-                        iterate();
-                    // If we can't CaS, then failed() must have been
-                    // called, and we just return.
-                    return;
+                    if (!_state.compareAndSet(state, State.PROCESSING))
+                        continue loop;
+                    processing();
+                    break loop;
                 }
-                case INACTIVE:
+                case CLOSED:
+                case FAILED:
                 {
-                    // Support the case where the callback is scheduled
-                    // externally without a call to iterate().
-                    iterate();
-                    return;
+                    // Too late!
+                    break loop;
                 }
+                case LOCKED:
+                {
+                    Thread.yield();
+                    continue loop;
+                }       
                 default:
                 {
-                    throw new IllegalStateException(toString());
+                    throw new IllegalStateException("state="+state);
                 }
             }
         }
@@ -267,53 +394,89 @@ public abstract class IteratingCallback implements Callback
     @Override
     public void failed(Throwable x)
     {
-        completeFailure();
-    }
-
-    private boolean completeSuccess()
-    {
-        while (true)
+        loop: while (true)
         {
-            State current = _state.get();
-            if (current == State.FAILED)
+            State state = _state.get();
+            switch (state)
             {
-                // Success arrived too late, sorry.
-                return false;
-            }
-            else
-            {
-                if (_state.compareAndSet(current, State.SUCCEEDED))
-                    return true;
+                case SUCCEEDED:
+                case FAILED:
+                case IDLE:
+                case CLOSED:
+                case CALLED:
+                {
+                    // too late!.
+                    break loop;
+                }
+                case LOCKED:
+                {
+                    Thread.yield();
+                    continue loop;
+                }  
+                case PENDING: 
+                case PROCESSING: 
+                {
+                    if (!_state.compareAndSet(state, State.FAILED))
+                        continue loop;
+
+                    onCompleteFailure(x);
+                    break loop;
+                }
+                default:
+                    throw new IllegalStateException("state="+state);
             }
         }
     }
 
-    private void completeFailure()
+    public void close()
     {
-        while (true)
+        loop: while (true)
         {
-            State current = _state.get();
-            if (current == State.SUCCEEDED)
+            State state = _state.get();
+            switch (state)
             {
-                // Failed arrived too late, sorry.
-                return;
-            }
-            else
-            {
-                if (_state.compareAndSet(current, State.FAILED))
-                    break;
+                case IDLE:
+                case SUCCEEDED:
+                case FAILED:
+                {
+                    if (!_state.compareAndSet(state, State.CLOSED))
+                        continue loop;
+                    break loop;
+                }
+                case CLOSED:
+                {
+                    break loop;
+                }
+                case LOCKED:
+                {
+                    Thread.yield();
+                    continue loop;
+                }    
+                default:
+                {
+                    if (!_state.compareAndSet(state, State.CLOSED))
+                        continue loop;
+                    onCompleteFailure(new ClosedChannelException());
+                    break loop;
+                }
             }
         }
     }
 
-    /**
+    /*
+     * only for testing
      * @return whether this callback is idle and {@link #iterate()} needs to be called
      */
-    public boolean isIdle()
+    boolean isIdle()
     {
-        return _state.get() == State.INACTIVE;
+        return _state.get() == State.IDLE;
     }
 
+    public boolean isClosed()
+    {
+        return _state.get() == State.CLOSED;
+    }
+    
     /**
      * @return whether this callback has failed
      */
@@ -330,45 +493,51 @@ public abstract class IteratingCallback implements Callback
         return _state.get() == State.SUCCEEDED;
     }
 
+    /**
+     * Resets this callback.
+     * <p/>
+     * A callback can only be reset to IDLE from the
+     * SUCCEEDED or FAILED states or if it is already IDLE.
+     *
+     * @return true if the reset was successful
+     */
+    public boolean reset()
+    {
+        while (true)
+        {
+            State state=_state.get();
+            switch(state)
+            {
+                case IDLE:
+                    return true;
+                    
+                case SUCCEEDED:
+                    if (!_state.compareAndSet(state, State.LOCKED))
+                        continue;
+                    _iterate=false;
+                    _state.set(State.IDLE);
+                    return true;
+                    
+                case FAILED:
+                    if (!_state.compareAndSet(state, State.LOCKED))
+                        continue;
+                    _iterate=false;
+                    _state.set(State.IDLE);
+                    return true;
+
+                case LOCKED:
+                    Thread.yield();
+                    continue;
+                    
+                default:
+                    return false;
+            }
+        }
+    }
+    
     @Override
     public String toString()
     {
         return String.format("%s[%s]", super.toString(), _state);
     }
-
-    /**
-     * The internal states of this callback
-     */
-    private enum State
-    {
-        /**
-         * This callback is inactive, ready to iterate.
-         */
-        INACTIVE,
-        /**
-         * This callback is iterating and {@link #process()} has scheduled an
-         * asynchronous operation by returning {@link Action#SCHEDULED}, but
-         * the operation is still undergoing.
-         */
-        ACTIVE,
-        /**
-         * This callback is iterating and {@link #process()} has been called
-         * but not returned yet.
-         */
-        ITERATING,
-        /**
-         * While this callback was iterating, another request for iteration
-         * has been issued, so the iteration must continue even if a previous
-         * call to {@link #process()} returned {@link Action#IDLE}.
-         */
-        ITERATE_AGAIN,
-        /**
-         * The overall job has succeeded.
-         */
-        SUCCEEDED,
-        /**
-         * The overall job has failed.
-         */
-        FAILED
-    }
 }
index e018f43a484be250854487acae1fc1f1be7f6a95..1cf154cad09f0655e9e8df6bb8c8c750147d3e39 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -48,15 +48,14 @@ public abstract class IteratingNestedCallback extends IteratingCallback
     }
     
     @Override
-    protected void completed()
+    protected void onCompleteSuccess()
     {
         _callback.succeeded();
     }
-
+    
     @Override
-    public void failed(Throwable x)
+    protected void onCompleteFailure(Throwable x)
     {
-        super.failed(x);
         _callback.failed(x);
     }
 
index 5a9b25705e17c8d565f668cb042700e415b9cf15..864c6af39bcaeb7b8e574472b0fc836e10d0c786 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 6ff416e64e81313b0000bf0826675c9aa8e5382b..3b259c7068a17f72b4cf83955729e5e246f02eed 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index b0ac94e9b4d0f5cb2cbf2b6b8dc71bafd23c74b0..11b3b31a83a153480e2ac4546d708cd6afeea7bd 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -31,40 +31,29 @@ import org.eclipse.jetty.util.log.Logger;
 /**
  * A facility to detect improper usage of resource pools.
  * <p>
- * Resource pools usually have a method to acquire a pooled resource
- * and a method to released it back to the pool.
+ * Resource pools usually have a method to acquire a pooled resource and a method to released it back to the pool.
  * <p>
- * To detect if client code acquires a resource but never releases it,
- * the resource pool can be modified to use a {@link LeakDetector}.
- * The modified resource pool should call {@link #acquired(Object)} every time
- * the method to acquire a resource is called, and {@link #released(Object)}
- * every time the method to release the resource is called.
+ * To detect if client code acquires a resource but never releases it, the resource pool can be modified to use a
+ * {@link LeakDetector}. The modified resource pool should call {@link #acquired(Object)} every time the method to
+ * acquire a resource is called, and {@link #released(Object)} every time the method to release the resource is called.
  * {@link LeakDetector} keeps track of these resources and invokes method
- * {@link #leaked(org.eclipse.jetty.util.LeakDetector.LeakInfo)} when it detects that a resource
- * has been leaked (that is, acquired but never released).
+ * {@link #leaked(org.eclipse.jetty.util.LeakDetector.LeakInfo)} when it detects that a resource has been leaked (that
+ * is, acquired but never released).
  * <p>
- * To detect whether client code releases a resource without having
- * acquired it, the resource pool can be modified to check the return value
- * of {@link #released(Object)}: if false, it means that the resource was
- * not acquired.
+ * To detect whether client code releases a resource without having acquired it, the resource pool can be modified to
+ * check the return value of {@link #released(Object)}: if false, it means that the resource was not acquired.
  * <p>
  * IMPLEMENTATION NOTES
  * <p>
- * This class relies on {@link System#identityHashCode(Object)} to create
- * a unique id for each resource passed to {@link #acquired(Object)} and
- * {@link #released(Object)}. {@link System#identityHashCode(Object)} does
- * not guarantee that it will not generate the same number for different
- * objects, but in practice the chance of collision is rare.
+ * This class relies on {@link System#identityHashCode(Object)} to create a unique id for each resource passed to
+ * {@link #acquired(Object)} and {@link #released(Object)}. {@link System#identityHashCode(Object)} does not guarantee
+ * that it will not generate the same number for different objects, but in practice the chance of collision is rare.
  * <p>
- * {@link LeakDetector} uses {@link PhantomReference}s to detect leaks.
- * {@link PhantomReference}s are enqueued in their {@link ReferenceQueue}
- * <em>after</em> they have been garbage collected (differently from
- * {@link WeakReference}s that are enqueued <em>before</em>).
- * Since the resource is now garbage collected, {@link LeakDetector} checks
- * whether it has been released and if not, it reports a leak.
- * Using {@link PhantomReference}s is better than overriding {@link #finalize()}
- * and works also in those cases where {@link #finalize()} is not
- * overridable.
+ * {@link LeakDetector} uses {@link PhantomReference}s to detect leaks. {@link PhantomReference}s are enqueued in their
+ * {@link ReferenceQueue} <em>after</em> they have been garbage collected (differently from {@link WeakReference}s that
+ * are enqueued <em>before</em>). Since the resource is now garbage collected, {@link LeakDetector} checks whether it
+ * has been released and if not, it reports a leak. Using {@link PhantomReference}s is better than overriding
+ * {@link #finalize()} and works also in those cases where {@link #finalize()} is not overridable.
  *
  * @param <T> the resource type.
  */
@@ -80,26 +69,43 @@ public class LeakDetector<T> extends AbstractLifeCycle implements Runnable
      * Tracks the resource as been acquired.
      *
      * @param resource the resource that has been acquired
-     * @return whether the resource has been tracked
+     * @return true whether the resource has been acquired normally, false if the resource has detected a leak (meaning
+     *         that another acquire occurred before a release of the same resource)
      * @see #released(Object)
      */
     public boolean acquired(T resource)
     {
         String id = id(resource);
-        return resources.putIfAbsent(id, new LeakInfo(resource, id)) == null;
+        LeakInfo info = resources.putIfAbsent(id, new LeakInfo(resource,id));
+        if (info != null)
+        {
+            // Leak detected, prior acquire exists (not released) or id clash.
+            return false;
+        }
+        // Normal behavior.
+        return true;
     }
 
     /**
      * Tracks the resource as been released.
      *
      * @param resource the resource that has been released
-     * @return whether the resource has been acquired
+     * @return true whether the resource has been released normally (based on a previous acquire). false if the resource
+     *         has been released without a prior acquire (such as a double release scenario)
      * @see #acquired(Object)
      */
     public boolean released(T resource)
     {
         String id = id(resource);
-        return resources.remove(id) != null;
+        LeakInfo info = resources.remove(id);
+        if (info != null)
+        {
+            // Normal behavior.
+            return true;
+        }
+
+        // Leak detected (released without acquire).
+        return false;
     }
 
     /**
@@ -108,7 +114,7 @@ public class LeakDetector<T> extends AbstractLifeCycle implements Runnable
      * @param resource the resource to generate the unique ID for
      * @return the unique ID of the given resource
      */
-    protected String id(T resource)
+    public String id(T resource)
     {
         return String.valueOf(System.identityHashCode(resource));
     }
@@ -117,7 +123,7 @@ public class LeakDetector<T> extends AbstractLifeCycle implements Runnable
     protected void doStart() throws Exception
     {
         super.doStart();
-        thread = new Thread(this, getClass().getSimpleName());
+        thread = new Thread(this,getClass().getSimpleName());
         thread.setDaemon(true);
         thread.start();
     }
@@ -125,8 +131,8 @@ public class LeakDetector<T> extends AbstractLifeCycle implements Runnable
     @Override
     protected void doStop() throws Exception
     {
-        thread.interrupt();
         super.doStop();
+        thread.interrupt();
     }
 
     @Override
@@ -138,7 +144,8 @@ public class LeakDetector<T> extends AbstractLifeCycle implements Runnable
             {
                 @SuppressWarnings("unchecked")
                 LeakInfo leakInfo = (LeakInfo)queue.remove();
-                LOG.debug("Resource GC'ed: {}", leakInfo);
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Resource GC'ed: {}",leakInfo);
                 if (resources.remove(leakInfo.id) != null)
                     leaked(leakInfo);
             }
@@ -156,7 +163,7 @@ public class LeakDetector<T> extends AbstractLifeCycle implements Runnable
      */
     protected void leaked(LeakInfo leakInfo)
     {
-        LOG.warn("Resource leaked: " + leakInfo.description, leakInfo.stackFrames);
+        LOG.warn("Resource leaked: " + leakInfo.description,leakInfo.stackFrames);
     }
 
     /**
@@ -170,7 +177,7 @@ public class LeakDetector<T> extends AbstractLifeCycle implements Runnable
 
         private LeakInfo(T referent, String id)
         {
-            super(referent, queue);
+            super(referent,queue);
             this.id = id;
             this.description = referent.toString();
             this.stackFrames = new Throwable();
index dfb87fd73a470923baef3867b599722772c5569e..c045070e410246302527ae1e09ece98fdf0a2686 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 764ad600187977b748e05a120e208d503e243a79..514af036dd385a9d173aba75cb1c93ecb8ccd03e 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 2e71f3c58ccc26ff9b0d671799806e980455ed41..7653ca6636385b769c4721f66f475c713aa78390 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -18,8 +18,6 @@
 
 package org.eclipse.jetty.util;
 
-import java.io.PrintStream;
-import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -43,10 +41,16 @@ public class MultiException extends Exception
     /* ------------------------------------------------------------ */
     public void add(Throwable e)
     {
+        if (e==null)
+            throw new IllegalArgumentException();
+
         if(nested == null)
         {
+            initCause(e);
             nested = new ArrayList<>();
         }
+        else
+            addSuppressed(e);
         
         if (e instanceof MultiException)
         {
@@ -66,9 +70,8 @@ public class MultiException extends Exception
     /* ------------------------------------------------------------ */
     public List<Throwable> getThrowables()
     {
-        if(nested == null) {
+        if(nested == null)
             return Collections.emptyList();
-        }
         return nested;
     }
     
@@ -168,47 +171,4 @@ public class MultiException extends Exception
         return str.toString();
     }
 
-    /* ------------------------------------------------------------ */
-    @Override
-    public void printStackTrace()
-    {
-        super.printStackTrace();
-        if(nested != null) {
-            for(Throwable t: nested) {
-                t.printStackTrace();
-            }
-        }
-    }
-   
-
-    /* ------------------------------------------------------------------------------- */
-    /**
-     * @see java.lang.Throwable#printStackTrace(java.io.PrintStream)
-     */
-    @Override
-    public void printStackTrace(PrintStream out)
-    {
-        super.printStackTrace(out);
-        if(nested != null) {
-            for(Throwable t: nested) {
-                t.printStackTrace(out);
-            }
-        }
-    }
-
-    /* ------------------------------------------------------------------------------- */
-    /**
-     * @see java.lang.Throwable#printStackTrace(java.io.PrintWriter)
-     */
-    @Override
-    public void printStackTrace(PrintWriter out)
-    {
-        super.printStackTrace(out);
-        if(nested != null) {
-            for(Throwable t: nested) {
-                t.printStackTrace(out);
-            }
-        }
-    }
-
 }
index a3c905a30cee052c8005ec967eb74765f3d1863c..1a057c62b1546af463cd4b0ec472cd96d84a37c6 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 441d648ea5267c94a4f664313470674c8cd490df..4fbc2a7fd87c51d0a5ab3c41d43e325cd07386de 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -57,7 +57,7 @@ public class MultiPartInputStreamParser
     protected InputStream _in;
     protected MultipartConfigElement _config;
     protected String _contentType;
-    protected MultiMap _parts;
+    protected MultiMap<Part> _parts;
     protected File _tmpDir;
     protected File _contextTmpDir;
     protected boolean _deleteOnExit;
@@ -72,7 +72,7 @@ public class MultiPartInputStreamParser
         protected OutputStream _out;
         protected ByteArrayOutputStream2 _bout;
         protected String _contentType;
-        protected MultiMap _headers;
+        protected MultiMap<String> _headers;
         protected long _size = 0;
         protected boolean _temporary = true;
 
@@ -92,19 +92,9 @@ public class MultiPartInputStreamParser
         protected void open()
         throws IOException
         {
-            //We will either be writing to a file, if it has a filename on the content-disposition
-            //and otherwise a byte-array-input-stream, OR if we exceed the getFileSizeThreshold, we
-            //will need to change to write to a file.
-            if (_filename != null && _filename.trim().length() > 0)
-            {
-                createFile();
-            }
-            else
-            {
-                //Write to a buffer in memory until we discover we've exceed the
-                //MultipartConfig fileSizeThreshold
-                _out = _bout= new ByteArrayOutputStream2();
-            }
+            //Write to a buffer in memory until we discover we've exceed the
+            //MultipartConfig fileSizeThreshold
+            _out = _bout= new ByteArrayOutputStream2();
         }
 
         protected void close()
@@ -122,6 +112,7 @@ public class MultiPartInputStreamParser
 
             if (MultiPartInputStreamParser.this._config.getFileSizeThreshold() > 0 && _size + 1 > MultiPartInputStreamParser.this._config.getFileSizeThreshold() && _file==null)
                 createFile();
+
             _out.write(b);
             _size ++;
         }
@@ -134,7 +125,7 @@ public class MultiPartInputStreamParser
 
             if (MultiPartInputStreamParser.this._config.getFileSizeThreshold() > 0 && _size + length > MultiPartInputStreamParser.this._config.getFileSizeThreshold() && _file==null)
                 createFile();
-
+           
             _out.write(bytes, offset, length);
             _size += length;
         }
@@ -143,6 +134,7 @@ public class MultiPartInputStreamParser
         throws IOException
         {
             _file = File.createTempFile("MultiPart", "", MultiPartInputStreamParser.this._tmpDir);
+            
             if (_deleteOnExit)
                 _file.deleteOnExit();
             FileOutputStream fos = new FileOutputStream(_file);
@@ -161,7 +153,7 @@ public class MultiPartInputStreamParser
 
 
 
-        protected void setHeaders(MultiMap headers)
+        protected void setHeaders(MultiMap<String> headers)
         {
             _headers = headers;
         }
@@ -359,9 +351,9 @@ public class MultiPartInputStreamParser
         if (_parts == null)
             return Collections.emptyList();
 
-        Collection<Object> values = _parts.values();
+        Collection<List<Part>> values = _parts.values();
         List<Part> parts = new ArrayList<Part>();
-        for (Object o: values)
+        for (List<Part> o: values)
         {
             List<Part> asList = LazyList.getList(o, false);
             parts.addAll(asList);
@@ -406,9 +398,9 @@ public class MultiPartInputStreamParser
     throws IOException, ServletException
     {
         parse();
-        Collection<Object> values = _parts.values();
+        Collection<List<Part>> values = _parts.values();
         List<Part> parts = new ArrayList<Part>();
-        for (Object o: values)
+        for (List<Part> o: values)
         {
             List<Part> asList = LazyList.getList(o, false);
             parts.addAll(asList);
@@ -447,7 +439,7 @@ public class MultiPartInputStreamParser
 
         //initialize
         long total = 0; //keep running total of size of bytes read from input and throw an exception if exceeds MultipartConfigElement._maxRequestSize
-        _parts = new MultiMap();
+        _parts = new MultiMap<Part>();
 
         //if its not a multipart request, don't parse it
         if (_contentType == null || !_contentType.startsWith("multipart/form-data"))
@@ -523,7 +515,7 @@ public class MultiPartInputStreamParser
             String contentType=null;
             String contentTransferEncoding=null;
             
-            MultiMap headers = new MultiMap();
+            MultiMap<String> headers = new MultiMap<String>();
             while(true)
             {
                 line=((ReadLineInputStream)_in).readLine();
index f554e767b29a509b4cecb9b641ef3b3918cbfb87..c39ae59f66a0b27ae0a6ea4a28eebd747d269527 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 002171258a214ec45d00089ca4d3d065faed6f71..78f8ed9d021125c60f389d9ceb0e01504621834d 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 0afda65a4cd3370c127abb425cf72b4711abb301..dd314c0b4f7229c05b4fb71aceb9aa305e14e67c 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
diff --git a/lib/jetty/org/eclipse/jetty/util/Predicate.java b/lib/jetty/org/eclipse/jetty/util/Predicate.java
new file mode 100644 (file)
index 0000000..9d26fa0
--- /dev/null
@@ -0,0 +1,31 @@
+//
+//  ========================================================================
+//  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;
+
+/**
+ * Temporary implementation of Java 8's <code>java.util.function.Predicate</code>
+ * <p>
+ * To be removed for Java 8 only versions of Jetty.
+ * 
+ * @param <ITEM> the item to test
+ */
+public interface Predicate<ITEM>
+{
+    boolean test(ITEM item);
+}
index 6727fc4e3a93f69a550aea79579a1a98b23d4c2e..3a6512d37887e2f2904d40e070dd091c8c7a25c9 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 3a4d51897de9a6410c25c3375441cf3fa25c9ad2..3ea1d8d57457c64098a5c26b1c4d6c562e8f7144 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 067b2c14897ed7b435bacbb77143b1c20859ff6d..4c507a96648950a88c26e6a4e079b32c618f21be 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
diff --git a/lib/jetty/org/eclipse/jetty/util/RegexSet.java b/lib/jetty/org/eclipse/jetty/util/RegexSet.java
new file mode 100644 (file)
index 0000000..7aacf9e
--- /dev/null
@@ -0,0 +1,109 @@
+//
+//  ========================================================================
+//  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.AbstractSet;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+/**
+ * A Set of Regular expressions strings.
+ * <p>
+ * Provides the efficient {@link #matches(String)} method to check for a match against all the combined Regex's
+ */
+public class RegexSet extends AbstractSet<String> implements Predicate<String>
+{
+    private final Set<String> _patterns=new HashSet<String>();
+    private final Set<String> _unmodifiable=Collections.unmodifiableSet(_patterns);
+    private Pattern _pattern;
+    
+    @Override
+    public Iterator<String> iterator()
+    {
+        return _unmodifiable.iterator();
+    }
+
+    @Override
+    public int size()
+    {
+        return _patterns.size();
+    }
+    
+    @Override
+    public boolean add(String pattern)
+    {
+        boolean added = _patterns.add(pattern);
+        if (added)
+            updatePattern();
+        return added;
+    }
+    
+    @Override
+    public boolean remove(Object pattern)
+    {
+        boolean removed = _patterns.remove(pattern);
+
+        if (removed)
+            updatePattern();
+        return removed;
+    }
+
+    @Override
+    public boolean isEmpty()
+    {
+        return _patterns.isEmpty();
+    }
+
+    @Override
+    public void clear()
+    {
+        _patterns.clear();
+        _pattern=null;
+    }
+
+    private void updatePattern()
+    {
+        StringBuilder builder = new StringBuilder();
+        builder.append("^(");
+        for (String pattern: _patterns)
+        {
+            if (builder.length()>2)
+                builder.append('|');
+            builder.append('(');
+            builder.append(pattern);
+            builder.append(')');
+        }
+        builder.append(")$");
+        _pattern = Pattern.compile(builder.toString());   
+    }
+    
+    @Override
+    public boolean test(String s)
+    {
+        return _pattern!=null && _pattern.matcher(s).matches();
+    }
+
+    public boolean matches(String s)
+    {
+        return _pattern!=null && _pattern.matcher(s).matches();
+    }
+}
index 60f5da4be5bcadef0b1b64a17e895e68ed617247..f154f9f68a60be1d91485814b239d6b4a6734e9f 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index f29db3daac4d0cdb0a5b5c9715f4bfcb3a28085d..2aba5b39a20f32b1e29149402add1e7e7739801f 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -557,12 +557,16 @@ public class Scanner extends AbstractLifeCycle
             {
                 if ((_filter == null) || ((_filter != null) && _filter.accept(f.getParentFile(), f.getName())))
                 {
-                    LOG.debug("scan accepted {}",f);
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("scan accepted {}",f);
                     String name = f.getCanonicalPath();
-                    scanInfoMap.put(name, new TimeNSize(f.lastModified(),f.length()));
+                    scanInfoMap.put(name, new TimeNSize(f.lastModified(),f.isDirectory()?0:f.length()));
                 }
                 else
-                    LOG.debug("scan rejected {}",f);
+                {
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("scan rejected {}",f);
+                }
             }
             
             // If it is a directory, scan if it is a known directory or the depth is OK.
index 3085a68735d150e20280888357eb3d1a8389fa82..5b4e5a312ebaaf17fce2691cbfa1326885cf1d53 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -48,7 +48,11 @@ import org.eclipse.jetty.util.thread.NonBlockingThread;
  */
 public class SharedBlockingCallback
 {
-    private static final Logger LOG = Log.getLogger(SharedBlockingCallback.class);
+    static final Logger LOG = Log.getLogger(SharedBlockingCallback.class);
+
+    final ReentrantLock _lock = new ReentrantLock();
+    final Condition _idle = _lock.newCondition();
+    final Condition _complete = _lock.newCondition();
 
     
     private static Throwable IDLE = new Throwable()
@@ -78,56 +82,64 @@ public class SharedBlockingCallback
         }
     };
 
-    final Blocker _blocker;
+    Blocker _blocker;
     
     public SharedBlockingCallback()
     {
-        this(new Blocker());
+        _blocker=new Blocker();
     }
     
-    protected SharedBlockingCallback(Blocker blocker)
+    protected long getIdleTimeout()
     {
-        _blocker=blocker;
+        return -1;
     }
     
     public Blocker acquire() throws IOException
     {
-        _blocker._lock.lock();
+        _lock.lock();
+        long idle = getIdleTimeout();
         try
         {
             while (_blocker._state != IDLE)
-                _blocker._idle.await();
+            {
+                if (idle>0 && (idle < Long.MAX_VALUE/2))
+                {
+                    // Wait a little bit longer than the blocker might block
+                    if (!_idle.await(idle*2,TimeUnit.MILLISECONDS))
+                        throw new IOException(new TimeoutException());
+                }
+                else
+                    _idle.await();
+            }
             _blocker._state = null;
         }
         catch (final InterruptedException e)
         {
-            throw new InterruptedIOException()
-            {
-                {
-                    initCause(e);
-                }
-            };
+            throw new InterruptedIOException();
         }
         finally
         {
-            _blocker._lock.unlock();
+            _lock.unlock();
         }
         return _blocker;
     }
 
+    protected void notComplete(Blocker blocker)
+    {
+        LOG.warn("Blocker not complete {}",blocker);
+        if (LOG.isDebugEnabled())
+            LOG.debug(new Throwable());
+    }
     
     /* ------------------------------------------------------------ */
     /** A Closeable Callback.
      * Uses the auto close mechanism to check block has been called OK.
      */
-    public static class Blocker implements Callback, Closeable
+    public class Blocker implements Callback, Closeable
     {
-        final ReentrantLock _lock = new ReentrantLock();
-        final Condition _idle = _lock.newCondition();
-        final Condition _complete = _lock.newCondition();
         Throwable _state = IDLE;
-
-        public Blocker()
+        
+        protected Blocker()
         {
         }
 
@@ -142,8 +154,8 @@ public class SharedBlockingCallback
                     _state = SUCCEEDED;
                     _complete.signalAll();
                 }
-                else if (_state == IDLE)
-                    throw new IllegalStateException("IDLE");
+                else
+                    throw new IllegalStateException(_state);
             }
             finally
             {
@@ -159,14 +171,17 @@ public class SharedBlockingCallback
             {
                 if (_state == null)
                 {
-                    // TODO remove when feedback received on 435322
                     if (cause==null)
-                        LOG.warn("null failed cause (please report stack trace) ",new Throwable());
-                    _state = cause==null?FAILED:cause;
+                        _state=FAILED;
+                    else if (cause instanceof BlockerTimeoutException)
+                        // Not this blockers timeout
+                        _state=new IOException(cause);
+                    else 
+                        _state=cause;
                     _complete.signalAll();
                 }
-                else if (_state == IDLE)
-                    throw new IllegalStateException("IDLE");
+                else 
+                    throw new IllegalStateException(_state);
             }
             finally
             {
@@ -187,18 +202,21 @@ public class SharedBlockingCallback
                 LOG.warn("Blocking a NonBlockingThread: ",new Throwable());
             
             _lock.lock();
+            long idle = getIdleTimeout();
             try
             {
                 while (_state == null)
                 {
-                    // TODO remove this debug timout!
-                    // This is here to help debug 435322,
-                    if (!_complete.await(10,TimeUnit.MINUTES))
+                    if (idle>0 && (idle < Long.MAX_VALUE/2))
                     {
-                        IOException x = new IOException("DEBUG timeout");
-                        LOG.warn("Blocked too long (please report!!!) "+this, x);
-                        _state=x;
+                        // 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();
                     }
+                    else
+                        _complete.await();
                 }
 
                 if (_state == SUCCEEDED)
@@ -217,12 +235,7 @@ public class SharedBlockingCallback
             }
             catch (final InterruptedException e)
             {
-                throw new InterruptedIOException()
-                {
-                    {
-                        initCause(e);
-                    }
-                };
+                throw new InterruptedIOException();
             }
             finally
             {
@@ -245,13 +258,26 @@ public class SharedBlockingCallback
                 if (_state == IDLE)
                     throw new IllegalStateException("IDLE");
                 if (_state == null)
-                    LOG.debug("Blocker not complete",new Throwable());
+                    notComplete(this);
             }
             finally
             {
-                _state = IDLE;
-                _idle.signalAll();
-                _lock.unlock();
+                try 
+                {
+                    // If the blocker timed itself out, remember the state
+                    if (_state instanceof BlockerTimeoutException)
+                        // and create a new Blocker
+                        _blocker=new Blocker();
+                    else
+                        // else reuse Blocker
+                        _state = IDLE;
+                    _idle.signalAll();
+                    _complete.signalAll();
+                } 
+                finally 
+                {
+                    _lock.unlock();
+                }
             }
         }
 
@@ -261,7 +287,7 @@ public class SharedBlockingCallback
             _lock.lock();
             try
             {
-                return String.format("%s@%x{%s}",SharedBlockingCallback.class.getSimpleName(),hashCode(),_state);
+                return String.format("%s@%x{%s}",Blocker.class.getSimpleName(),hashCode(),_state);
             }
             finally
             {
@@ -269,4 +295,8 @@ public class SharedBlockingCallback
             }
         }
     }
+    
+    private static class BlockerTimeoutException extends TimeoutException
+    { 
+    }
 }
index e75abfc064fd2799fec8a0e9392ad6a577e42c06..f6eff3f026c4979fce4bd0b91dd15da2b841e71e 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -31,69 +31,10 @@ import org.eclipse.jetty.util.log.Logger;
 import org.eclipse.jetty.util.thread.Scheduler;
 
 /**
- * Creates asynchronously {@link SocketAddress} instances, returning them through a {@link Promise},
- * in order to avoid blocking on DNS lookup.
- * <p />
- * {@link InetSocketAddress#InetSocketAddress(String, int)} attempts to perform a DNS resolution of
- * the host name, and this may block for several seconds.
- * This class creates the {@link InetSocketAddress} in a separate thread and provides the result
- * through a {@link Promise}, with the possibility to specify a timeout for the operation.
- * <p />
- * Example usage:
- * <pre>
- * SocketAddressResolver resolver = new SocketAddressResolver(executor, scheduler);
- * resolver.resolve("www.google.com", 80, new Promise&lt;SocketAddress&gt;()
- * {
- *     public void succeeded(SocketAddress result)
- *     {
- *         // The address was resolved
- *     }
- *
- *     public void failed(Throwable failure)
- *     {
- *         // The address resolution failed
- *     }
- * });
- * </pre>
+ * <p>Creates {@link SocketAddress} instances, returning them through a {@link Promise}.</p>
  */
-public class SocketAddressResolver
+public interface SocketAddressResolver
 {
-    private static final Logger LOG = Log.getLogger(SocketAddressResolver.class);
-
-    private final Executor executor;
-    private final Scheduler scheduler;
-    private final long timeout;
-
-    /**
-     * Creates a new instance with the given executor (to perform DNS resolution in a separate thread),
-     * the given scheduler (to cancel the operation if it takes too long) and the given timeout, in milliseconds.
-     *
-     * @param executor the thread pool to use to perform DNS resolution in pooled threads
-     * @param scheduler the scheduler to schedule tasks to cancel DNS resolution if it takes too long
-     * @param timeout the timeout, in milliseconds, for the DNS resolution to complete
-     */
-    public SocketAddressResolver(Executor executor, Scheduler scheduler, long timeout)
-    {
-        this.executor = executor;
-        this.scheduler = scheduler;
-        this.timeout = timeout;
-    }
-
-    public Executor getExecutor()
-    {
-        return executor;
-    }
-
-    public Scheduler getScheduler()
-    {
-        return scheduler;
-    }
-
-    public long getTimeout()
-    {
-        return timeout;
-    }
-
     /**
      * Resolves the given host and port, returning a {@link SocketAddress} through the given {@link Promise}
      * with the default timeout.
@@ -101,75 +42,149 @@ public class SocketAddressResolver
      * @param host the host to resolve
      * @param port the port of the resulting socket address
      * @param promise the callback invoked when the resolution succeeds or fails
-     * @see #resolve(String, int, long, Promise)
      */
-    public void resolve(String host, int port, Promise<SocketAddress> promise)
+    public void resolve(String host, int port, Promise<SocketAddress> promise);
+
+    /**
+     * <p>Creates {@link SocketAddress} instances synchronously in the caller thread.</p>
+     */
+    public static class Sync implements SocketAddressResolver
     {
-        resolve(host, port, timeout, promise);
+        @Override
+        public void resolve(String host, int port, Promise<SocketAddress> promise)
+        {
+            try
+            {
+                InetSocketAddress result = new InetSocketAddress(host, port);
+                if (result.isUnresolved())
+                    promise.failed(new UnresolvedAddressException());
+                else
+                    promise.succeeded(result);
+            }
+            catch (Throwable x)
+            {
+                promise.failed(x);
+            }
+        }
     }
 
     /**
-     * Resolves the given host and port, returning a {@link SocketAddress} through the given {@link Promise}
-     * with the given timeout.
+     * <p>Creates {@link SocketAddress} instances asynchronously in a different thread.</p>
+     * <p>{@link InetSocketAddress#InetSocketAddress(String, int)} attempts to perform a DNS
+     * resolution of the host name, and this may block for several seconds.
+     * This class creates the {@link InetSocketAddress} in a separate thread and provides the result
+     * through a {@link Promise}, with the possibility to specify a timeout for the operation.</p>
+     * <p>Example usage:</p>
+     * <pre>
+     * SocketAddressResolver resolver = new SocketAddressResolver.Async(executor, scheduler, timeout);
+     * resolver.resolve("www.google.com", 80, new Promise&lt;SocketAddress&gt;()
+     * {
+     *     public void succeeded(SocketAddress result)
+     *     {
+     *         // The address was resolved
+     *     }
      *
-     * @param host the host to resolve
-     * @param port the port of the resulting socket address
-     * @param timeout the timeout, in milliseconds, for the DNS resolution to complete
-     * @param promise the callback invoked when the resolution succeeds or fails
+     *     public void failed(Throwable failure)
+     *     {
+     *         // The address resolution failed
+     *     }
+     * });
+     * </pre>
      */
-    protected void resolve(final String host, final int port, final long timeout, final Promise<SocketAddress> promise)
+    public static class Async implements SocketAddressResolver
     {
-        executor.execute(new Runnable()
+        private static final Logger LOG = Log.getLogger(SocketAddressResolver.class);
+
+        private final Executor executor;
+        private final Scheduler scheduler;
+        private final long timeout;
+
+        /**
+         * Creates a new instance with the given executor (to perform DNS resolution in a separate thread),
+         * the given scheduler (to cancel the operation if it takes too long) and the given timeout, in milliseconds.
+         *
+         * @param executor  the thread pool to use to perform DNS resolution in pooled threads
+         * @param scheduler the scheduler to schedule tasks to cancel DNS resolution if it takes too long
+         * @param timeout   the timeout, in milliseconds, for the DNS resolution to complete
+         */
+        public Async(Executor executor, Scheduler scheduler, long timeout)
+        {
+            this.executor = executor;
+            this.scheduler = scheduler;
+            this.timeout = timeout;
+        }
+
+        public Executor getExecutor()
+        {
+            return executor;
+        }
+
+        public Scheduler getScheduler()
+        {
+            return scheduler;
+        }
+
+        public long getTimeout()
         {
-            @Override
-            public void run()
+            return timeout;
+        }
+
+        @Override
+        public void resolve(final String host, final int port, final Promise<SocketAddress> promise)
+        {
+            executor.execute(new Runnable()
             {
-                Scheduler.Task task = null;
-                final AtomicBoolean complete = new AtomicBoolean();
-                if (timeout > 0)
+                @Override
+                public void run()
                 {
-                    final Thread thread = Thread.currentThread();
-                    task = scheduler.schedule(new Runnable()
+                    Scheduler.Task task = null;
+                    final AtomicBoolean complete = new AtomicBoolean();
+                    if (timeout > 0)
                     {
-                        @Override
-                        public void run()
+                        final Thread thread = Thread.currentThread();
+                        task = scheduler.schedule(new Runnable()
                         {
-                            if (complete.compareAndSet(false, true))
+                            @Override
+                            public void run()
                             {
-                                promise.failed(new TimeoutException());
-                                thread.interrupt();
+                                if (complete.compareAndSet(false, true))
+                                {
+                                    promise.failed(new TimeoutException());
+                                    thread.interrupt();
+                                }
                             }
-                        }
-                    }, timeout, TimeUnit.MILLISECONDS);
-                }
+                        }, timeout, TimeUnit.MILLISECONDS);
+                    }
 
-                try
-                {
-                    long start = System.nanoTime();
-                    InetSocketAddress result = new InetSocketAddress(host, port);
-                    long elapsed = System.nanoTime() - start;
-                    LOG.debug("Resolved {} in {} ms", host, TimeUnit.NANOSECONDS.toMillis(elapsed));
-                    if (complete.compareAndSet(false, true))
+                    try
                     {
-                        if (result.isUnresolved())
-                            promise.failed(new UnresolvedAddressException());
-                        else
-                            promise.succeeded(result);
+                        long start = System.nanoTime();
+                        InetSocketAddress result = new InetSocketAddress(host, port);
+                        long elapsed = System.nanoTime() - start;
+                        if (LOG.isDebugEnabled())
+                            LOG.debug("Resolved {} in {} ms", host, TimeUnit.NANOSECONDS.toMillis(elapsed));
+                        if (complete.compareAndSet(false, true))
+                        {
+                            if (result.isUnresolved())
+                                promise.failed(new UnresolvedAddressException());
+                            else
+                                promise.succeeded(result);
+                        }
+                    }
+                    catch (Throwable x)
+                    {
+                        if (complete.compareAndSet(false, true))
+                            promise.failed(x);
+                    }
+                    finally
+                    {
+                        if (task != null)
+                            task.cancel();
+                        // Reset the interrupted status before releasing the thread to the pool
+                        Thread.interrupted();
                     }
                 }
-                catch (Throwable x)
-                {
-                    if (complete.compareAndSet(false, true))
-                        promise.failed(x);
-                }
-                finally
-                {
-                    if (task != null)
-                        task.cancel();
-                    // Reset the interrupted status before releasing the thread to the pool
-                    Thread.interrupted();
-                }
-            }
-        });
+            });
+        }
     }
 }
index 55868ad5edd9039d36e33e3094dd27729a18ffc4..9dbd9e49b73daf30b271938f40a5e3a05e3387ba 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -21,6 +21,8 @@ package org.eclipse.jetty.util;
 import java.io.UnsupportedEncodingException;
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
 
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
@@ -43,8 +45,10 @@ public class StringUtil
     
     public static final String ALL_INTERFACES="0.0.0.0";
     public static final String CRLF="\015\012";
-    public static final String __LINE_SEPARATOR=
-        System.getProperty("line.separator","\n");
+    
+    /** @deprecated use {@link System#lineSeparator()} instead */
+    @Deprecated
+    public static final String __LINE_SEPARATOR = System.lineSeparator();
        
     public static final String __ISO_8859_1="ISO-8859-1";
     public final static String __UTF8="UTF-8";
@@ -370,6 +374,53 @@ public class StringUtil
         }
     }
 
+    /**
+     * Find the index of a control characters in String
+     * <p>
+     * This will return a result on the first occurrence of a control character, regardless if
+     * there are more than one.
+     * </p>
+     * <p>
+     * Note: uses codepoint version of {@link Character#isISOControl(int)} to support Unicode better.
+     * </p>
+     *
+     * <pre>
+     *   indexOfControlChars(null)      == -1
+     *   indexOfControlChars("")        == -1
+     *   indexOfControlChars("\r\n")    == 0
+     *   indexOfControlChars("\t")      == 0
+     *   indexOfControlChars("   ")     == -1
+     *   indexOfControlChars("a")       == -1
+     *   indexOfControlChars(".")       == -1
+     *   indexOfControlChars(";\n")     == 1
+     *   indexOfControlChars("abc\f")   == 3
+     *   indexOfControlChars("z\010")   == 1
+     *   indexOfControlChars(":\u001c") == 1
+     * </pre>
+     *
+     * @param str
+     *            the string to test.
+     * @return the index of first control character in string, -1 if no control characters encountered
+     */
+    public static int indexOfControlChars(String str)
+    {
+        if (str == null)
+        {
+            return -1;
+        }
+        int len = str.length();
+        for (int i = 0; i < len; i++)
+        {
+            if (Character.isISOControl(str.codePointAt(i)))
+            {
+                // found a control character, we can stop searching  now
+                return i;
+            }
+        }
+        // no control characters
+        return -1;
+    }
+
     /* ------------------------------------------------------------ */
     /**
      * Test if a string is null or only has whitespace characters in it.
@@ -719,6 +770,11 @@ public class StringUtil
         return str.substring(0,maxSize);
     }
 
+    /**
+    * Parse the string representation of a list using {@link #csvSplit(List,String,int,int)}
+    * @param s The string to parse, expected to be enclosed as '[...]'
+    * @return An array of parsed values.
+    */
     public static String[] arrayFromString(String s) 
     {
         if (s==null)
@@ -729,7 +785,249 @@ public class StringUtil
         if (s.length()==2)
             return new String[]{};
 
-        return s.substring(1,s.length()-1).split(" *, *");
+        return csvSplit(s,1,s.length()-2);
+    }
+    
+    /**
+    * Parse a CSV string using {@link #csvSplit(List,String, int, int)}
+    * @param s The string to parse
+    * @return An array of parsed values.
+    */
+    public static String[] csvSplit(String s)
+    {
+        if (s==null)
+            return null;
+        return csvSplit(s,0,s.length());
+    }
+    
+    /**
+     * Parse a CSV string using {@link #csvSplit(List,String, int, int)}
+     * @param s The string to parse
+     * @param off The offset into the string to start parsing
+     * @param len The len in characters to parse
+     * @return An array of parsed values.
+     */
+    public static String[] csvSplit(String s, int off,int len)
+    {
+        if (s==null)
+            return null;
+        if (off<0 || len<0 || off>s.length())
+            throw new IllegalArgumentException();
+
+        List<String> list = new ArrayList<>();
+        csvSplit(list,s,off,len);
+        return list.toArray(new String[list.size()]);
+    }
+
+    enum CsvSplitState { PRE_DATA, QUOTE, SLOSH, DATA, WHITE, POST_DATA };
+
+    /** Split a quoted comma separated string to a list
+     * <p>Handle <a href="https://www.ietf.org/rfc/rfc4180.txt">rfc4180</a>-like 
+     * CSV strings, with the exceptions:<ul>
+     * <li>quoted values may contain double quotes escaped with back-slash
+     * <li>Non-quoted values are trimmed of leading trailing white space
+     * <li>trailing commas are ignored
+     * <li>double commas result in a empty string value
+     * </ul>  
+     * @param list The Collection to split to (or null to get a new list)
+     * @param s The string to parse
+     * @param off The offset into the string to start parsing
+     * @param len The len in characters to parse
+     * @return list containing the parsed list values
+     */
+    public static List<String> csvSplit(List<String> list,String s, int off,int len)
+    {
+        if (list==null)
+            list=new ArrayList<>();
+        CsvSplitState state = CsvSplitState.PRE_DATA;
+        StringBuilder out = new StringBuilder();
+        int last=-1;
+        while (len>0)
+        {
+            char ch = s.charAt(off++);
+            len--;
+            
+            switch(state)
+            {
+                case PRE_DATA:
+                    if (Character.isWhitespace(ch))
+                        continue;
+
+                    if ('"'==ch)
+                    {
+                        state=CsvSplitState.QUOTE;
+                        continue;
+                    }
+                    
+                    if (','==ch)
+                    {
+                        list.add("");
+                        continue;
+                    }
+
+                    state=CsvSplitState.DATA;
+                    out.append(ch);
+                    continue;
+
+                case DATA:
+                    if (Character.isWhitespace(ch))
+                    {
+                        last=out.length();
+                        out.append(ch);
+                        state=CsvSplitState.WHITE;
+                        continue;
+                    }
+                    
+                    if (','==ch)
+                    {
+                        list.add(out.toString());
+                        out.setLength(0);
+                        state=CsvSplitState.PRE_DATA;
+                        continue;
+                    }
+
+                    out.append(ch);
+                    continue;
+                    
+                case WHITE:
+                    if (Character.isWhitespace(ch))
+                    {
+                        out.append(ch);
+                        continue;
+                    }
+                    
+                    if (','==ch)
+                    {
+                        out.setLength(last);
+                        list.add(out.toString());
+                        out.setLength(0);
+                        state=CsvSplitState.PRE_DATA;
+                        continue;
+                    }
+                    
+                    state=CsvSplitState.DATA;
+                    out.append(ch);
+                    last=-1;
+                    continue;
+
+                case QUOTE:
+                    if ('\\'==ch)
+                    {
+                        state=CsvSplitState.SLOSH;
+                        continue;
+                    }
+                    if ('"'==ch)
+                    {
+                        list.add(out.toString());
+                        out.setLength(0);
+                        state=CsvSplitState.POST_DATA;
+                        continue;
+                    }
+                    out.append(ch);
+                    continue;
+                    
+                case SLOSH:
+                    out.append(ch);
+                    state=CsvSplitState.QUOTE;
+                    continue;
+                    
+                case POST_DATA:
+                    if (','==ch)
+                    {
+                        state=CsvSplitState.PRE_DATA;
+                        continue;
+                    }
+                    continue;
+            }
+        }
+
+        switch(state)
+        {
+            case PRE_DATA:
+            case POST_DATA:
+                break;
+
+            case DATA:
+            case QUOTE:
+            case SLOSH:
+                list.add(out.toString());
+                break;
+                
+            case WHITE:
+                out.setLength(last);
+                list.add(out.toString());
+                break;
+        }
+        
+        return list;
+    }
+
+    public static String sanitizeXmlString(String html)
+    {
+        if (html==null)
+            return null;
+        
+        int i=0;
+        
+        // Are there any characters that need sanitizing?
+        loop: for (;i<html.length();i++)
+        {
+            char c=html.charAt(i);
+
+            switch(c)
+            {
+                case '&' :
+                case '<' :
+                case '>' :
+                case '\'':
+                case '"':
+                    break loop;
+
+                default:
+                    if (Character.isISOControl(c) && !Character.isWhitespace(c))
+                        break loop;
+            }
+        }
+
+        // No characters need sanitizing, so return original string
+        if (i==html.length())
+            return html;
+        
+        // Create builder with OK content so far 
+        StringBuilder out = new StringBuilder(html.length()*4/3);
+        out.append(html,0,i);
+        
+        // sanitize remaining content
+        for (;i<html.length();i++)
+        {
+            char c=html.charAt(i);
+
+            switch(c)
+            {
+                case '&' :
+                    out.append("&amp;");
+                    break;
+                case '<' :
+                    out.append("&lt;");
+                    break;
+                case '>' :
+                    out.append("&gt;");
+                    break;
+                case '\'':
+                    out.append("&apos;");
+                    break;
+                case '"':
+                    out.append("&quot;");
+                    break;
+
+                default:
+                    if (Character.isISOControl(c) && !Character.isWhitespace(c))
+                        out.append('?');
+                    else
+                        out.append(c);
+            }
+        }
+        return out.toString();
     }
 
 }
index 42f3bdccaddc7857d8a352e2552eaf0d74686733..d791151ee13d29c3dbe2cbdf45b97b4cfeb282c0 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -31,6 +31,15 @@ import java.util.Set;
  * <p>This implementation is always case insensitive and is optimal for
  * a variable number of fixed strings with few special characters.
  * </p>
+ * <p>This Trie is stored in a Tree and is unlimited in capacity</p>
+ * 
+ * <p>This Trie is not Threadsafe and contains no mutual exclusion 
+ * or deliberate memory barriers.  It is intended for an ArrayTrie to be
+ * built by a single thread and then used concurrently by multiple threads
+ * and not mutated during that access.  If concurrent mutations of the
+ * Trie is required external locks need to be applied.
+ * </p>
+ * 
  * @param <V>
  */
 public class TreeTrie<V> extends AbstractTrie<V>
@@ -38,8 +47,8 @@ public class TreeTrie<V> extends AbstractTrie<V>
     private static final int[] __lookup = 
     { // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
    /*0*/-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-   /*1*/-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 30
-   /*2*/31, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, -1, 27, -1, -1,
+   /*1*/-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+   /*2*/31, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, -1, 27, 30, -1,
    /*3*/-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 28, 29, -1, -1, -1, -1,
    /*4*/-1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
    /*5*/15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
index 9c7492413c22fef00bf13afdb60586d934f86448..fd4459b901ebb1ff2b41d22cc0e31ccce916bcb4 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index b96a520c110e413329e7b811f889b46a838a07db..b71e29e8adf076a03b61d53517dbb7d46f210786 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -569,8 +569,9 @@ public class TypeUtil
                 
                 // target has no annotations
                 if ( parameterAnnotations == null || parameterAnnotations.length == 0 )
-                {                
-                    LOG.debug("Target has no parameter annotations");                   
+                {
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Target has no parameter annotations");
                     return constructor.newInstance(arguments);
                 }
                 else
@@ -588,19 +589,22 @@ public class TypeUtil
                                
                                if (namedArgMap.containsKey(param.value()))
                                {
-                                   LOG.debug("placing named {} in position {}", param.value(), count);
+                                   if (LOG.isDebugEnabled())
+                                       LOG.debug("placing named {} in position {}", param.value(), count);
                                    swizzled[count] = namedArgMap.get(param.value());
                                }
                                else
                                {
-                                   LOG.debug("placing {} in position {}", arguments[count], count);
+                                   if (LOG.isDebugEnabled())
+                                       LOG.debug("placing {} in position {}", arguments[count], count);
                                    swizzled[count] = arguments[count];
                                }
                                ++count;
                            }
                            else
                            {
-                               LOG.debug("passing on annotation {}", annotation);
+                               if (LOG.isDebugEnabled())
+                                   LOG.debug("passing on annotation {}", annotation);
                            }
                        }
                    }
index f333fc3b5f2f2106877540ac25f330907d069763..193a118081c8f0d001463cc348580f683efb4156 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -663,7 +663,49 @@ public class URIUtil
         }
         return false;
     }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * Create a new URI from the arguments, handling IPv6 host encoding and default ports
+     * @param scheme
+     * @param server
+     * @param port
+     * @param path
+     * @param query
+     * @return A String URI
+     */
+    public static String newURI(String scheme,String server, int port,String path,String query)
+    {
+        StringBuilder builder = newURIBuilder(scheme, server, port);
+        builder.append(path);
+        if (query!=null && query.length()>0)
+            builder.append('?').append(query);
+        return builder.toString();
+    }
     
+    /* ------------------------------------------------------------ */
+    /**
+     * Create a new URI StringBuilder from the arguments, handling IPv6 host encoding and default ports
+     * @param scheme
+     * @param server
+     * @param port
+     * @return a StringBuilder containing URI prefix
+     */
+    public static StringBuilder newURIBuilder(String scheme,String server, int port)
+    {
+        StringBuilder builder = new StringBuilder();
+        appendSchemeHostPort(builder, scheme, server, port);
+        return builder;
+    }
+
+    /* ------------------------------------------------------------ */
+    /** 
+     * Append scheme, host and port URI prefix, handling IPv6 address encoding and default ports</p>
+     * @param url StringBuilder to append to
+     * @param scheme
+     * @param server
+     * @param port
+     */
     public static void appendSchemeHostPort(StringBuilder url,String scheme,String server, int port)
     {
         if (server.indexOf(':')>=0&&server.charAt(0)!='[')
@@ -671,10 +713,34 @@ public class URIUtil
         else
             url.append(scheme).append("://").append(server);
 
-        if (port > 0 && (("http".equalsIgnoreCase(scheme) && port != 80) || ("https".equalsIgnoreCase(scheme) && port != 443)))
-            url.append(':').append(port);
+        if (port > 0)
+        {
+            switch(scheme)
+            {
+                case "http":
+                    if (port!=80) 
+                        url.append(':').append(port);
+                    break;
+                    
+                case "https":
+                    if (port!=443) 
+                        url.append(':').append(port);
+                    break;
+
+                default:
+                    url.append(':').append(port);
+            }
+        }
     }
     
+    /* ------------------------------------------------------------ */
+    /** 
+     * Append scheme, host and port URI prefix, handling IPv6 address encoding and default ports</p>
+     * @param url StringBuffer to append to
+     * @param scheme
+     * @param server
+     * @param port
+     */
     public static void appendSchemeHostPort(StringBuffer url,String scheme,String server, int port)
     {
         synchronized (url)
@@ -684,9 +750,53 @@ public class URIUtil
             else
                 url.append(scheme).append("://").append(server);
 
-            if (port > 0 && (("http".equalsIgnoreCase(scheme) && port != 80) || ("https".equalsIgnoreCase(scheme) && port != 443)))
-                url.append(':').append(port);
+            if (port > 0)
+            {
+                switch(scheme)
+                {
+                    case "http":
+                        if (port!=80) 
+                            url.append(':').append(port);
+                        break;
+                        
+                    case "https":
+                        if (port!=443) 
+                            url.append(':').append(port);
+                        break;
+
+                    default:
+                        url.append(':').append(port);
+                }
+            }
+        }
+    }
+
+    public static boolean equalsIgnoreEncodings(String uriA, String uriB)
+    {
+        int lenA=uriA.length();
+        int lenB=uriB.length();
+        int a=0;
+        int b=0;
+        
+        while (a<lenA && b<lenB)
+        {
+            int oa=uriA.charAt(a++);
+            int ca=oa;
+            if (ca=='%')
+                ca=TypeUtil.convertHexDigit(uriA.charAt(a++))*16+TypeUtil.convertHexDigit(uriA.charAt(a++));
+            
+            int ob=uriB.charAt(b++);
+            int cb=ob;
+            if (cb=='%')
+                cb=TypeUtil.convertHexDigit(uriB.charAt(b++))*16+TypeUtil.convertHexDigit(uriB.charAt(b++));
+            
+            if (ca=='/' && oa!=ob)
+                return false;
+            
+            if (ca!=cb )
+                return URIUtil.decodePath(uriA).equals(URIUtil.decodePath(uriB));
         }
+        return a==lenA && b==lenB;
     }
 }
 
diff --git a/lib/jetty/org/eclipse/jetty/util/Uptime.java b/lib/jetty/org/eclipse/jetty/util/Uptime.java
new file mode 100644 (file)
index 0000000..9daa525
--- /dev/null
@@ -0,0 +1,132 @@
+//
+//  ========================================================================
+//  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.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * Provide for a Uptime class that is compatible with Android, GAE, and the new Java 8 compact profiles
+ */
+public class Uptime
+{
+    public static final int NOIMPL = -1;
+
+    public static interface Impl
+    {
+        public long getUptime();
+    }
+
+    public static class DefaultImpl implements Impl
+    {
+        public Object mxBean;
+        public Method uptimeMethod;
+
+        public DefaultImpl()
+        {
+            ClassLoader cl = Thread.currentThread().getContextClassLoader();
+            try
+            {
+                Class<?> mgmtFactory = Class.forName("java.lang.management.ManagementFactory",true,cl);
+                Class<?> runtimeClass = Class.forName("java.lang.management.RuntimeMXBean",true,cl);
+                Class<?> noparams[] = new Class<?>[0];
+                Method mxBeanMethod = mgmtFactory.getMethod("getRuntimeMXBean",noparams);
+                if (mxBeanMethod == null)
+                {
+                    throw new UnsupportedOperationException("method getRuntimeMXBean() not found");
+                }
+                mxBean = mxBeanMethod.invoke(mgmtFactory);
+                if (mxBean == null)
+                {
+                    throw new UnsupportedOperationException("getRuntimeMXBean() method returned null");
+                }
+                uptimeMethod = runtimeClass.getMethod("getUptime",noparams);
+                if (mxBean == null)
+                {
+                    throw new UnsupportedOperationException("method getUptime() not found");
+                }
+            }
+            catch (ClassNotFoundException | 
+                   NoClassDefFoundError | 
+                   NoSuchMethodException | 
+                   SecurityException | 
+                   IllegalAccessException | 
+                   IllegalArgumentException | 
+                   InvocationTargetException e)
+            {
+                throw new UnsupportedOperationException("Implementation not available in this environment",e);
+            }
+        }
+
+        @Override
+        public long getUptime()
+        {
+            try
+            {
+                return (long)uptimeMethod.invoke(mxBean);
+            }
+            catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e)
+            {
+                return NOIMPL;
+            }
+        }
+    }
+
+    private static final Uptime INSTANCE = new Uptime();
+
+    public static Uptime getInstance()
+    {
+        return INSTANCE;
+    }
+
+    private Impl impl;
+
+    private Uptime()
+    {
+        try
+        {
+            impl = new DefaultImpl();
+        }
+        catch (UnsupportedOperationException e)
+        {
+            System.err.printf("Defaulting Uptime to NOIMPL due to (%s) %s%n",e.getClass().getName(),e.getMessage());
+            impl = null;
+        }
+    }
+
+    public Impl getImpl()
+    {
+        return impl;
+    }
+
+    public void setImpl(Impl impl)
+    {
+        this.impl = impl;
+    }
+
+    public static long getUptime()
+    {
+        Uptime u = getInstance();
+        if (u == null || u.impl == null)
+        {
+            return NOIMPL;
+        }
+        return u.impl.getUptime();
+    }
+}
index ef7f2f5fa9ef88ca04a24bcd720713ad34756067..a893fc9bc6130fd9bdcc9ca35b60947d9c9351da 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -684,87 +684,89 @@ public class UrlEncoded extends MultiMap<String> implements Cloneable
             int c;
             
             int totalLength = 0;
-            ByteArrayOutputStream2 output = new ByteArrayOutputStream2();
             
-            int size=0;
-            
-            while ((c=in.read())>0)
+            try(ByteArrayOutputStream2 output = new ByteArrayOutputStream2();)
             {
-                switch ((char) c)
+                int size=0;
+
+                while ((c=in.read())>0)
                 {
-                    case '&':
-                        size=output.size();
-                        value = size==0?"":output.toString(charset);
-                        output.setCount(0);
-                        if (key != null)
-                        {
-                            map.add(key,value);
-                        }
-                        else if (value!=null&&value.length()>0)
-                        {
-                            map.add(value,"");
-                        }
-                        key = null;
-                        value=null;
-                        if (maxKeys>0 && map.size()>maxKeys)
-                            throw new IllegalStateException("Form too many keys");
-                        break;
-                    case '=':
-                        if (key!=null)
-                        {
-                            output.write(c);
+                    switch ((char) c)
+                    {
+                        case '&':
+                            size=output.size();
+                            value = size==0?"":output.toString(charset);
+                            output.setCount(0);
+                            if (key != null)
+                            {
+                                map.add(key,value);
+                            }
+                            else if (value!=null&&value.length()>0)
+                            {
+                                map.add(value,"");
+                            }
+                            key = null;
+                            value=null;
+                            if (maxKeys>0 && map.size()>maxKeys)
+                                throw new IllegalStateException("Form too many keys");
                             break;
-                        }
-                        size=output.size();
-                        key = size==0?"":output.toString(charset);
-                        output.setCount(0);
-                        break;
-                    case '+':
-                        output.write(' ');
-                        break;
-                    case '%':
-                        int code0=in.read();
-                        if ('u'==code0)
-                        {
-                            int code1=in.read();
-                            if (code1>=0)
+                        case '=':
+                            if (key!=null)
                             {
-                                int code2=in.read();
-                                if (code2>=0)
+                                output.write(c);
+                                break;
+                            }
+                            size=output.size();
+                            key = size==0?"":output.toString(charset);
+                            output.setCount(0);
+                            break;
+                        case '+':
+                            output.write(' ');
+                            break;
+                        case '%':
+                            int code0=in.read();
+                            if ('u'==code0)
+                            {
+                                int code1=in.read();
+                                if (code1>=0)
                                 {
-                                    int code3=in.read();
-                                    if (code3>=0)
-                                        output.write(new String(Character.toChars((convertHexDigit(code0)<<12)+(convertHexDigit(code1)<<8)+(convertHexDigit(code2)<<4)+convertHexDigit(code3))).getBytes(charset));
+                                    int code2=in.read();
+                                    if (code2>=0)
+                                    {
+                                        int code3=in.read();
+                                        if (code3>=0)
+                                            output.write(new String(Character.toChars((convertHexDigit(code0)<<12)+(convertHexDigit(code1)<<8)+(convertHexDigit(code2)<<4)+convertHexDigit(code3))).getBytes(charset));
+                                    }
                                 }
+
                             }
-                            
-                        }
-                        else if (code0>=0)
-                        {
-                            int code1=in.read();
-                            if (code1>=0)
-                                output.write((convertHexDigit(code0)<<4)+convertHexDigit(code1));
-                        }
-                        break;
-                    default:
-                        output.write(c);
-                    break;
+                            else if (code0>=0)
+                            {
+                                int code1=in.read();
+                                if (code1>=0)
+                                    output.write((convertHexDigit(code0)<<4)+convertHexDigit(code1));
+                            }
+                            break;
+                        default:
+                            output.write(c);
+                            break;
+                    }
+
+                    totalLength++;
+                    if (maxLength>=0 && totalLength > maxLength)
+                        throw new IllegalStateException("Form too large");
                 }
-                
-                totalLength++;
-                if (maxLength>=0 && totalLength > maxLength)
-                    throw new IllegalStateException("Form too large");
-            }
 
-            size=output.size();
-            if (key != null)
-            {
-                value = size==0?"":output.toString(charset);
-                output.setCount(0);
-                map.add(key,value);
+                size=output.size();
+                if (key != null)
+                {
+                    value = size==0?"":output.toString(charset);
+                    output.setCount(0);
+                    map.add(key,value);
+                }
+                else if (size>0)
+                    map.add(output.toString(charset),"");
             }
-            else if (size>0)
-                map.add(output.toString(charset),"");
         }
     }
     
index ff58764ad7dd45d4507dd0af010ee7eb0732da66..d7136986fc5c426030af874286ab24915967b924 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index b54cf41939180c3e9c8f7414fc1ee53f4f7c2222..0332d9893d8631f875b5c52282ec91ab10e5a9f8 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -20,8 +20,6 @@ package org.eclipse.jetty.util;
 
 import java.nio.ByteBuffer;
 
-import org.eclipse.jetty.util.Utf8Appendable.NotUtf8Exception;
-
 /**
  * Stateful parser for lines of UTF8 formatted text, looking for <code>"\n"</code> as a line termination character.
  * <p>
index 63fb1aca222aa7cc530ebba9f5c8fe99ef5a7c16..4f6a0c509a026db9f7e55eb500261ddfcb093aad 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 28fa20b65e687354dd34bfae9f88b5ddf0a189c8..de6917882869b12f093335ea75148654408e25f5 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 29a805fe71e7caa98be49e3f95676592750c99ef..a113c30fa1df8711afa8a347944856e2c2507404 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 15f4b550e3fac693cd5c151aadbe298b260f8d3a..e2e7d1de89b09c93f42d62ee6f49bfa2413adad0 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 3a29368f6b89f324a59b17d4ad5c185d67f56787..1dd9791c5cae67ef675a616704521c3239ec69e0 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index b79e76e9cf3b7b2ee1a872b2e3866ea08de54fe5..c6905996a2f1e21d5ac0c47e6e65d194205a10b7 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 5f0038b2bcb2adc010b0c518d51f3c48b228f159..c91a83a1b47c7a2ffec24cacb715562d8b1f76e3 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 8f2d9dc7ab02447bad8e8abf2c28994acc481e0d..4aef3418f49386ba9ddb2a3d488c12260aa0a181 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -18,9 +18,9 @@
 
 package org.eclipse.jetty.util.component;
 
-import java.lang.management.ManagementFactory;
 import java.util.concurrent.CopyOnWriteArrayList;
 
+import org.eclipse.jetty.util.Uptime;
 import org.eclipse.jetty.util.annotation.ManagedAttribute;
 import org.eclipse.jetty.util.annotation.ManagedObject;
 import org.eclipse.jetty.util.log.Log;
@@ -174,15 +174,15 @@ public abstract class AbstractLifeCycle implements LifeCycle
     {
         _state = __STARTED;
         if (LOG.isDebugEnabled())
-            
-        LOG.debug(STARTED+" @{}ms {}",ManagementFactory.getRuntimeMXBean().getUptime(),this);
+            LOG.debug(STARTED+" @{}ms {}",Uptime.getUptime(),this);
         for (Listener listener : _listeners)
             listener.lifeCycleStarted(this);
     }
 
     private void setStarting()
     {
-        LOG.debug("starting {}",this);
+        if (LOG.isDebugEnabled())
+            LOG.debug("starting {}",this);
         _state = __STARTING;
         for (Listener listener : _listeners)
             listener.lifeCycleStarting(this);
@@ -190,7 +190,8 @@ public abstract class AbstractLifeCycle implements LifeCycle
 
     private void setStopping()
     {
-        LOG.debug("stopping {}",this);
+        if (LOG.isDebugEnabled())
+            LOG.debug("stopping {}",this);
         _state = __STOPPING;
         for (Listener listener : _listeners)
             listener.lifeCycleStopping(this);
@@ -199,7 +200,8 @@ public abstract class AbstractLifeCycle implements LifeCycle
     private void setStopped()
     {
         _state = __STOPPED;
-        LOG.debug("{} {}",STOPPED,this);
+        if (LOG.isDebugEnabled())
+            LOG.debug("{} {}",STOPPED,this);
         for (Listener listener : _listeners)
             listener.lifeCycleStopped(this);
     }
index a5a4c75898ee50741e72c869b41bc48ce28484f8..878800434a372550444e56c20f29a725a8b85f6c 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 464c0f7e4a88b18e2540b9c99d609076f4b91ecc..4756bc12a092fa0fc09bb737cac94ceb6c3bc016 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -320,7 +320,8 @@ public class ContainerLifeCycle extends AbstractLifeCycle implements Container,
             throw new RuntimeException(e);
         }
 
-        LOG.debug("{} added {}",this,new_bean);
+        if (LOG.isDebugEnabled())
+            LOG.debug("{} added {}",this,new_bean);
 
         return true;
     }
@@ -523,6 +524,7 @@ public class ContainerLifeCycle extends AbstractLifeCycle implements Container,
     {
         if (_beans.remove(bean))
         {
+            boolean wasManaged = bean.isManaged();
             
             unmanage(bean);
 
@@ -533,7 +535,7 @@ public class ContainerLifeCycle extends AbstractLifeCycle implements Container,
                 removeEventListener((Container.Listener)bean._bean);
 
             // stop managed beans
-            if (bean._managed==Managed.MANAGED && bean._bean instanceof LifeCycle)
+            if (wasManaged && bean._bean instanceof LifeCycle)
             {
                 try
                 {
index 2e7e441ce0deb7b2b2b520247ba17669be8a8879..8a7730f2f67b10c665efc9a8349524212e4530ca 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 2a1882bccaa0cc0be3110720146126f4601b9386..6ac3d20da8ee794f84d46622060dedd3f5bbb67b 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 94936452bd38ec5e017a545d4c8b6ae7eb708c57..dd1a8c5a2755f328dee581ab041f89d880a53efe 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -86,7 +86,8 @@ public class FileDestroyable implements Destroyable
         {
             if (file.exists())
             {
-                LOG.debug("Destroy {}",file);
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Destroy {}",file);
                 IO.delete(file);
             }
         }
index 1c4dcecd1cb60ef6ea81cbcb58cc045198d016a3..4233b79b937d35e75e50c5c6bc75d74344d5e401 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 96bec3364cab9a6cbd94292881793026758355ac..025309227c98ac21c0fc6aa1ef004d2f8847a566 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index f58fd1a55f295e8ae7073d3be9c0a31ab508f21e..b064d54214f3ac81eb58bfa60204b559a67009ee 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 2ae3d1983b85dcdc4c52a69018713067be11c58c..42b27e13a6f2d0febd08125f8fec1fd12288edf2 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 66453768a2225b899330b1be60f33d58016c6931..e061ae7b29be5d5aed8c2a331dc8a5a0d020c53f 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -79,6 +79,8 @@ public abstract class AbstractLogger implements Logger
     public void debug(String msg, long arg)
     {
         if (isDebugEnabled())
-            debug(msg,new Long(arg));
+        {
+            debug(msg,new Object[] { new Long(arg) });
+        }
     }
 }
index 094d97838eadf4e632fcd6c56e8d0c824895ad35..70498e4166c62ce44fbb2355afc9fabf674e63df 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 91b61f9a64fb5c9bdbfde5394d9096e8b534cc33..b33b5f2b59010cbae2643d8ec3f8b61c8987945f 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -20,7 +20,6 @@ package org.eclipse.jetty.util.log;
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.lang.management.ManagementFactory;
 import java.lang.reflect.Method;
 import java.net.URL;
 import java.security.AccessController;
@@ -34,6 +33,7 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
 import org.eclipse.jetty.util.Loader;
+import org.eclipse.jetty.util.Uptime;
 import org.eclipse.jetty.util.annotation.ManagedAttribute;
 
 /**
@@ -167,8 +167,6 @@ public class Log
                 return;
             __initialized = true;
 
-            final long uptime=ManagementFactory.getRuntimeMXBean().getUptime();
-
             try
             {
                 Class<?> log_class = Loader.loadClass(Log.class, __logClass);
@@ -185,7 +183,7 @@ public class Log
             }
 
             if (LOG!=null)
-                LOG.info(String.format("Logging initialized @%dms",uptime));
+                LOG.info(String.format("Logging initialized @%dms",Uptime.getUptime()));
         }
     }
 
index ac6e0861a1e6f14d61f4d68f42b5bdbf30498c42..e02acc4a7ce5b89e5900302c5e1cc7919dac1023 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 1026cb07d03181bf828d754f06ed6bf9ee13a8ad..d4a7d41d0cd95b720c8eea7fcef928f65767cc5d 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index fd6fb327dd81005f514478d68028d7e40c2ee14c..0b5de612f80bc8098cca7cb1e6e99d15eb74e461 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index fda1c722b5b0ec48273c3ff4a4c50178a4c6960c..b8bf5aa86f95d974ee4ac7725f9341f99b6e96a4 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -239,6 +239,12 @@ public class StdErrLog extends AbstractLogger
      */
     public static int getLoggingLevel(Properties props, final String name)
     {
+        if ((props == null) || (props.isEmpty()))
+        {
+            // Default Logging Level
+            return getLevelId("log.LEVEL","INFO");
+        }
+        
         // Calculate the level this named logger should operate under.
         // Checking with FQCN first, then each package segment from longest to shortest.
         String nameSegment = name;
@@ -688,7 +694,12 @@ public class StdErrLog extends AbstractLogger
             builder.append(string);
     }
 
-    private void format(StringBuilder buffer, Throwable thrown)
+    protected void format(StringBuilder buffer, Throwable thrown)
+    {
+        format(buffer,thrown,"");
+    }
+    
+    protected void format(StringBuilder buffer, Throwable thrown, String indent)
     {
         if (thrown == null)
         {
@@ -696,20 +707,26 @@ public class StdErrLog extends AbstractLogger
         }
         else
         {
-            buffer.append(EOL);
+            buffer.append(EOL).append(indent);
             format(buffer,thrown.toString());
             StackTraceElement[] elements = thrown.getStackTrace();
             for (int i = 0; elements != null && i < elements.length; i++)
             {
-                buffer.append(EOL).append("\tat ");
+                buffer.append(EOL).append(indent).append("\tat ");
                 format(buffer,elements[i].toString());
             }
 
+            for (Throwable suppressed:thrown.getSuppressed())
+            {
+                buffer.append(EOL).append(indent).append("Suppressed: ");
+                format(buffer,suppressed,"\t|"+indent);
+            }
+            
             Throwable cause = thrown.getCause();
             if (cause != null && cause != thrown)
             {
-                buffer.append(EOL).append("Caused by: ");
-                format(buffer,cause);
+                buffer.append(EOL).append(indent).append("Caused by: ");
+                format(buffer,cause,indent);
             }
         }
     }
index 27166b69150155d23670858e78102375d38283a4..5a791eaee4e0e2a3aae12fc2eeb210f47f46295c 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 6545cbee418bcd7272105754ddff84760966052b..df73857a9abd08d49d8f03647c0d7cbf9ccb7276 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 0f6caf9b0726876384a87d33fe7633fb832fc673..0c4439f46380a80578de60df35d21a3dcc260ef1 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -40,7 +40,8 @@ public class AWTLeakPreventer extends AbstractLeakPreventer
     @Override
     public void prevent(ClassLoader loader)
     {
-        LOG.debug("Pinning classloader for java.awt.EventQueue using "+loader);
+        if (LOG.isDebugEnabled())
+            LOG.debug("Pinning classloader for java.awt.EventQueue using "+loader);
         Toolkit.getDefaultToolkit();
     }
 
index 2322a762435fe2f2793dcd796ec7526113a35940..48b449ae51ee2a402eb1db224ece3de9f7a8c846 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 0cfd3c9553d29a6bcc876638fe23ca6c23fc085c..abadd654f39bc8f16b128f8fcd374e433691a5ad 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -34,7 +34,8 @@ public class AppContextLeakPreventer extends AbstractLeakPreventer
     @Override
     public void prevent(ClassLoader loader)
     {
-        LOG.debug("Pinning classloader for AppContext.getContext() with "+loader);
+        if (LOG.isDebugEnabled())
+            LOG.debug("Pinning classloader for AppContext.getContext() with "+loader);
         ImageIO.getUseCache();
     }
 
index 5fee3659bfec1ad9095dda8c5af24571173d7b55..cc0846cada8777f843f7b16033918132d4746650 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index d229ba740aa1920fdc88395d720177a4734e5693..b919af32e515db489623e0869785bdb952644fe5 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -35,7 +35,8 @@ public class DriverManagerLeakPreventer extends AbstractLeakPreventer
     @Override
     public void prevent(ClassLoader loader)
     {
-        LOG.debug("Pinning DriverManager classloader with "+loader);
+        if (LOG.isDebugEnabled())
+            LOG.debug("Pinning DriverManager classloader with "+loader);
         DriverManager.getDrivers();
     }
 
index 6ea4de2e16d9f4cd31778a88a9c52e568ba1c998..037fa57eb003dd8966b0e2a019d0aac900e637f8 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -47,7 +47,7 @@ public class GCThreadLeakPreventer extends AbstractLeakPreventer
     {
         try
         {
-            Class clazz = Class.forName("sun.misc.GC");
+            Class<?> clazz = Class.forName("sun.misc.GC");
             Method requestLatency = clazz.getMethod("requestLatency", new Class[] {long.class});
             requestLatency.invoke(null, Long.valueOf(Long.MAX_VALUE-1));
         }
index 3a2ad823b8076032954f6b6d63715379d3b09d79..9219889cd67f5782fc3350c1e989c3868d02aefb 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 5c497d1c26b1e25fb6fbfc90a9d27ca5065f95da..966a45d9c7e97a7e51511b493ed6710b6af29ad3 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index c1d9fe28111916ce2a6e1e7a1085973e583b5523..cb7a2a231196e5e8ddc6dd658edc93191a4224eb 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 9976c560cac35a0051974ff490661dd119de2554..a9487679d537b0bc699d9ca7f2947235ce666138 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index a6800e8ac563912c87cafa7bb1586c63391802f2..101802141a93c01977a198aec2203979c89c7885 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 72a9ed4c0a1ab12c06a2392acfa3f4ce07326ac0..764aa307b13fdbdde599a61174142ee8a9c527c0 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 3dad17b302e2b9b45f0972c8f9200071cf14a8d7..e381432d865acb3adf1ec9559af6f57c4ecb6d08 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 449884241b6fb5dd881d9c6f93086c146499205c..dbc4670a727a8184c159ce9ea574582bd41d42ee 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -29,10 +29,12 @@ import java.net.URL;
 import java.net.URLConnection;
 import java.nio.channels.FileChannel;
 import java.nio.channels.ReadableByteChannel;
+import java.nio.file.InvalidPathException;
 import java.nio.file.StandardOpenOption;
 import java.security.Permission;
 
 import org.eclipse.jetty.util.IO;
+import org.eclipse.jetty.util.StringUtil;
 import org.eclipse.jetty.util.URIUtil;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
@@ -65,6 +67,7 @@ public class FileResource extends Resource
         {
             // Try standard API to convert URL to file.
             file =new File(url.toURI());
+            assertValidPath(file.toString());
         }
         catch (URISyntaxException e) 
         {
@@ -98,7 +101,7 @@ public class FileResource extends Resource
         
         _file=file;
         _uri=normalizeURI(_file,url.toURI());
-        _alias=checkAlias(_file);
+        _alias=checkFileAlias(_file);
     }
 
     /* -------------------------------------------------------- */
@@ -108,25 +111,22 @@ public class FileResource extends Resource
         _file=file;
         URI file_uri=_file.toURI();
         _uri=normalizeURI(_file,uri);
-        
-        if (!_uri.equals(file_uri.toString()))
-        {
-            // URI and File URI are different.  Is it just an encoding difference?
-            if (!file_uri.toString().equals(URIUtil.decodePath(uri.toString())))
-                 _alias=_file.toURI();
-            else
-                _alias=checkAlias(_file);
-        }
+        assertValidPath(file.toString());
+
+        // Is it a URI alias?
+        if (!URIUtil.equalsIgnoreEncodings(_uri,file_uri.toString()))
+            _alias=_file.toURI();
         else
-            _alias=checkAlias(_file);
+            _alias=checkFileAlias(_file);
     }
 
     /* -------------------------------------------------------- */
     FileResource(File file)
     {
+        assertValidPath(file.toString());
         _file=file;
         _uri=normalizeURI(_file,_file.toURI());
-        _alias=checkAlias(_file);
+        _alias=checkFileAlias(_file);
     }
 
     /* -------------------------------------------------------- */
@@ -144,7 +144,7 @@ public class FileResource extends Resource
     }
 
     /* -------------------------------------------------------- */
-    private static URI checkAlias(File file)
+    private static URI checkFileAlias(File file)
     {
         try
         {
@@ -153,7 +153,8 @@ public class FileResource extends Resource
 
             if (!abs.equals(can))
             {
-                LOG.debug("ALIAS abs={} can={}",abs,can);
+                if (LOG.isDebugEnabled())
+                    LOG.debug("ALIAS abs={} can={}",abs,can);
 
                 URI alias=new File(can).toURI();
                 // Have to encode the path as File.toURI does not!
@@ -183,6 +184,7 @@ public class FileResource extends Resource
     public Resource addPath(String path)
         throws IOException,MalformedURLException
     {
+        assertValidPath(path);
         path = org.eclipse.jetty.util.URIUtil.canonicalPath(path);
 
         if (path==null)
@@ -208,13 +210,21 @@ public class FileResource extends Resource
         }
         catch(final URISyntaxException e)
         {
-            throw new MalformedURLException(){{initCause(e);}};
+            throw new InvalidPathException(path, e.getMessage());
         }
 
         return new FileResource(uri);
     }
-   
-    
+
+    private void assertValidPath(String path)
+    {
+        int idx = StringUtil.indexOfControlChars(path);
+        if (idx >= 0)
+        {
+            throw new InvalidPathException(path, "Invalid Character at index " + idx);
+        }
+    }
+
     /* ------------------------------------------------------------ */
     @Override
     public URI getAlias()
index 434aa88756502419d59d95ea15c68b75b8c14199..ccb15ae070825200202765d3233598122ee5a5b4 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -73,7 +73,8 @@ class JarFileResource extends JarResource
             {
                 try
                 {
-                    LOG.debug("Closing JarFile "+_jarFile.getName());
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Closing JarFile "+_jarFile.getName());
                     _jarFile.close();
                 }
                 catch ( IOException ioe )
@@ -135,6 +136,7 @@ class JarFileResource extends JarResource
      * Returns true if the represented resource exists.
      */
     @Override
+
     public boolean exists()
     {
         if (_exists)
@@ -160,10 +162,11 @@ class JarFileResource extends JarResource
         else 
         {
             // Can we find a file for it?
-            JarFile jarFile=null;
+            boolean close_jar_file= false;
+            JarFile jar_file=null;
             if (check)
                 // Yes
-                jarFile=_jarFile;
+                jar_file=_jarFile;
             else
             {
                 // No - so lets look if the root entry exists.
@@ -171,7 +174,8 @@ class JarFileResource extends JarResource
                 {
                     JarURLConnection c=(JarURLConnection)((new URL(_jarUrl)).openConnection());
                     c.setUseCaches(getUseCaches());
-                    jarFile=c.getJarFile();
+                    jar_file=c.getJarFile();
+                    close_jar_file = !getUseCaches();
                 }
                 catch(Exception e)
                 {
@@ -180,10 +184,10 @@ class JarFileResource extends JarResource
             }
 
             // Do we need to look more closely?
-            if (jarFile!=null && _entry==null && !_directory)
+            if (jar_file!=null && _entry==null && !_directory)
             {
                 // OK - we have a JarFile, lets look at the entries for our path
-                Enumeration<JarEntry> e=jarFile.entries();
+                Enumeration<JarEntry> e=jar_file.entries();
                 while(e.hasMoreElements())
                 {
                     JarEntry entry = e.nextElement();
@@ -212,6 +216,18 @@ class JarFileResource extends JarResource
                     }
                 }
             }
+
+            if(close_jar_file && jar_file!=null) 
+            {
+                try 
+                {
+                    jar_file.close();
+                } 
+                catch (IOException ioe) 
+                {
+                    LOG.ignore(ioe);
+                }
+            }
         }    
         
         _exists= ( _directory || _entry!=null);
index 3dbb70a9ffdd427743a556a7020b3fcaa6e7de77..47eb108631a17f4a6222b059700cc1bd3a6d1352 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -92,7 +92,7 @@ public class JarResource extends URLResource
     
     /* ------------------------------------------------------------ */
     /**
-     * Returns true if the respresenetd resource exists.
+     * Returns true if the represented resource exists.
      */
     @Override
     public boolean exists()
@@ -118,7 +118,7 @@ public class JarResource extends URLResource
     {     
         checkConnection();
         if (!_urlString.endsWith("!/"))
-            return new FilterInputStream(super.getInputStream()) 
+            return new FilterInputStream(getInputStream(false)) 
             {
                 @Override
                 public void close() throws IOException {this.in=IO.getClosedStream();}
@@ -129,6 +129,9 @@ public class JarResource extends URLResource
         return is;
     }
     
+    
+    
     /* ------------------------------------------------------------ */
     @Override
     public void copyTo(File directory)
diff --git a/lib/jetty/org/eclipse/jetty/util/resource/PathResource.java b/lib/jetty/org/eclipse/jetty/util/resource/PathResource.java
new file mode 100644 (file)
index 0000000..8e77367
--- /dev/null
@@ -0,0 +1,366 @@
+//
+//  ========================================================================
+//  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.resource;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.channels.FileChannel;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.file.DirectoryIteratorException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.InvalidPathException;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.StandardOpenOption;
+import java.nio.file.attribute.FileTime;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jetty.util.StringUtil;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+/**
+ * Java NIO Path equivalent of FileResource.
+ */
+public class PathResource extends Resource
+{
+    private static final Logger LOG = Log.getLogger(PathResource.class);
+
+    private final Path path;
+    private final URI uri;
+    private LinkOption linkOptions[] = new LinkOption[] { LinkOption.NOFOLLOW_LINKS };
+
+    public PathResource(File file)
+    {
+        this(file.toPath());
+    }
+
+    public PathResource(Path path)
+    {
+        this.path = path;
+        assertValidPath(path);
+        this.uri = this.path.toUri();
+    }
+
+    public PathResource(URI uri) throws IOException
+    {
+        if (!uri.isAbsolute())
+        {
+            throw new IllegalArgumentException("not an absolute uri");
+        }
+
+        if (!uri.getScheme().equalsIgnoreCase("file"))
+        {
+            throw new IllegalArgumentException("not file: scheme");
+        }
+
+        Path path;
+        try
+        {
+            path = new File(uri).toPath();
+        }
+        catch (InvalidPathException e)
+        {
+            throw e;
+        }
+        catch (IllegalArgumentException e)
+        {
+            throw e;
+        }
+        catch (Exception e)
+        {
+            LOG.ignore(e);
+            throw new IOException("Unable to build Path from: " + uri,e);
+        }
+
+        this.path = path;
+        this.uri = path.toUri();
+    }
+
+    public PathResource(URL url) throws IOException, URISyntaxException
+    {
+        this(url.toURI());
+    }
+
+    @Override
+    public Resource addPath(String apath) throws IOException, MalformedURLException
+    {
+        return new PathResource(this.path.getFileSystem().getPath(path.toString(), apath));
+    }
+
+    private void assertValidPath(Path path)
+    {
+        String str = path.toString();
+        int idx = StringUtil.indexOfControlChars(str);
+        if(idx >= 0)
+        {
+            throw new InvalidPathException(str, "Invalid Character at index " + idx);
+        }
+    }
+
+    @Override
+    public void close()
+    {
+        // not applicable for FileSytem / Path
+    }
+
+    @Override
+    public boolean delete() throws SecurityException
+    {
+        try
+        {
+            return Files.deleteIfExists(path);
+        }
+        catch (IOException e)
+        {
+            LOG.ignore(e);
+            return false;
+        }
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+        if (obj == null)
+        {
+            return false;
+        }
+        if (getClass() != obj.getClass())
+        {
+            return false;
+        }
+        PathResource other = (PathResource)obj;
+        if (path == null)
+        {
+            if (other.path != null)
+            {
+                return false;
+            }
+        }
+        else if (!path.equals(other.path))
+        {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public boolean exists()
+    {
+        return Files.exists(path,linkOptions);
+    }
+
+    @Override
+    public File getFile() throws IOException
+    {
+        return path.toFile();
+    }
+
+    public boolean getFollowLinks()
+    {
+        return (linkOptions != null) && (linkOptions.length > 0) && (linkOptions[0] == LinkOption.NOFOLLOW_LINKS);
+    }
+
+    @Override
+    public InputStream getInputStream() throws IOException
+    {
+        return Files.newInputStream(path,StandardOpenOption.READ);
+    }
+
+    @Override
+    public String getName()
+    {
+        return path.toAbsolutePath().toString();
+    }
+
+    @Override
+    public ReadableByteChannel getReadableByteChannel() throws IOException
+    {
+        return FileChannel.open(path,StandardOpenOption.READ);
+    }
+
+    @Override
+    public URI getURI()
+    {
+        return this.uri;
+    }
+
+    @Override
+    public URL getURL()
+    {
+        try
+        {
+            return path.toUri().toURL();
+        }
+        catch (MalformedURLException e)
+        {
+            return null;
+        }
+    }
+
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        result = (prime * result) + ((path == null)?0:path.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean isContainedIn(Resource r) throws MalformedURLException
+    {
+        // not applicable for FileSystem / path
+        return false;
+    }
+
+    @Override
+    public boolean isDirectory()
+    {
+        return Files.isDirectory(path,linkOptions);
+    }
+
+    @Override
+    public long lastModified()
+    {
+        try
+        {
+            FileTime ft = Files.getLastModifiedTime(path,linkOptions);
+            return ft.toMillis();
+        }
+        catch (IOException e)
+        {
+            LOG.ignore(e);
+            return 0;
+        }
+    }
+
+    @Override
+    public long length()
+    {
+        try
+        {
+            return Files.size(path);
+        }
+        catch (IOException e)
+        {
+            // in case of error, use File.length logic of 0L
+            return 0L;
+        }
+    }
+
+    @Override
+    public URI getAlias()
+    {
+        if (Files.isSymbolicLink(path))
+        {
+            try
+            {
+                return path.toRealPath().toUri();
+            }
+            catch (IOException e)
+            {
+                LOG.debug(e);
+                return null;
+            }
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+    @Override
+    public String[] list()
+    {
+        try (DirectoryStream<Path> dir = Files.newDirectoryStream(path))
+        {
+            List<String> entries = new ArrayList<>();
+            for (Path entry : dir)
+            {
+                String name = entry.getFileName().toString();
+
+                if (Files.isDirectory(entry))
+                {
+                    name += "/";
+                }
+
+                entries.add(name);
+            }
+            int size = entries.size();
+            return entries.toArray(new String[size]);
+        }
+        catch (DirectoryIteratorException e)
+        {
+            LOG.debug(e);
+        }
+        catch (IOException e)
+        {
+            LOG.debug(e);
+        }
+        return null;
+    }
+
+    @Override
+    public boolean renameTo(Resource dest) throws SecurityException
+    {
+        if (dest instanceof PathResource)
+        {
+            PathResource destRes = (PathResource)dest;
+            try
+            {
+                Path result = Files.move(path,destRes.path,StandardCopyOption.ATOMIC_MOVE);
+                return Files.exists(result,linkOptions);
+            }
+            catch (IOException e)
+            {
+                LOG.ignore(e);
+                return false;
+            }
+        }
+        else
+        {
+            return false;
+        }
+    }
+
+    public void setFollowLinks(boolean followLinks)
+    {
+        if (followLinks)
+        {
+            linkOptions = new LinkOption[0];
+        }
+        else
+        {
+            linkOptions = new LinkOption[] { LinkOption.NOFOLLOW_LINKS };
+        }
+    }
+}
index b36a935582366c10b84c8430b4a973a2f5cdc55d..7c9c8ecd46cc8228027abdcdc288743ea16b0984 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -193,7 +193,7 @@ public abstract class Resource implements ResourceFactory, Closeable
             }
         }
 
-        return newResource(url);
+        return newResource(url, useCaches);
     }
 
     /* ------------------------------------------------------------ */
@@ -352,6 +352,7 @@ public abstract class Resource implements ResourceFactory, Closeable
     /**
      * Returns an URL representing the given resource
      */
+    // TODO: should deprecate this one and only use getURI()
     public abstract URL getURL();
 
     /* ------------------------------------------------------------ */
@@ -405,6 +406,7 @@ public abstract class Resource implements ResourceFactory, Closeable
     /**
      * Deletes the given resource
      */
+    // TODO: can throw IOException
     public abstract boolean delete()
         throws SecurityException;
     
@@ -412,6 +414,7 @@ public abstract class Resource implements ResourceFactory, Closeable
     /**
      * Rename the given resource
      */
+    // TODO: can throw IOException
     public abstract boolean renameTo( Resource dest)
         throws SecurityException;
     
@@ -420,6 +423,7 @@ public abstract class Resource implements ResourceFactory, Closeable
      * Returns a list of resource names contained in the given resource
      * The resource names are not URL encoded.
      */
+    // TODO: can throw IOException
     public abstract String[] list();
 
     /* ------------------------------------------------------------ */
@@ -545,7 +549,7 @@ public abstract class Resource implements ResourceFactory, Closeable
             buf.append("</TD></TR>");
         }
         buf.append("</TABLE>\n");
-       buf.append("</BODY></HTML>\n");
+        buf.append("</BODY></HTML>\n");
         
         return buf.toString();
     }
@@ -609,7 +613,7 @@ public abstract class Resource implements ResourceFactory, Closeable
     
     private static String deTag(String raw) 
     {
-        return StringUtil.replace( StringUtil.replace(raw,"<","&lt;"), ">", "&gt;");
+        return StringUtil.sanitizeXmlString(raw);
     }
     
     /* ------------------------------------------------------------ */
index 8135e0ba0c7f4142cb6a53afc36876dd600ef54e..178b156ee9ecfc59959e1a31d465dbad7aed8f8c 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 707a67245aca15ef603c8f32d9d9db0eec4b597a..5219ae2bf67cb2c9b8a0834093a3adc94b18576d 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index b696817e50b0d6a0012eca310c7cf96c99f5cb8f..5bba2c4726570a4bfbf5ed58b6a6dd60eaa2161b 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -197,13 +197,33 @@ public class URLResource extends Resource
         return _url.toExternalForm();
     }
 
+    
     /* ------------------------------------------------------------ */
     /**
-     * Returns an input stream to the resource
+     * Returns an input stream to the resource. The underlying 
+     * url connection will be nulled out to prevent re-use.
      */
     @Override
     public synchronized InputStream getInputStream()
         throws java.io.IOException
+    {
+        return getInputStream (true); //backwards compatibility
+    }
+    
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * Returns an input stream to the resource, optionally nulling
+     * out the underlying url connection. If the connection is not
+     * nulled out, a subsequent call to getInputStream() may return
+     * an existing and already in-use input stream - this depends on
+     * the url protocol. Eg JarURLConnection does not reuse inputstreams.
+     * 
+     * @param resetConnection if true the connection field is set to null
+     */
+    protected synchronized InputStream getInputStream(boolean resetConnection)
+        throws java.io.IOException
     {
         if (!checkConnection())
             throw new IOException( "Invalid resource");
@@ -220,7 +240,11 @@ public class URLResource extends Resource
         }
         finally
         {
-            _connection=null;
+            if (resetConnection)
+            {
+                _connection=null;
+                if (LOG.isDebugEnabled()) LOG.debug("Connection nulled");
+            }
         }
     }
 
@@ -277,7 +301,7 @@ public class URLResource extends Resource
 
         path = URIUtil.canonicalPath(path);
 
-        return newResource(URIUtil.addPaths(_url.toExternalForm(),path));
+        return newResource(URIUtil.addPaths(_url.toExternalForm(),URIUtil.encodePath(path)), _useCaches);
     }
 
     /* ------------------------------------------------------------ */
index f8d2428aabc76237a5de1f210627dd865168d246..03f46822064bac7524dd605543804c3c5f695f89 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 4ed9ae2157b50b06cbe8e18e73eaf205bb302c90..86a4f9e3154c1f8f9bb10c1dba1128f6144f5794 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 2ead38781624174e2c2c6f7340710bcc3cf683ba..0093b2040cf7ba90c70f91dbf0964bdf06a329bc 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 28c003b8538c4183822f104c2d3cf5e444cba893..daf343335ccde1b71145f25b1044c61805dc3ad1 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 1feb604790f464a2b062c2f17d32564f230c1248..660116f545c0cdb1896eb4d47233782b3082ee3e 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -160,17 +160,19 @@ public abstract class Credential implements Serializable
                         digest = __md.digest();
                     }
                     if (digest == null || digest.length != _digest.length) return false;
+                    boolean digestMismatch = false;
                     for (int i = 0; i < digest.length; i++)
-                        if (digest[i] != _digest[i]) return false;
-                    return true;
+                        digestMismatch |= (digest[i] != _digest[i]);
+                    return !digestMismatch;
                 }
                 else if (credentials instanceof MD5)
                 {
                     MD5 md5 = (MD5) credentials;
                     if (_digest.length != md5._digest.length) return false;
+                    boolean digestMismatch = false;
                     for (int i = 0; i < _digest.length; i++)
-                        if (_digest[i] != md5._digest[i]) return false;
-                    return true;
+                        digestMismatch |= (_digest[i] != md5._digest[i]);
+                    return !digestMismatch;
                 }
                 else if (credentials instanceof Credential)
                 {
index 13160c1d3dee6d75fd0f90924a0455338feea17f..0b5fe909aafdb51a7bdbc51059ef1799f118cf03 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -21,6 +21,7 @@ package org.eclipse.jetty.util.security;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
+import java.util.Locale;
 
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
@@ -28,15 +29,15 @@ import org.eclipse.jetty.util.log.Logger;
 /* ------------------------------------------------------------ */
 /**
  * Password utility class.
- * 
+ *
  * This utility class gets a password or pass phrase either by:
- * 
+ *
  * <PRE>
  *  + Password is set as a system property.
  *  + The password is prompted for and read from standard input
  *  + A program is run to get the password.
  * </pre>
- * 
+ *
  * Passwords that begin with OBF: are de obfuscated. Passwords can be obfuscated
  * by run org.eclipse.util.Password as a main class. Obfuscated password are
  * required if a system needs to recover the full password (eg. so that it may
@@ -50,8 +51,8 @@ import org.eclipse.jetty.util.log.Logger;
  * a secure(ish) way to store passwords that only need to be checked rather than
  * recovered. Note that it is not strong security - specially if simple
  * passwords are used.
- * 
- * 
+ *
+ *
  */
 public class Password extends Credential
 {
@@ -66,7 +67,7 @@ public class Password extends Credential
     /* ------------------------------------------------------------ */
     /**
      * Constructor.
-     * 
+     *
      * @param password The String password.
      */
     public Password(String password)
@@ -112,10 +113,10 @@ public class Password extends Credential
     @Override
     public boolean equals(Object o)
     {
-        if (this == o) 
+        if (this == o)
             return true;
 
-        if (null == o) 
+        if (null == o)
             return false;
 
         if (o instanceof Password)
@@ -125,7 +126,7 @@ public class Password extends Credential
             return p._pw == _pw || (null != _pw && _pw.equals(p._pw));
         }
 
-        if (o instanceof String) 
+        if (o instanceof String)
             return o.equals(_pw);
 
         return false;
@@ -151,8 +152,8 @@ public class Password extends Credential
             byte b2 = b[b.length - (i + 1)];
             if (b1<0 || b2<0)
             {
-                int i0 = (0xff&b1)*256 + (0xff&b2); 
-                String x = Integer.toString(i0, 36).toLowerCase();
+                int i0 = (0xff&b1)*256 + (0xff&b2);
+                String x = Integer.toString(i0, 36).toLowerCase(Locale.ENGLISH);
                 buf.append("U0000",0,5-x.length());
                 buf.append(x);
             }
@@ -161,13 +162,13 @@ public class Password extends Credential
                 int i1 = 127 + b1 + b2;
                 int i2 = 127 + b1 - b2;
                 int i0 = i1 * 256 + i2;
-                String x = Integer.toString(i0, 36).toLowerCase();
+                String x = Integer.toString(i0, 36).toLowerCase(Locale.ENGLISH);
 
                 int j0 = Integer.parseInt(x, 36);
                 int j1 = (i0 / 256);
                 int j2 = (i0 % 256);
                 byte bx = (byte) ((j1 + j2 - 254) / 2);
-                
+
                 buf.append("000",0,4-x.length());
                 buf.append(x);
             }
@@ -216,7 +217,7 @@ public class Password extends Credential
      * <LI>Prompting for a password
      * <LI>Using promptDft if nothing was entered.
      * </UL>
-     * 
+     *
      * @param realm The realm name for the password, used as a SystemProperty
      *                name.
      * @param dft The default password.
index a9271a5d0f9f7fe76b2a2ba337903241df499e62..a83a0e177f9147e49722eb22c16c04e64d156e93 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index b97aa3446dd447a6d97602b58e8f44ec4eb5bcc9..53c7ca0420ca6b998101c0ad27ea3982ec11b67f 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 29d33bb45235db4a3aa4f789a74c5a514d53fde5..8da8f6824626434c3ee7b3b8057c74c17e284242 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 016c81273eb41772b1edbf8a77ca9be11dd36d43..edf37897ec7db89ff69793d431297ea49a85df5f 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -116,12 +116,13 @@ public class SslContextFactory extends AbstractLifeCycle
     private final Set<String> _excludeProtocols = new LinkedHashSet<>();
 
     /** Included protocols. */
-    private Set<String> _includeProtocols = null;
+    private final Set<String> _includeProtocols = new LinkedHashSet<>();
 
     /** Excluded cipher suites. */
     private final Set<String> _excludeCipherSuites = new LinkedHashSet<>();
+    
     /** Included cipher suites. */
-    private Set<String> _includeCipherSuites = null;
+    private final Set<String> _includeCipherSuites = new LinkedHashSet<>();
 
     /** Keystore path. */
     private String _keyStorePath;
@@ -224,6 +225,7 @@ public class SslContextFactory extends AbstractLifeCycle
     public SslContextFactory(boolean trustAll)
     {
         setTrustAll(trustAll);
+        addExcludeProtocols("SSL", "SSLv2", "SSLv2Hello", "SSLv3");
     }
 
     /**
@@ -251,13 +253,14 @@ public class SslContextFactory extends AbstractLifeCycle
 
                 if (_trustAll)
                 {
-                    LOG.debug("No keystore or trust store configured.  ACCEPTING UNTRUSTED CERTIFICATES!!!!!");
+                    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);
-                SSLContext context = SSLContext.getInstance(_sslProtocol);
+                SSLContext context = _sslProvider == null ? SSLContext.getInstance(_sslProtocol) : SSLContext.getInstance(_sslProtocol, _sslProvider);
                 context.init(null, trust_managers, secureRandom);
                 _context = context;
             }
@@ -298,15 +301,17 @@ public class SslContextFactory extends AbstractLifeCycle
                 TrustManager[] trustManagers = getTrustManagers(trustStore,crls);
 
                 SecureRandom secureRandom = (_secureRandomAlgorithm == null)?null:SecureRandom.getInstance(_secureRandomAlgorithm);
-                SSLContext context = _sslProvider == null ? SSLContext.getInstance(_sslProtocol) : SSLContext.getInstance(_sslProtocol,_sslProvider);
+                SSLContext context = _sslProvider == null ? SSLContext.getInstance(_sslProtocol) : SSLContext.getInstance(_sslProtocol, _sslProvider);
                 context.init(keyManagers,trustManagers,secureRandom);
                 _context = context;
             }
 
             SSLEngine engine = newSSLEngine();
-            LOG.debug("Enabled Protocols {} of {}",Arrays.asList(engine.getEnabledProtocols()),Arrays.asList(engine.getSupportedProtocols()));
             if (LOG.isDebugEnabled())
+            {
+                LOG.debug("Enabled Protocols {} of {}",Arrays.asList(engine.getEnabledProtocols()),Arrays.asList(engine.getSupportedProtocols()));
                 LOG.debug("Enabled Ciphers   {} of {}",Arrays.asList(engine.getEnabledCipherSuites()),Arrays.asList(engine.getSupportedCipherSuites()));
+            }
         }
     }
 
@@ -364,7 +369,8 @@ public class SslContextFactory extends AbstractLifeCycle
     public void setIncludeProtocols(String... protocols)
     {
         checkNotStarted();
-        _includeProtocols = new LinkedHashSet<>(Arrays.asList(protocols));
+        _includeProtocols.clear();
+        _includeProtocols.addAll(Arrays.asList(protocols));
     }
 
     /**
@@ -416,7 +422,8 @@ public class SslContextFactory extends AbstractLifeCycle
     public void setIncludeCipherSuites(String... cipherSuites)
     {
         checkNotStarted();
-        _includeCipherSuites = new LinkedHashSet<>(Arrays.asList(cipherSuites));
+        _includeCipherSuites.clear();
+        _includeCipherSuites.addAll(Arrays.asList(cipherSuites));
     }
 
     /**
@@ -1034,7 +1041,7 @@ public class SslContextFactory extends AbstractLifeCycle
         Set<String> selected_protocols = new LinkedHashSet<>();
 
         // Set the starting protocols - either from the included or enabled list
-        if (_includeProtocols!=null)
+        if (!_includeProtocols.isEmpty())
         {
             // Use only the supported included protocols
             for (String protocol : _includeProtocols)
@@ -1064,17 +1071,17 @@ public class SslContextFactory extends AbstractLifeCycle
         Set<String> selected_ciphers = new CopyOnWriteArraySet<>();
 
         // Set the starting ciphers - either from the included or enabled list
-        if (_includeCipherSuites!=null)
-            processIncludeCipherSuites(supportedCipherSuites, selected_ciphers);
-        else
+        if (_includeCipherSuites.isEmpty())
             selected_ciphers.addAll(Arrays.asList(enabledCipherSuites));
+        else
+            processIncludeCipherSuites(supportedCipherSuites, selected_ciphers);
 
         removeExcludedCipherSuites(selected_ciphers);
 
         return selected_ciphers.toArray(new String[selected_ciphers.size()]);
     }
 
-    private void processIncludeCipherSuites(String[] supportedCipherSuites, Set<String> selected_ciphers)
+    protected void processIncludeCipherSuites(String[] supportedCipherSuites, Set<String> selected_ciphers)
     {
         for (String cipherSuite : _includeCipherSuites)
         {
@@ -1088,7 +1095,7 @@ public class SslContextFactory extends AbstractLifeCycle
         }
     }
 
-    private void removeExcludedCipherSuites(Set<String> selected_ciphers)
+    protected void removeExcludedCipherSuites(Set<String> selected_ciphers)
     {
         for (String excludeCipherSuite : _excludeCipherSuites)
         {
index 26ffa876b99dde6c266ce19708ff86d2f1733e64..9270550e35455558299bd3e2efe1a00e989aec6e 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 027dfe36a72ea1a58aa8c70ef488a3aad6616f0c..a57f0453e5d7fa45c69465da6234f7914cc9845c 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index eae7d470783a5575c52d31c8dd726eeab16350e2..718be6e757adcade691e81da2bf289d493161f1f 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index fac39e4e8e8cd103b810aa5d6cbc9d21ae0a74a8..7617b724e6ee04b003d87b3d463ba1c36bee7689 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 4f6b5fe62c1152a35d95019cd18791f2829c0959..899babefa97627a4d08bdc2f118167d3bfa8c3d5 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 4fb75c7fb0c3cd2da3e2290a6f2bbcca516ad219..db0545ff015595854ba58a86d2ff5c35d3422c86 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -53,7 +53,7 @@ public class NonBlockingThread implements Runnable
         }
         finally
         {
-            __nonBlockingThread.remove();
+            __nonBlockingThread.set(Boolean.FALSE);
         }
     }
 }
index 5cc75121c0b57a837aba35103c8aa23a73eb953f..bb986b6f68a1273a55f46971dbd7cdf1e4d2ccd0 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -24,14 +24,13 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.RejectedExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
 
 import org.eclipse.jetty.util.BlockingArrayQueue;
-import org.eclipse.jetty.util.StringUtil;
+import org.eclipse.jetty.util.ConcurrentHashSet;
 import org.eclipse.jetty.util.annotation.ManagedAttribute;
 import org.eclipse.jetty.util.annotation.ManagedObject;
 import org.eclipse.jetty.util.annotation.ManagedOperation;
@@ -52,7 +51,7 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
     private final AtomicInteger _threadsStarted = new AtomicInteger();
     private final AtomicInteger _threadsIdle = new AtomicInteger();
     private final AtomicLong _lastShrink = new AtomicLong();
-    private final ConcurrentLinkedQueue<Thread> _threads = new ConcurrentLinkedQueue<>();
+    private final ConcurrentHashSet<Thread> _threads=new ConcurrentHashSet<Thread>();
     private final Object _joinLock = new Object();
     private final BlockingQueue<Runnable> _jobs;
     private String _name = "qtp" + hashCode();
@@ -91,9 +90,11 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
         setStopTimeout(5000);
 
         if (queue==null)
-            queue=new BlockingArrayQueue<>(_minThreads, _minThreads);
+        {
+            int capacity=Math.max(_minThreads, 8);
+            queue=new BlockingArrayQueue<>(capacity, capacity);
+        }
         _jobs=queue;
-
     }
 
     @Override
@@ -166,7 +167,7 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
                     StringBuilder dmp = new StringBuilder();
                     for (StackTraceElement element : unstopped.getStackTrace())
                     {
-                        dmp.append(StringUtil.__LINE_SEPARATOR).append("\tat ").append(element);
+                        dmp.append(System.lineSeparator()).append("\tat ").append(element);
                     }
                     LOG.warn("Couldn't stop {}{}", unstopped, dmp.toString());
                 }
@@ -360,6 +361,12 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
             LOG.warn("{} rejected {}", this, job);
             throw new RejectedExecutionException(job.toString());
         }
+        else
+        {
+            // Make sure there is at least one thread executing the job.
+            if (getThreads() == 0)
+                startThreads(1);
+        }
     }
 
     /**
@@ -398,6 +405,15 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
         return _threadsIdle.get();
     }
 
+    /**
+     * @return The number of busy threads in the pool
+     */
+    @ManagedAttribute("total number of busy threads in the pool")
+    public int getBusyThreads()
+    {
+        return getThreads() - getIdleThreads();
+    }
+    
     /**
      * @return True if the pool is at maxThreads and there are not more idle threads than queued jobs
      */
@@ -410,7 +426,7 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
 
     private boolean startThreads(int threadsToStart)
     {
-        while (threadsToStart > 0)
+        while (threadsToStart > 0 && isRunning())
         {
             int threads = _threadsStarted.get();
             if (threads >= _maxThreads)
@@ -430,14 +446,13 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
 
                 thread.start();
                 started = true;
+                --threadsToStart;
             }
             finally
             {
                 if (!started)
                     _threadsStarted.decrementAndGet();
             }
-            if (started)
-                threadsToStart--;
         }
         return true;
     }
@@ -447,7 +462,6 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
         return new Thread(runnable);
     }
 
-
     @Override
     @ManagedOperation("dump thread state")
     public String dump()
@@ -480,7 +494,10 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
                     @Override
                     public void dump(Appendable out, String indent) throws IOException
                     {
-                        out.append(String.valueOf(thread.getId())).append(' ').append(thread.getName()).append(' ').append(thread.getState().toString()).append(idle ? " IDLE" : "").append('\n');
+                        out.append(String.valueOf(thread.getId())).append(' ').append(thread.getName()).append(' ').append(thread.getState().toString()).append(idle ? " IDLE" : "");
+                        if (thread.getPriority()!=Thread.NORM_PRIORITY)
+                            out.append(" prio=").append(String.valueOf(thread.getPriority()));
+                        out.append(System.lineSeparator());
                         if (!idle)
                             ContainerLifeCycle.dump(out, indent, Arrays.asList(trace));
                     }
@@ -494,7 +511,8 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
             }
             else
             {
-                dump.add(thread.getId() + " " + thread.getName() + " " + thread.getState() + " @ " + (trace.length > 0 ? trace[0] : "???") + (idle ? " IDLE" : ""));
+                int p=thread.getPriority();
+                dump.add(thread.getId() + " " + thread.getName() + " " + thread.getState() + " @ " + (trace.length > 0 ? trace[0] : "???") + (idle ? " IDLE" : "")+ (p==Thread.NORM_PRIORITY?"":(" prio="+p)));
             }
         }
 
@@ -519,6 +537,7 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
         public void run()
         {
             boolean shrink = false;
+            boolean ignore = false;
             try
             {
                 Runnable job = _jobs.poll();
@@ -535,7 +554,10 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
                     {
                         runJob(job);
                         if (Thread.interrupted())
+                        {
+                            ignore=true;
                             break loop;
+                        }
                         job = _jobs.poll();
                     }
 
@@ -558,11 +580,10 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
                                     long now = System.nanoTime();
                                     if (last == 0 || (now - last) > TimeUnit.MILLISECONDS.toNanos(_idleTimeout))
                                     {
-                                        shrink = _lastShrink.compareAndSet(last, now) &&
-                                                _threadsStarted.compareAndSet(size, size - 1);
-                                        if (shrink)
+                                        if (_lastShrink.compareAndSet(last, now) && _threadsStarted.compareAndSet(size, size - 1))
                                         {
-                                            return;
+                                            shrink=true;
+                                            break loop;
                                         }
                                     }
                                 }
@@ -581,6 +602,7 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
             }
             catch (InterruptedException e)
             {
+                ignore=true;
                 LOG.ignore(e);
             }
             catch (Throwable e)
@@ -589,8 +611,14 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
             }
             finally
             {
-                if (!shrink)
-                    _threadsStarted.decrementAndGet();
+                if (!shrink && isRunning())
+                {
+                    if (!ignore)
+                        LOG.warn("Unexpected thread death: {} in {}",this,QueuedThreadPool.this);
+                    // This is an unexpected thread death!
+                    if (_threadsStarted.decrementAndGet()<getMaxThreads())
+                        startThreads(1);
+                }
                 _threads.remove(Thread.currentThread());
             }
         }
@@ -653,14 +681,13 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
             if (thread.getId() == id)
             {
                 StringBuilder buf = new StringBuilder();
-                buf.append(thread.getId()).append(" ").append(thread.getName()).append(" ").append(thread.getState()).append(":\n");
+                buf.append(thread.getId()).append(" ").append(thread.getName()).append(" ");
+                buf.append(thread.getState()).append(":").append(System.lineSeparator());
                 for (StackTraceElement element : thread.getStackTrace())
-                    buf.append("  at ").append(element.toString()).append('\n');
+                    buf.append("  at ").append(element.toString()).append(System.lineSeparator());
                 return buf.toString();
             }
         }
         return null;
     }
-    
-
 }
index 5f8d62a65ac356deeead2d62d1d31a3df5695436..70cb518c60b194c03746072a174d15cc6857b68c 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
 
 package org.eclipse.jetty.util.thread;
 
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.ScheduledThreadPoolExecutor;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.TimeUnit;
 
 import org.eclipse.jetty.util.component.AbstractLifeCycle;
+import org.eclipse.jetty.util.component.ContainerLifeCycle;
+import org.eclipse.jetty.util.component.Dumpable;
 
 /**
  * Implementation of {@link Scheduler} based on JDK's {@link ScheduledThreadPoolExecutor}.
@@ -33,21 +38,29 @@ import org.eclipse.jetty.util.component.AbstractLifeCycle;
  * queue even if the task did not fire, which provides a huge benefit in the performance
  * of garbage collection in young generation.
  */
-public class ScheduledExecutorScheduler extends AbstractLifeCycle implements Scheduler
+public class ScheduledExecutorScheduler extends AbstractLifeCycle implements Scheduler, Dumpable
 {
     private final String name;
     private final boolean daemon;
+    private final ClassLoader classloader;
     private volatile ScheduledThreadPoolExecutor scheduler;
+    private volatile Thread thread;
 
     public ScheduledExecutorScheduler()
     {
         this(null, false);
-    }
+    }  
 
     public ScheduledExecutorScheduler(String name, boolean daemon)
+    {
+        this (name,daemon, Thread.currentThread().getContextClassLoader());
+    }
+    
+    public ScheduledExecutorScheduler(String name, boolean daemon, ClassLoader threadFactoryClassLoader)
     {
         this.name = name == null ? "Scheduler-" + hashCode() : name;
         this.daemon = daemon;
+        this.classloader = threadFactoryClassLoader;
     }
 
     @Override
@@ -58,8 +71,9 @@ public class ScheduledExecutorScheduler extends AbstractLifeCycle implements Sch
             @Override
             public Thread newThread(Runnable r)
             {
-                Thread thread = new Thread(r, name);
+                Thread thread = ScheduledExecutorScheduler.this.thread = new Thread(r, name);
                 thread.setDaemon(daemon);
+                thread.setContextClassLoader(classloader);
                 return thread;
             }
         });
@@ -78,10 +92,37 @@ public class ScheduledExecutorScheduler extends AbstractLifeCycle implements Sch
     @Override
     public Task schedule(Runnable task, long delay, TimeUnit unit)
     {
-        ScheduledFuture<?> result = scheduler.schedule(task, delay, unit);
+        ScheduledThreadPoolExecutor s = scheduler;
+        if (s==null)
+            return new Task(){
+                @Override
+                public boolean cancel()
+                {
+                    return false;
+                }};
+
+        ScheduledFuture<?> result = s.schedule(task, delay, unit);
         return new ScheduledFutureTask(result);
     }
 
+    @Override
+    public String dump()
+    {
+        return ContainerLifeCycle.dump(this);
+    }
+
+    @Override
+    public void dump(Appendable out, String indent) throws IOException
+    {
+        ContainerLifeCycle.dumpObject(out, this);
+        Thread thread = this.thread;
+        if (thread != null)
+        {
+            List<StackTraceElement> frames = Arrays.asList(thread.getStackTrace());
+            ContainerLifeCycle.dump(out, indent, frames);
+        }
+    }
+
     private class ScheduledFutureTask implements Task
     {
         private final ScheduledFuture<?> scheduledFuture;
index f519184666c31c183b98b8acc276def4ae833189..c863914cfd151f1c7809bfa897666199a545d77f 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 168b444ca002c5c29c0e9ca637ef473873cc04f7..db6ccf8e93258240d51249107f331390cc003768 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -119,6 +119,12 @@ public class ShutdownThread extends Thread
             _thread.unhook();
     }
 
+    /* ------------------------------------------------------------ */
+    public static synchronized boolean isRegistered(LifeCycle lifeCycle)
+    {
+        return _thread._lifeCycles.contains(lifeCycle);
+    }
+
     /* ------------------------------------------------------------ */
     @Override
     public void run()
@@ -132,7 +138,7 @@ public class ShutdownThread extends Thread
                     lifeCycle.stop();
                     LOG.debug("Stopped {}",lifeCycle);
                 }
-                
+
                 if (lifeCycle instanceof Destroyable)
                 {
                     ((Destroyable)lifeCycle).destroy();
diff --git a/lib/jetty/org/eclipse/jetty/util/thread/SpinLock.java b/lib/jetty/org/eclipse/jetty/util/thread/SpinLock.java
new file mode 100644 (file)
index 0000000..fa199cc
--- /dev/null
@@ -0,0 +1,82 @@
+//
+//  ========================================================================
+//  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.thread;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * <p>This spin lock is a lock designed to protect VERY short sections
+ * of critical code.  Threads attempting to take the lock will spin
+ * forever until the lock is available, thus it is important that
+ * the code protected by this lock is extremely simple and non
+ * blocking. The reason for this lock is that it prevents a thread
+ * from giving up a CPU core when contending for the lock.</p>
+ * <pre>
+ * try(SpinLock.Lock lock = spinlock.lock())
+ * {
+ *   // something very quick and non blocking
+ * }
+ * </pre>
+ * <p>Further analysis however, shows that spin locks behave really
+ * bad under heavy contention and where the number of threads
+ * exceeds the number of cores, which are common scenarios for a
+ * server, so this class was removed from usage, preferring
+ * standard locks instead.</p>
+ * @deprecated Do not use it anymore, prefer normal locks
+ */
+@Deprecated
+public class SpinLock
+{
+    private final AtomicReference<Thread> _lock = new AtomicReference<>(null);
+    private final Lock _unlock = new Lock();
+
+    public Lock lock()
+    {
+        Thread thread = Thread.currentThread();
+        while(true)
+        {
+            if (!_lock.compareAndSet(null,thread))
+            {
+                if (_lock.get()==thread)
+                    throw new IllegalStateException("SpinLock is not reentrant");
+                continue;
+            }
+            return _unlock;
+        }
+    }
+
+    public boolean isLocked()
+    {
+        return _lock.get()!=null;
+    }
+
+    public boolean isLockedThread()
+    {
+        return _lock.get()==Thread.currentThread();
+    }
+
+    public class Lock implements AutoCloseable
+    {
+        @Override
+        public void close()
+        {
+            _lock.set(null);
+        }
+    }
+}
diff --git a/lib/jetty/org/eclipse/jetty/util/thread/Sweeper.java b/lib/jetty/org/eclipse/jetty/util/thread/Sweeper.java
new file mode 100644 (file)
index 0000000..0ea8800
--- /dev/null
@@ -0,0 +1,194 @@
+//
+//  ========================================================================
+//  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.thread;
+
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.eclipse.jetty.util.component.AbstractLifeCycle;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+/**
+ * <p>A utility class to perform periodic sweeping of resources.</p>
+ * <p>{@link Sweepable} resources may be added to or removed from a
+ * {@link Sweeper} and the resource implementation decides whether
+ * it should be swept or not.</p>
+ * <p>If a {@link Sweepable} resources is itself a container of
+ * other sweepable resources, it will forward the sweep operation
+ * to children resources, and so on recursively.</p>
+ * <p>Typical usage is to add {@link Sweeper} as a bean to an existing
+ * container:</p>
+ * <pre>
+ * Server server = new Server();
+ * server.addBean(new Sweeper(), true);
+ * server.start();
+ * </pre>
+ * Code that knows it has sweepable resources can then lookup the
+ * {@link Sweeper} and offer the sweepable resources to it:
+ * <pre>
+ * class MyComponent implements Sweeper.Sweepable
+ * {
+ *     private final long creation;
+ *     private volatile destroyed;
+ *
+ *     MyComponent(Server server)
+ *     {
+ *         this.creation = System.nanoTime();
+ *         Sweeper sweeper = server.getBean(Sweeper.class);
+ *         sweeper.offer(this);
+ *     }
+ *
+ *     void destroy()
+ *     {
+ *         destroyed = true;
+ *     }
+ *
+ *     &#64;Override
+ *     public boolean sweep()
+ *     {
+ *         return destroyed;
+ *     }
+ * }
+ * </pre>
+ */
+public class Sweeper extends AbstractLifeCycle implements Runnable
+{
+    private static final Logger LOG = Log.getLogger(Sweeper.class);
+
+    private final AtomicReference<List<Sweepable>> items = new AtomicReference<>();
+    private final AtomicReference<Scheduler.Task> task = new AtomicReference<>();
+    private final Scheduler scheduler;
+    private final long period;
+
+    public Sweeper(Scheduler scheduler, long period)
+    {
+        this.scheduler = scheduler;
+        this.period = period;
+    }
+
+    @Override
+    protected void doStart() throws Exception
+    {
+        super.doStart();
+        items.set(new CopyOnWriteArrayList<Sweepable>());
+        activate();
+    }
+
+    @Override
+    protected void doStop() throws Exception
+    {
+        deactivate();
+        items.set(null);
+        super.doStop();
+    }
+
+    public int getSize()
+    {
+        List<Sweepable> refs = items.get();
+        return refs == null ? 0 : refs.size();
+    }
+
+    public boolean offer(Sweepable sweepable)
+    {
+        List<Sweepable> refs = items.get();
+        if (refs == null)
+            return false;
+        refs.add(sweepable);
+        if (LOG.isDebugEnabled())
+            LOG.debug("Resource offered {}", sweepable);
+        return true;
+    }
+
+    public boolean remove(Sweepable sweepable)
+    {
+        List<Sweepable> refs = items.get();
+        return refs != null && refs.remove(sweepable);
+    }
+
+    @Override
+    public void run()
+    {
+        List<Sweepable> refs = items.get();
+        if (refs == null)
+            return;
+        for (Sweepable sweepable : refs)
+        {
+            try
+            {
+                if (sweepable.sweep())
+                {
+                    refs.remove(sweepable);
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Resource swept {}", sweepable);
+                }
+            }
+            catch (Throwable x)
+            {
+                LOG.info("Exception while sweeping " + sweepable, x);
+            }
+        }
+        activate();
+    }
+
+    private void activate()
+    {
+        if (isRunning())
+        {
+            Scheduler.Task t = scheduler.schedule(this, period, TimeUnit.MILLISECONDS);
+            if (LOG.isDebugEnabled())
+                LOG.debug("Scheduled in {} ms sweep task {}", period, t);
+            task.set(t);
+        }
+        else
+        {
+            if (LOG.isDebugEnabled())
+                LOG.debug("Skipping sweep task scheduling");
+        }
+    }
+
+    private void deactivate()
+    {
+        Scheduler.Task t = task.getAndSet(null);
+        if (t != null)
+        {
+            boolean cancelled = t.cancel();
+            if (LOG.isDebugEnabled())
+                LOG.debug("Cancelled ({}) sweep task {}", cancelled, t);
+        }
+    }
+
+    /**
+     * <p>A {@link Sweepable} resource implements this interface to
+     * signal to a {@link Sweeper} or to a parent container if it
+     * needs to be swept or not.</p>
+     * <p>Typical implementations will check their own internal state
+     * and return true or false from {@link #sweep()} to indicate
+     * whether they should be swept.</p>
+     */
+    public interface Sweepable
+    {
+        /**
+         * @return whether this resource should be swept
+         */
+        public boolean sweep();
+    }
+}
index c2abcfc80e5ab07ddd5100f1be848faf5e74cad7..84b8390db62a0e418e4d4a81c004cf93381e54a8 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
@@ -22,7 +22,6 @@ import java.util.concurrent.Executor;
 
 import org.eclipse.jetty.util.annotation.ManagedAttribute;
 import org.eclipse.jetty.util.annotation.ManagedObject;
-import org.eclipse.jetty.util.component.LifeCycle;
 
 /* ------------------------------------------------------------ */
 /** ThreadPool.
index c07390a76ee14d50240a29bb15faf2f30719f30a..c46394af5c67ed0798909e8a7b0b0213a912fa5f 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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
index 2637e49ee1df7efaa40fef89b0abc08447861a22..ec02bd6494091f4bbd83fb0d72a90244a42b67db 100644 (file)
@@ -1,6 +1,6 @@
 //
 //  ========================================================================
-//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  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