From ba4f228fa9f72d50991a2218cfd83987ef5d385e Mon Sep 17 00:00:00 2001 From: =?utf8?q?Felix=20D=C3=B6rre?= Date: Thu, 30 Jun 2016 12:58:08 +0200 Subject: [PATCH] updating jetty to jetty-9.2.16.v2016040 Change-Id: I5b14fada113d25f8e08be400b47a335dbe70e02f --- .../org/eclipse/jetty/http/DateGenerator.java | 2 +- .../org/eclipse/jetty/http/DateParser.java | 2 +- .../org/eclipse/jetty/http/HttpContent.java | 8 +- .../org/eclipse/jetty/http/HttpCookie.java | 2 +- .../org/eclipse/jetty/http/HttpField.java | 2 +- .../org/eclipse/jetty/http/HttpFields.java | 16 +- .../org/eclipse/jetty/http/HttpGenerator.java | 49 +- .../org/eclipse/jetty/http/HttpHeader.java | 2 +- .../eclipse/jetty/http/HttpHeaderValue.java | 2 +- .../org/eclipse/jetty/http/HttpMethod.java | 41 +- .../org/eclipse/jetty/http/HttpParser.java | 224 +++++--- .../org/eclipse/jetty/http/HttpScheme.java | 2 +- .../org/eclipse/jetty/http/HttpStatus.java | 3 +- .../org/eclipse/jetty/http/HttpTester.java | 2 +- .../org/eclipse/jetty/http/HttpTokens.java | 2 +- lib/jetty/org/eclipse/jetty/http/HttpURI.java | 4 +- .../org/eclipse/jetty/http/HttpVersion.java | 7 +- .../org/eclipse/jetty/http/MimeTypes.java | 2 +- lib/jetty/org/eclipse/jetty/http/PathMap.java | 56 +- .../org/eclipse/jetty/http/mime.properties | 2 + .../org/eclipse/jetty/http/package-info.java | 2 +- .../jetty/http/pathmap/MappedResource.java | 101 ++++ .../jetty/http/pathmap/PathMappings.java | 159 +++++ .../eclipse/jetty/http/pathmap/PathSpec.java | 167 ++++++ .../jetty/http/pathmap/PathSpecGroup.java | 101 ++++ .../jetty/http/pathmap/PathSpecSet.java | 223 ++++++++ .../jetty/http/pathmap/RegexPathSpec.java | 176 ++++++ .../jetty/http/pathmap/ServletPathSpec.java | 261 +++++++++ .../http/pathmap/UriTemplatePathSpec.java | 341 +++++++++++ .../eclipse/jetty/io/AbstractConnection.java | 86 +-- .../eclipse/jetty/io/AbstractEndPoint.java | 51 +- .../eclipse/jetty/io/ArrayByteBufferPool.java | 2 +- .../eclipse/jetty/io/ByteArrayEndPoint.java | 2 +- .../org/eclipse/jetty/io/ByteBufferPool.java | 2 +- .../org/eclipse/jetty/io/ChannelEndPoint.java | 11 +- .../jetty/io/ClientConnectionFactory.java | 5 +- .../org/eclipse/jetty/io/Connection.java | 37 +- lib/jetty/org/eclipse/jetty/io/EndPoint.java | 15 +- .../org/eclipse/jetty/io/EofException.java | 2 +- .../org/eclipse/jetty/io/FillInterest.java | 4 +- .../org/eclipse/jetty/io/IdleTimeout.java | 13 +- .../jetty/io/LeakTrackingByteBufferPool.java | 64 ++- .../jetty/io/MappedByteBufferPool.java | 27 +- .../jetty/io/NegotiatingClientConnection.java | 4 +- .../NegotiatingClientConnectionFactory.java | 2 +- .../jetty/io/NetworkTrafficListener.java | 2 +- .../NetworkTrafficSelectChannelEndPoint.java | 3 +- .../eclipse/jetty/io/RuntimeIOException.java | 2 +- .../jetty/io/SelectChannelEndPoint.java | 14 +- .../org/eclipse/jetty/io/SelectorManager.java | 171 ++++-- .../jetty/io/UncheckedPrintWriter.java | 5 +- .../org/eclipse/jetty/io/WriteFlusher.java | 136 ++--- .../eclipse/jetty/io/WriterOutputStream.java | 2 +- .../org/eclipse/jetty/io/package-info.java | 2 +- .../io/ssl/SslClientConnectionFactory.java | 2 +- .../eclipse/jetty/io/ssl/SslConnection.java | 86 ++- .../eclipse/jetty/io/ssl/package-info.java | 2 +- .../security/AbstractUserAuthentication.java | 2 +- .../eclipse/jetty/security/Authenticator.java | 2 +- .../jetty/security/ConstraintAware.java | 2 +- .../jetty/security/ConstraintMapping.java | 2 +- .../security/ConstraintSecurityHandler.java | 27 +- .../security/CrossContextPsuedoSession.java | 3 +- .../security/DefaultAuthenticatorFactory.java | 2 +- .../security/DefaultIdentityService.java | 2 +- .../jetty/security/DefaultUserIdentity.java | 2 +- .../HashCrossContextPsuedoSession.java | 3 +- .../jetty/security/HashLoginService.java | 9 +- .../jetty/security/IdentityService.java | 3 +- .../jetty/security/JDBCLoginService.java | 5 +- .../eclipse/jetty/security/LoginService.java | 2 +- .../jetty/security/MappedLoginService.java | 2 +- .../jetty/security/PropertyUserStore.java | 5 +- .../org/eclipse/jetty/security/RoleInfo.java | 2 +- .../jetty/security/RoleRunAsToken.java | 2 +- .../eclipse/jetty/security/RunAsToken.java | 2 +- .../jetty/security/SecurityHandler.java | 3 +- .../jetty/security/ServerAuthException.java | 2 +- .../jetty/security/SpnegoLoginService.java | 2 +- .../jetty/security/SpnegoUserIdentity.java | 2 +- .../jetty/security/SpnegoUserPrincipal.java | 2 +- .../jetty/security/UserAuthentication.java | 2 +- .../jetty/security/UserDataConstraint.java | 2 +- .../authentication/BasicAuthenticator.java | 2 +- .../ClientCertAuthenticator.java | 2 +- .../DeferredAuthentication.java | 38 +- .../authentication/DigestAuthenticator.java | 3 +- .../authentication/FormAuthenticator.java | 2 +- .../authentication/LoginAuthenticator.java | 2 +- .../authentication/LoginCallback.java | 2 +- .../authentication/LoginCallbackImpl.java | 2 +- .../authentication/SessionAuthentication.java | 2 +- .../authentication/SpnegoAuthenticator.java | 10 +- .../security/authentication/package-info.java | 2 +- .../eclipse/jetty/security/package-info.java | 2 +- .../server/AbstractConnectionFactory.java | 2 +- .../jetty/server/AbstractConnector.java | 79 ++- .../jetty/server/AbstractNCSARequestLog.java | 5 +- .../server/AbstractNetworkConnector.java | 2 +- .../jetty/server/AsyncContextEvent.java | 2 +- .../jetty/server/AsyncContextState.java | 2 +- .../jetty/server/AsyncNCSARequestLog.java | 2 +- .../eclipse/jetty/server/Authentication.java | 2 +- .../server/ByteBufferQueuedHttpInput.java | 2 +- .../eclipse/jetty/server/ClassLoaderDump.java | 2 +- .../jetty/server/ConnectionFactory.java | 2 +- .../org/eclipse/jetty/server/Connector.java | 3 +- .../jetty/server/ConnectorStatistics.java | 2 +- .../eclipse/jetty/server/CookieCutter.java | 2 +- .../org/eclipse/jetty/server/Dispatcher.java | 2 +- .../jetty/server/EncodingHttpWriter.java | 2 +- .../server/ForwardedRequestCustomizer.java | 4 +- .../org/eclipse/jetty/server/Handler.java | 4 +- .../jetty/server/HandlerContainer.java | 2 +- .../eclipse/jetty/server/HomeBaseWarning.java | 75 +++ .../jetty/server/HostHeaderCustomizer.java | 4 +- .../org/eclipse/jetty/server/HttpChannel.java | 160 ++++-- .../jetty/server/HttpChannelState.java | 34 +- .../jetty/server/HttpConfiguration.java | 125 +++- .../eclipse/jetty/server/HttpConnection.java | 363 ++++++------ .../jetty/server/HttpConnectionFactory.java | 2 +- .../org/eclipse/jetty/server/HttpInput.java | 76 ++- .../jetty/server/HttpInputOverHTTP.java | 5 +- .../org/eclipse/jetty/server/HttpOutput.java | 112 ++-- .../eclipse/jetty/server/HttpTransport.java | 4 +- .../org/eclipse/jetty/server/HttpWriter.java | 2 +- .../jetty/server/InclusiveByteRange.java | 6 +- .../jetty/server/Iso88591HttpWriter.java | 2 +- .../eclipse/jetty/server/LocalConnector.java | 19 +- .../jetty/server/LowResourceMonitor.java | 2 +- .../eclipse/jetty/server/NCSARequestLog.java | 2 +- .../server/NegotiatingServerConnection.java | 21 +- .../NegotiatingServerConnectionFactory.java | 2 +- .../jetty/server/NetworkConnector.java | 2 +- .../server/NetworkTrafficServerConnector.java | 2 +- .../eclipse/jetty/server/QueuedHttpInput.java | 11 +- .../jetty/server/QuietServletException.java | 2 +- .../org/eclipse/jetty/server/Request.java | 76 +-- .../org/eclipse/jetty/server/RequestLog.java | 2 +- .../eclipse/jetty/server/ResourceCache.java | 11 +- .../org/eclipse/jetty/server/Response.java | 101 ++-- .../jetty/server/SecureRequestCustomizer.java | 27 +- .../org/eclipse/jetty/server/Server.java | 81 ++- .../eclipse/jetty/server/ServerConnector.java | 61 +- .../server/ServletRequestHttpWrapper.java | 36 +- .../server/ServletResponseHttpWrapper.java | 2 +- .../jetty/server/SessionIdManager.java | 2 +- .../eclipse/jetty/server/SessionManager.java | 3 +- .../eclipse/jetty/server/ShutdownMonitor.java | 234 ++++++-- .../jetty/server/SslConnectionFactory.java | 2 +- .../eclipse/jetty/server/UserIdentity.java | 2 +- .../eclipse/jetty/server/Utf8HttpWriter.java | 2 +- .../jetty/server/handler/AbstractHandler.java | 8 +- .../handler/AbstractHandlerContainer.java | 4 +- .../handler/AllowSymLinkAliasChecker.java | 8 +- .../server/handler/AsyncDelayHandler.java | 153 +++++ .../jetty/server/handler/ContextHandler.java | 121 ++-- .../handler/ContextHandlerCollection.java | 276 +++++---- .../jetty/server/handler/DebugHandler.java | 2 +- .../jetty/server/handler/DefaultHandler.java | 103 ++-- .../jetty/server/handler/ErrorHandler.java | 27 +- .../server/handler/HandlerCollection.java | 11 +- .../jetty/server/handler/HandlerList.java | 2 +- .../jetty/server/handler/HandlerWrapper.java | 3 +- .../jetty/server/handler/HotSwapHandler.java | 2 +- .../jetty/server/handler/IPAccessHandler.java | 2 +- .../server/handler/IdleTimeoutHandler.java | 26 +- .../server/handler/MovedContextHandler.java | 2 +- .../server/handler/RequestLogHandler.java | 11 +- .../jetty/server/handler/ResourceHandler.java | 73 ++- .../jetty/server/handler/ScopedHandler.java | 2 +- .../handler/SecuredRedirectHandler.java | 76 +++ .../jetty/server/handler/ShutdownHandler.java | 34 +- .../server/handler/StatisticsHandler.java | 48 +- .../jetty/server/handler/package-info.java | 2 +- .../NetworkTrafficSelectChannelConnector.java | 2 +- .../jetty/server/nio/package-info.java | 2 +- .../eclipse/jetty/server/package-info.java | 2 +- .../jetty/server/session/AbstractSession.java | 9 +- .../session/AbstractSessionIdManager.java | 5 +- .../session/AbstractSessionManager.java | 11 +- .../server/session/HashSessionIdManager.java | 4 +- .../server/session/HashSessionManager.java | 59 +- .../jetty/server/session/HashedSession.java | 21 +- .../server/session/JDBCSessionIdManager.java | 21 +- .../server/session/JDBCSessionManager.java | 21 +- .../jetty/server/session/MemSession.java | 2 +- .../jetty/server/session/SessionHandler.java | 15 +- .../jetty/server/session/package-info.java | 2 +- .../org/eclipse/jetty/servlet/BaseHolder.java | 2 +- .../eclipse/jetty/servlet/DefaultServlet.java | 129 +++-- .../jetty/servlet/ErrorPageErrorHandler.java | 2 +- .../eclipse/jetty/servlet/FilterHolder.java | 5 +- .../eclipse/jetty/servlet/FilterMapping.java | 33 +- .../org/eclipse/jetty/servlet/Holder.java | 6 +- .../org/eclipse/jetty/servlet/Invoker.java | 18 +- .../servlet/JspPropertyGroupServlet.java | 35 +- .../eclipse/jetty/servlet/ListenerHolder.java | 2 +- .../eclipse/jetty/servlet/NoJspServlet.java | 2 +- .../jetty/servlet/ServletContextHandler.java | 10 +- .../eclipse/jetty/servlet/ServletHandler.java | 163 +++--- .../eclipse/jetty/servlet/ServletHolder.java | 198 +++++-- .../eclipse/jetty/servlet/ServletMapping.java | 2 +- .../eclipse/jetty/servlet/ServletTester.java | 44 +- .../jetty/servlet/StatisticsServlet.java | 2 +- .../servlet/listener/ELContextCleaner.java | 37 +- .../servlet/listener/IntrospectorCleaner.java | 2 +- .../jetty/servlet/listener/package-info.java | 2 +- .../eclipse/jetty/servlet/package-info.java | 2 +- .../org/eclipse/jetty/util/AbstractTrie.java | 2 +- .../org/eclipse/jetty/util/ArrayQueue.java | 2 +- .../eclipse/jetty/util/ArrayTernaryTrie.java | 58 +- .../org/eclipse/jetty/util/ArrayTrie.java | 60 +- .../org/eclipse/jetty/util/ArrayUtil.java | 2 +- lib/jetty/org/eclipse/jetty/util/Atomics.java | 22 +- .../org/eclipse/jetty/util/Attributes.java | 2 +- .../org/eclipse/jetty/util/AttributesMap.java | 2 +- lib/jetty/org/eclipse/jetty/util/B64Code.java | 3 +- .../jetty/util/BlockingArrayQueue.java | 2 +- .../eclipse/jetty/util/BlockingCallback.java | 2 +- .../org/eclipse/jetty/util/BufferUtil.java | 112 ++-- .../jetty/util/ByteArrayISO8859Writer.java | 2 +- .../jetty/util/ByteArrayOutputStream2.java | 2 +- .../org/eclipse/jetty/util/Callback.java | 20 +- .../util/ClassLoadingObjectInputStream.java | 6 +- .../jetty/util/CompletableCallback.java | 96 +++- .../jetty/util/ConcurrentArrayQueue.java | 21 +- .../eclipse/jetty/util/ConcurrentHashSet.java | 2 +- .../eclipse/jetty/util/CountingCallback.java | 98 ++++ .../org/eclipse/jetty/util/DateCache.java | 2 +- lib/jetty/org/eclipse/jetty/util/Fields.java | 2 +- .../org/eclipse/jetty/util/ForkInvoker.java | 135 ----- .../eclipse/jetty/util/FutureCallback.java | 4 +- .../org/eclipse/jetty/util/FuturePromise.java | 4 +- lib/jetty/org/eclipse/jetty/util/HostMap.java | 2 +- .../eclipse/jetty/util/HttpCookieStore.java | 2 +- lib/jetty/org/eclipse/jetty/util/IO.java | 55 +- .../org/eclipse/jetty/util/IPAddressMap.java | 2 +- .../eclipse/jetty/util/IncludeExclude.java | 166 ++++++ .../eclipse/jetty/util/IntrospectionUtil.java | 2 +- .../eclipse/jetty/util/IteratingCallback.java | 541 ++++++++++++------ .../jetty/util/IteratingNestedCallback.java | 9 +- lib/jetty/org/eclipse/jetty/util/Jetty.java | 2 +- .../org/eclipse/jetty/util/LazyList.java | 2 +- .../org/eclipse/jetty/util/LeakDetector.java | 83 +-- lib/jetty/org/eclipse/jetty/util/Loader.java | 2 +- .../org/eclipse/jetty/util/MemoryUtils.java | 2 +- .../eclipse/jetty/util/MultiException.java | 56 +- .../org/eclipse/jetty/util/MultiMap.java | 2 +- .../util/MultiPartInputStreamParser.java | 40 +- .../jetty/util/MultiPartOutputStream.java | 2 +- .../eclipse/jetty/util/MultiPartWriter.java | 2 +- .../eclipse/jetty/util/PatternMatcher.java | 2 +- .../org/eclipse/jetty/util/Predicate.java | 31 + lib/jetty/org/eclipse/jetty/util/Promise.java | 2 +- .../jetty/util/QuotedStringTokenizer.java | 2 +- .../jetty/util/ReadLineInputStream.java | 2 +- .../org/eclipse/jetty/util/RegexSet.java | 109 ++++ .../jetty/util/RolloverFileOutputStream.java | 2 +- lib/jetty/org/eclipse/jetty/util/Scanner.java | 12 +- .../jetty/util/SharedBlockingCallback.java | 120 ++-- .../jetty/util/SocketAddressResolver.java | 241 ++++---- .../org/eclipse/jetty/util/StringUtil.java | 306 +++++++++- .../org/eclipse/jetty/util/TreeTrie.java | 15 +- lib/jetty/org/eclipse/jetty/util/Trie.java | 2 +- .../org/eclipse/jetty/util/TypeUtil.java | 16 +- lib/jetty/org/eclipse/jetty/util/URIUtil.java | 120 +++- lib/jetty/org/eclipse/jetty/util/Uptime.java | 132 +++++ .../org/eclipse/jetty/util/UrlEncoded.java | 144 ++--- .../eclipse/jetty/util/Utf8Appendable.java | 2 +- .../eclipse/jetty/util/Utf8LineParser.java | 4 +- .../eclipse/jetty/util/Utf8StringBuffer.java | 2 +- .../eclipse/jetty/util/Utf8StringBuilder.java | 2 +- .../util/annotation/ManagedAttribute.java | 2 +- .../jetty/util/annotation/ManagedObject.java | 2 +- .../util/annotation/ManagedOperation.java | 2 +- .../eclipse/jetty/util/annotation/Name.java | 2 +- .../jetty/util/annotation/package-info.java | 2 +- .../util/component/AbstractLifeCycle.java | 16 +- .../jetty/util/component/Container.java | 2 +- .../util/component/ContainerLifeCycle.java | 8 +- .../jetty/util/component/Destroyable.java | 2 +- .../jetty/util/component/Dumpable.java | 2 +- .../jetty/util/component/FileDestroyable.java | 5 +- .../FileNoticeLifeCycleListener.java | 2 +- .../jetty/util/component/Graceful.java | 2 +- .../jetty/util/component/LifeCycle.java | 2 +- .../jetty/util/component/package-info.java | 2 +- .../jetty/util/log/AbstractLogger.java | 6 +- .../eclipse/jetty/util/log/JavaUtilLog.java | 2 +- lib/jetty/org/eclipse/jetty/util/log/Log.java | 8 +- .../org/eclipse/jetty/util/log/Logger.java | 2 +- .../org/eclipse/jetty/util/log/LoggerLog.java | 2 +- .../jetty/util/log/StacklessLogging.java | 2 +- .../org/eclipse/jetty/util/log/StdErrLog.java | 29 +- .../eclipse/jetty/util/log/package-info.java | 2 +- .../org/eclipse/jetty/util/package-info.java | 2 +- .../util/preventers/AWTLeakPreventer.java | 5 +- .../preventers/AbstractLeakPreventer.java | 2 +- .../preventers/AppContextLeakPreventer.java | 5 +- .../util/preventers/DOMLeakPreventer.java | 2 +- .../DriverManagerLeakPreventer.java | 5 +- .../preventers/GCThreadLeakPreventer.java | 4 +- .../util/preventers/Java2DLeakPreventer.java | 2 +- .../util/preventers/LDAPLeakPreventer.java | 2 +- .../LoginConfigurationLeakPreventer.java | 2 +- .../SecurityProviderLeakPreventer.java | 2 +- .../jetty/util/preventers/package-info.java | 2 +- .../jetty/util/resource/BadResource.java | 2 +- .../jetty/util/resource/EmptyResource.java | 2 +- .../jetty/util/resource/FileResource.java | 46 +- .../jetty/util/resource/JarFileResource.java | 30 +- .../jetty/util/resource/JarResource.java | 9 +- .../jetty/util/resource/PathResource.java | 366 ++++++++++++ .../eclipse/jetty/util/resource/Resource.java | 12 +- .../util/resource/ResourceCollection.java | 2 +- .../jetty/util/resource/ResourceFactory.java | 2 +- .../jetty/util/resource/URLResource.java | 32 +- .../jetty/util/resource/package-info.java | 2 +- .../jetty/util/security/CertificateUtils.java | 2 +- .../util/security/CertificateValidator.java | 2 +- .../jetty/util/security/Constraint.java | 2 +- .../jetty/util/security/Credential.java | 12 +- .../eclipse/jetty/util/security/Password.java | 31 +- .../jetty/util/security/package-info.java | 2 +- .../ssl/AliasedX509ExtendedKeyManager.java | 2 +- .../jetty/util/ssl/AliasedX509KeyManager.java | 2 +- .../jetty/util/ssl/SslContextFactory.java | 37 +- .../eclipse/jetty/util/ssl/package-info.java | 2 +- .../util/statistic/CounterStatistic.java | 2 +- .../jetty/util/statistic/SampleStatistic.java | 2 +- .../jetty/util/statistic/package-info.java | 2 +- .../jetty/util/thread/ExecutorThreadPool.java | 2 +- .../jetty/util/thread/NonBlockingThread.java | 4 +- .../jetty/util/thread/QueuedThreadPool.java | 73 ++- .../thread/ScheduledExecutorScheduler.java | 51 +- .../eclipse/jetty/util/thread/Scheduler.java | 2 +- .../jetty/util/thread/ShutdownThread.java | 10 +- .../eclipse/jetty/util/thread/SpinLock.java | 82 +++ .../eclipse/jetty/util/thread/Sweeper.java | 194 +++++++ .../eclipse/jetty/util/thread/ThreadPool.java | 3 +- .../jetty/util/thread/TimerScheduler.java | 2 +- .../jetty/util/thread/package-info.java | 2 +- 343 files changed, 7835 insertions(+), 2783 deletions(-) create mode 100644 lib/jetty/org/eclipse/jetty/http/pathmap/MappedResource.java create mode 100644 lib/jetty/org/eclipse/jetty/http/pathmap/PathMappings.java create mode 100644 lib/jetty/org/eclipse/jetty/http/pathmap/PathSpec.java create mode 100644 lib/jetty/org/eclipse/jetty/http/pathmap/PathSpecGroup.java create mode 100644 lib/jetty/org/eclipse/jetty/http/pathmap/PathSpecSet.java create mode 100644 lib/jetty/org/eclipse/jetty/http/pathmap/RegexPathSpec.java create mode 100644 lib/jetty/org/eclipse/jetty/http/pathmap/ServletPathSpec.java create mode 100644 lib/jetty/org/eclipse/jetty/http/pathmap/UriTemplatePathSpec.java create mode 100644 lib/jetty/org/eclipse/jetty/server/HomeBaseWarning.java create mode 100644 lib/jetty/org/eclipse/jetty/server/handler/AsyncDelayHandler.java create mode 100644 lib/jetty/org/eclipse/jetty/server/handler/SecuredRedirectHandler.java create mode 100644 lib/jetty/org/eclipse/jetty/util/CountingCallback.java delete mode 100644 lib/jetty/org/eclipse/jetty/util/ForkInvoker.java create mode 100644 lib/jetty/org/eclipse/jetty/util/IncludeExclude.java create mode 100644 lib/jetty/org/eclipse/jetty/util/Predicate.java create mode 100644 lib/jetty/org/eclipse/jetty/util/RegexSet.java create mode 100644 lib/jetty/org/eclipse/jetty/util/Uptime.java create mode 100644 lib/jetty/org/eclipse/jetty/util/resource/PathResource.java create mode 100644 lib/jetty/org/eclipse/jetty/util/thread/SpinLock.java create mode 100644 lib/jetty/org/eclipse/jetty/util/thread/Sweeper.java diff --git a/lib/jetty/org/eclipse/jetty/http/DateGenerator.java b/lib/jetty/org/eclipse/jetty/http/DateGenerator.java index 3ecaad8c..e38d3c69 100644 --- a/lib/jetty/org/eclipse/jetty/http/DateGenerator.java +++ b/lib/jetty/org/eclipse/jetty/http/DateGenerator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/DateParser.java b/lib/jetty/org/eclipse/jetty/http/DateParser.java index 1ede4cec..f181ce1d 100644 --- a/lib/jetty/org/eclipse/jetty/http/DateParser.java +++ b/lib/jetty/org/eclipse/jetty/http/DateParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/HttpContent.java b/lib/jetty/org/eclipse/jetty/http/HttpContent.java index ebae56d1..ba098805 100644 --- a/lib/jetty/org/eclipse/jetty/http/HttpContent.java +++ b/lib/jetty/org/eclipse/jetty/http/HttpContent.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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); + } } } diff --git a/lib/jetty/org/eclipse/jetty/http/HttpCookie.java b/lib/jetty/org/eclipse/jetty/http/HttpCookie.java index 1a2426b1..2d769df6 100644 --- a/lib/jetty/org/eclipse/jetty/http/HttpCookie.java +++ b/lib/jetty/org/eclipse/jetty/http/HttpCookie.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/HttpField.java b/lib/jetty/org/eclipse/jetty/http/HttpField.java index 50f29b1e..55ab65ca 100644 --- a/lib/jetty/org/eclipse/jetty/http/HttpField.java +++ b/lib/jetty/org/eclipse/jetty/http/HttpField.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/HttpFields.java b/lib/jetty/org/eclipse/jetty/http/HttpFields.java index d4742274..6bec4d97 100644 --- a/lib/jetty/org/eclipse/jetty/http/HttpFields.java +++ b/lib/jetty/org/eclipse/jetty/http/HttpFields.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 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 } return false; } - + + public String getStringField(HttpHeader header) { return getStringField(header.asString()); diff --git a/lib/jetty/org/eclipse/jetty/http/HttpGenerator.java b/lib/jetty/org/eclipse/jetty/http/HttpGenerator.java index a51e4ba7..6f7ead3e 100644 --- a/lib/jetty/org/eclipse/jetty/http/HttpGenerator.java +++ b/lib/jetty/org/eclipse/jetty/http/HttpGenerator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 __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)); } diff --git a/lib/jetty/org/eclipse/jetty/http/HttpHeader.java b/lib/jetty/org/eclipse/jetty/http/HttpHeader.java index ab0ddcf3..a62f5f27 100644 --- a/lib/jetty/org/eclipse/jetty/http/HttpHeader.java +++ b/lib/jetty/org/eclipse/jetty/http/HttpHeader.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/HttpHeaderValue.java b/lib/jetty/org/eclipse/jetty/http/HttpHeaderValue.java index 8338a322..71301003 100644 --- a/lib/jetty/org/eclipse/jetty/http/HttpHeaderValue.java +++ b/lib/jetty/org/eclipse/jetty/http/HttpHeaderValue.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/HttpMethod.java b/lib/jetty/org/eclipse/jetty/http/HttpMethod.java index 8a262680..1d2eeda0 100644 --- a/lib/jetty/org/eclipse/jetty/http/HttpMethod.java +++ b/lib/jetty/org/eclipse/jetty/http/HttpMethod.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 diff --git a/lib/jetty/org/eclipse/jetty/http/HttpParser.java b/lib/jetty/org/eclipse/jetty/http/HttpParser.java index 79f1c28d..e1ddee83 100644 --- a/lib/jetty/org/eclipse/jetty/http/HttpParser.java +++ b/lib/jetty/org/eclipse/jetty/http/HttpParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 *

- * The is 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=0 && ch0 && _state.ordinal() 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 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 extends HttpHandler { /** @@ -1657,6 +1697,9 @@ public class HttpParser public abstract boolean parsedHostHeader(String host,int port); } + /* ------------------------------------------------------------------------------- */ + /* ------------------------------------------------------------------------------- */ + /* ------------------------------------------------------------------------------- */ public interface ResponseHandler extends HttpHandler { /** @@ -1665,24 +1708,15 @@ public class HttpParser public abstract boolean startResponse(HttpVersion version, int status, String reason); } - public Trie 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(); } } diff --git a/lib/jetty/org/eclipse/jetty/http/HttpScheme.java b/lib/jetty/org/eclipse/jetty/http/HttpScheme.java index 13f2a8d3..f44bcdd6 100644 --- a/lib/jetty/org/eclipse/jetty/http/HttpScheme.java +++ b/lib/jetty/org/eclipse/jetty/http/HttpScheme.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/HttpStatus.java b/lib/jetty/org/eclipse/jetty/http/HttpStatus.java index e6ea1f71..8762644c 100644 --- a/lib/jetty/org/eclipse/jetty/http/HttpStatus.java +++ b/lib/jetty/org/eclipse/jetty/http/HttpStatus.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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; diff --git a/lib/jetty/org/eclipse/jetty/http/HttpTester.java b/lib/jetty/org/eclipse/jetty/http/HttpTester.java index 537c457c..0283f9e3 100644 --- a/lib/jetty/org/eclipse/jetty/http/HttpTester.java +++ b/lib/jetty/org/eclipse/jetty/http/HttpTester.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/HttpTokens.java b/lib/jetty/org/eclipse/jetty/http/HttpTokens.java index 4138334d..067a21ef 100644 --- a/lib/jetty/org/eclipse/jetty/http/HttpTokens.java +++ b/lib/jetty/org/eclipse/jetty/http/HttpTokens.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/HttpURI.java b/lib/jetty/org/eclipse/jetty/http/HttpURI.java index afe925e1..46a8a5bc 100644 --- a/lib/jetty/org/eclipse/jetty/http/HttpURI.java +++ b/lib/jetty/org/eclipse/jetty/http/HttpURI.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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); } diff --git a/lib/jetty/org/eclipse/jetty/http/HttpVersion.java b/lib/jetty/org/eclipse/jetty/http/HttpVersion.java index eb889e56..ddedc274 100644 --- a/lib/jetty/org/eclipse/jetty/http/HttpVersion.java +++ b/lib/jetty/org/eclipse/jetty/http/HttpVersion.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 CACHE= new ArrayTrie(); @@ -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(); } } diff --git a/lib/jetty/org/eclipse/jetty/http/MimeTypes.java b/lib/jetty/org/eclipse/jetty/http/MimeTypes.java index 9cac4abd..145f2200 100644 --- a/lib/jetty/org/eclipse/jetty/http/MimeTypes.java +++ b/lib/jetty/org/eclipse/jetty/http/MimeTypes.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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.java b/lib/jetty/org/eclipse/jetty/http/PathMap.java index b78f5728..d2196874 100644 --- a/lib/jetty/org/eclipse/jetty/http/PathMap.java +++ b/lib/jetty/org/eclipse/jetty/http/PathMap.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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,14 +18,18 @@ 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 extends HashMap this.mapped = mapped; } } + + public static class PathSet extends AbstractSet implements Predicate + { + private final PathMap _map = new PathMap<>(); + + @Override + public Iterator 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); + } + } } diff --git a/lib/jetty/org/eclipse/jetty/http/mime.properties b/lib/jetty/org/eclipse/jetty/http/mime.properties index b2709897..302cbd0a 100644 --- a/lib/jetty/org/eclipse/jetty/http/mime.properties +++ b/lib/jetty/org/eclipse/jetty/http/mime.properties @@ -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 diff --git a/lib/jetty/org/eclipse/jetty/http/package-info.java b/lib/jetty/org/eclipse/jetty/http/package-info.java index 825422a3..aeca4a3f 100644 --- a/lib/jetty/org/eclipse/jetty/http/package-info.java +++ b/lib/jetty/org/eclipse/jetty/http/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 index 00000000..155dce8b --- /dev/null +++ b/lib/jetty/org/eclipse/jetty/http/pathmap/MappedResource.java @@ -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 implements Comparable> +{ + 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 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 index 00000000..d1c36cfb --- /dev/null +++ b/lib/jetty/org/eclipse/jetty/http/pathmap/PathMappings.java @@ -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. + *

+ * Sorted into search order upon entry into the Set + * + * @param the type of mapping endpoint + */ +@ManagedObject("Path Mappings") +public class PathMappings implements Iterable>, Dumpable +{ + private static final Logger LOG = Log.getLogger(PathMappings.class); + private List> mappings = new ArrayList>(); + private MappedResource defaultResource = null; + private MappedResource 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> 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> getMatches(String path) + { + boolean matchRoot = "/".equals(path); + + List> ret = new ArrayList<>(); + int len = mappings.size(); + for (int i = 0; i < len; i++) + { + MappedResource 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 getMatch(String path) + { + if (path.equals("/") && rootResource != null) + { + return rootResource; + } + + int len = mappings.size(); + for (int i = 0; i < len; i++) + { + MappedResource mr = mappings.get(i); + if (mr.getPathSpec().matches(path)) + { + return mr; + } + } + return defaultResource; + } + + @Override + public Iterator> iterator() + { + return mappings.iterator(); + } + + @SuppressWarnings("incomplete-switch") + public void put(PathSpec pathSpec, E resource) + { + MappedResource 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 index 00000000..a2b8ea56 --- /dev/null +++ b/lib/jetty/org/eclipse/jetty/http/pathmap/PathSpec.java @@ -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 +{ + 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. + *

+ * 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 index 00000000..f9d96ced --- /dev/null +++ b/lib/jetty/org/eclipse/jetty/http/pathmap/PathSpecGroup.java @@ -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. + *

+ * This is used to facilitate proper pathspec search order. + *

+ * Search Order: + *

    + *
  1. {@link PathSpecGroup#ordinal()} [increasing]
  2. + *
  3. {@link PathSpec#specLength} [decreasing]
  4. + *
  5. {@link PathSpec#pathSpec} [natural sort order]
  6. + *
+ */ +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. + * + *
+     *   "^/downloads/[^/]*.zip$"  - regex spec
+     *   "/a/{var}/c"              - uri-template spec
+     * 
+ * + * 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. + *

+ * + *

+     *   "/downloads/*"          - servlet spec
+     *   "/api/*"                - servlet spec
+     *   "^/rest/.*$"            - regex spec
+     *   "/bookings/{guest-id}"  - uri-template spec
+     *   "/rewards/{vip-level}"  - uri-template spec
+     * 
+ */ + PREFIX_GLOB, + /** + * For path specs that have a wildcard glob with a hardcoded suffix + * + *
+     *   "*.do"        - servlet spec
+     *   "*.css"       - servlet spec
+     *   "^.*\.zip$"   - regex spec
+     * 
+ * + * 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. + * + *
+     *   ""           - servlet spec       (Root Servlet)
+     *   null         - servlet spec       (Root Servlet)
+     * 
+ * + * 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. + * + *
+     *   "/"           - servlet spec      (Default Servlet)
+     *   "/"           - uri-template spec (Root Context)
+     *   "^/$"         - regex spec        (Root Context)
+     * 
+ * + * 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 index 00000000..1ffb783e --- /dev/null +++ b/lib/jetty/org/eclipse/jetty/http/pathmap/PathSpecSet.java @@ -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. + *

+ * Used by {@link org.eclipse.jetty.util.IncludeExclude} logic + */ +public class PathSpecSet implements Set, Predicate +{ + private final Set 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 iterator() + { + return new Iterator() + { + private Iterator 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[] 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 coll) + { + boolean ret = false; + + for (String s : coll) + { + ret |= add(s); + } + + return ret; + } + + @Override + public boolean retainAll(Collection coll) + { + List collSpecs = new ArrayList<>(); + for (Object o : coll) + { + collSpecs.add(asPathSpec(o)); + } + return specs.retainAll(collSpecs); + } + + @Override + public boolean removeAll(Collection coll) + { + List 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 index 00000000..0d83f3b0 --- /dev/null +++ b/lib/jetty/org/eclipse/jetty/http/pathmap/RegexPathSpec.java @@ -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 index 00000000..45633056 --- /dev/null +++ b/lib/jetty/org/eclipse/jetty/http/pathmap/ServletPathSpec.java @@ -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 index 00000000..208820b6 --- /dev/null +++ b/lib/jetty/org/eclipse/jetty/http/pathmap/UriTemplatePathSpec.java @@ -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 URI Templates (Level 1) + */ +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 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 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 getPathParams(String path) + { + Matcher matcher = getMatcher(path); + if (matcher.matches()) + { + if (group == PathSpecGroup.EXACT) + { + return Collections.emptyMap(); + } + Map 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; + } +} diff --git a/lib/jetty/org/eclipse/jetty/io/AbstractConnection.java b/lib/jetty/org/eclipse/jetty/io/AbstractConnection.java index 7f8e9f81..28c7082f 100644 --- a/lib/jetty/org/eclipse/jetty/io/AbstractConnection.java +++ b/lib/jetty/org/eclipse/jetty/io/AbstractConnection.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 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); } } - + /** *

Utility method to be called to register read interest.

*

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; } } - + /** *

Callback method invoked when the endpoint is ready to be read.

* @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() { diff --git a/lib/jetty/org/eclipse/jetty/io/AbstractEndPoint.java b/lib/jetty/org/eclipse/jetty/io/AbstractEndPoint.java index 8fa2cc86..44a38ecb 100644 --- a/lib/jetty/org/eclipse/jetty/io/AbstractEndPoint.java +++ b/lib/jetty/org/eclipse/jetty/io/AbstractEndPoint.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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()); } diff --git a/lib/jetty/org/eclipse/jetty/io/ArrayByteBufferPool.java b/lib/jetty/org/eclipse/jetty/io/ArrayByteBufferPool.java index fa3a01d0..86b49722 100644 --- a/lib/jetty/org/eclipse/jetty/io/ArrayByteBufferPool.java +++ b/lib/jetty/org/eclipse/jetty/io/ArrayByteBufferPool.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/io/ByteArrayEndPoint.java b/lib/jetty/org/eclipse/jetty/io/ByteArrayEndPoint.java index 4b8c527c..73cea8c8 100644 --- a/lib/jetty/org/eclipse/jetty/io/ByteArrayEndPoint.java +++ b/lib/jetty/org/eclipse/jetty/io/ByteArrayEndPoint.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/io/ByteBufferPool.java b/lib/jetty/org/eclipse/jetty/io/ByteBufferPool.java index 302adde3..4b5bada4 100644 --- a/lib/jetty/org/eclipse/jetty/io/ByteBufferPool.java +++ b/lib/jetty/org/eclipse/jetty/io/ByteBufferPool.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/io/ChannelEndPoint.java b/lib/jetty/org/eclipse/jetty/io/ChannelEndPoint.java index c65ca0cc..5ce60e7b 100644 --- a/lib/jetty/org/eclipse/jetty/io/ChannelEndPoint.java +++ b/lib/jetty/org/eclipse/jetty/io/ChannelEndPoint.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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(); diff --git a/lib/jetty/org/eclipse/jetty/io/ClientConnectionFactory.java b/lib/jetty/org/eclipse/jetty/io/ClientConnectionFactory.java index 7eb59318..a11fe8e4 100644 --- a/lib/jetty/org/eclipse/jetty/io/ClientConnectionFactory.java +++ b/lib/jetty/org/eclipse/jetty/io/ClientConnectionFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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. *

* 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 */ diff --git a/lib/jetty/org/eclipse/jetty/io/Connection.java b/lib/jetty/org/eclipse/jetty/io/Connection.java index 96baa016..5c7d564d 100644 --- a/lib/jetty/org/eclipse/jetty/io/Connection.java +++ b/lib/jetty/org/eclipse/jetty/io/Connection.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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,13 +19,12 @@ package org.eclipse.jetty.io; import java.io.Closeable; - -import org.eclipse.jetty.util.Callback; +import java.nio.ByteBuffer; /** *

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}.

- *

A typical implementation of {@link Connection} overrides {@link #onOpen()} to + *

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.

@@ -34,10 +33,6 @@ public interface Connection extends Closeable { public void addListener(Listener listener); - /** - *

Callback method invoked when this {@link Connection} is opened.

- *

Creators of the connection implementation are responsible for calling this method.

- */ public void onOpen(); /** @@ -50,7 +45,7 @@ public interface Connection extends Closeable * @return the {@link EndPoint} associated with this {@link Connection} */ public EndPoint getEndPoint(); - + /** *

Performs a logical close of this connection.

*

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. + *

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 + { + /** + *

Callback method invoked when this {@link Connection} is upgraded.

+ *

This must be called before {@link #onOpen()}.

+ * @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 { diff --git a/lib/jetty/org/eclipse/jetty/io/EndPoint.java b/lib/jetty/org/eclipse/jetty/io/EndPoint.java index 87adb40b..c96dcb8b 100644 --- a/lib/jetty/org/eclipse/jetty/io/EndPoint.java +++ b/lib/jetty/org/eclipse/jetty/io/EndPoint.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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); } diff --git a/lib/jetty/org/eclipse/jetty/io/EofException.java b/lib/jetty/org/eclipse/jetty/io/EofException.java index 72042f40..29aa5e0c 100644 --- a/lib/jetty/org/eclipse/jetty/io/EofException.java +++ b/lib/jetty/org/eclipse/jetty/io/EofException.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/io/FillInterest.java b/lib/jetty/org/eclipse/jetty/io/FillInterest.java index b2c3f685..a2343975 100644 --- a/lib/jetty/org/eclipse/jetty/io/FillInterest.java +++ b/lib/jetty/org/eclipse/jetty/io/FillInterest.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 diff --git a/lib/jetty/org/eclipse/jetty/io/IdleTimeout.java b/lib/jetty/org/eclipse/jetty/io/IdleTimeout.java index 8b251ac8..d8a6c274 100644 --- a/lib/jetty/org/eclipse/jetty/io/IdleTimeout.java +++ b/lib/jetty/org/eclipse/jetty/io/IdleTimeout.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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")); diff --git a/lib/jetty/org/eclipse/jetty/io/LeakTrackingByteBufferPool.java b/lib/jetty/org/eclipse/jetty/io/LeakTrackingByteBufferPool.java index a6fc7562..f9ac66e7 100644 --- a/lib/jetty/org/eclipse/jetty/io/LeakTrackingByteBufferPool.java +++ b/lib/jetty/org/eclipse/jetty/io/LeakTrackingByteBufferPool.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 leakDetector = new LeakDetector() { + 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.LeakInfo leakInfo) { LOG.warn("ByteBuffer " + leakInfo.getResourceDescription() + " leaked at:", leakInfo.getStackFrames()); diff --git a/lib/jetty/org/eclipse/jetty/io/MappedByteBufferPool.java b/lib/jetty/org/eclipse/jetty/io/MappedByteBufferPool.java index b331904c..bc9e8147 100644 --- a/lib/jetty/org/eclipse/jetty/io/MappedByteBufferPool.java +++ b/lib/jetty/org/eclipse/jetty/io/MappedByteBufferPool.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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; + } + } } diff --git a/lib/jetty/org/eclipse/jetty/io/NegotiatingClientConnection.java b/lib/jetty/org/eclipse/jetty/io/NegotiatingClientConnection.java index cd05630f..f0a8b1f3 100644 --- a/lib/jetty/org/eclipse/jetty/io/NegotiatingClientConnection.java +++ b/lib/jetty/org/eclipse/jetty/io/NegotiatingClientConnection.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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,10 @@ 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; diff --git a/lib/jetty/org/eclipse/jetty/io/NegotiatingClientConnectionFactory.java b/lib/jetty/org/eclipse/jetty/io/NegotiatingClientConnectionFactory.java index ff386007..5f20837c 100644 --- a/lib/jetty/org/eclipse/jetty/io/NegotiatingClientConnectionFactory.java +++ b/lib/jetty/org/eclipse/jetty/io/NegotiatingClientConnectionFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/io/NetworkTrafficListener.java b/lib/jetty/org/eclipse/jetty/io/NetworkTrafficListener.java index 6a4239f0..3a04207c 100644 --- a/lib/jetty/org/eclipse/jetty/io/NetworkTrafficListener.java +++ b/lib/jetty/org/eclipse/jetty/io/NetworkTrafficListener.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/io/NetworkTrafficSelectChannelEndPoint.java b/lib/jetty/org/eclipse/jetty/io/NetworkTrafficSelectChannelEndPoint.java index a4b6f7d2..bf7606ba 100644 --- a/lib/jetty/org/eclipse/jetty/io/NetworkTrafficSelectChannelEndPoint.java +++ b/lib/jetty/org/eclipse/jetty/io/NetworkTrafficSelectChannelEndPoint.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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; diff --git a/lib/jetty/org/eclipse/jetty/io/RuntimeIOException.java b/lib/jetty/org/eclipse/jetty/io/RuntimeIOException.java index 88c33f73..5f0e95b6 100644 --- a/lib/jetty/org/eclipse/jetty/io/RuntimeIOException.java +++ b/lib/jetty/org/eclipse/jetty/io/RuntimeIOException.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/io/SelectChannelEndPoint.java b/lib/jetty/org/eclipse/jetty/io/SelectChannelEndPoint.java index 30504029..6eec73d4 100644 --- a/lib/jetty/org/eclipse/jetty/io/SelectChannelEndPoint.java +++ b/lib/jetty/org/eclipse/jetty/io/SelectChannelEndPoint.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 diff --git a/lib/jetty/org/eclipse/jetty/io/SelectorManager.java b/lib/jetty/org/eclipse/jetty/io/SelectorManager.java index fd3c6c6b..26a18c3d 100644 --- a/lib/jetty/org/eclipse/jetty/io/SelectorManager.java +++ b/lib/jetty/org/eclipse/jetty/io/SelectorManager.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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. + *

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.

+ * + * @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 /** *

Registers a channel to perform a non-blocking connect.

- *

The channel must be set in non-blocking mode, and {@link SocketChannel#connect(SocketAddress)} - * must be called prior to calling this method.

+ *

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).

* * @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); + } + /** *

Registers a channel to perform non-blocking read/write operations.

*

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)}.

+ * 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.

* * @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)); } - + /** *

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(); } } - + /** *

Submits a change to be executed in the selector thread.

*

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")); } } } diff --git a/lib/jetty/org/eclipse/jetty/io/UncheckedPrintWriter.java b/lib/jetty/org/eclipse/jetty/io/UncheckedPrintWriter.java index 6898ddfb..928605e1 100644 --- a/lib/jetty/org/eclipse/jetty/io/UncheckedPrintWriter.java +++ b/lib/jetty/org/eclipse/jetty/io/UncheckedPrintWriter.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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); } diff --git a/lib/jetty/org/eclipse/jetty/io/WriteFlusher.java b/lib/jetty/org/eclipse/jetty/io/WriteFlusher.java index fccc6229..ed594c12 100644 --- a/lib/jetty/org/eclipse/jetty/io/WriteFlusher.java +++ b/lib/jetty/org/eclipse/jetty/io/WriteFlusher.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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> __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 diff --git a/lib/jetty/org/eclipse/jetty/io/WriterOutputStream.java b/lib/jetty/org/eclipse/jetty/io/WriterOutputStream.java index d08b4736..0ee72147 100644 --- a/lib/jetty/org/eclipse/jetty/io/WriterOutputStream.java +++ b/lib/jetty/org/eclipse/jetty/io/WriterOutputStream.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/io/package-info.java b/lib/jetty/org/eclipse/jetty/io/package-info.java index 6316823e..9db10927 100644 --- a/lib/jetty/org/eclipse/jetty/io/package-info.java +++ b/lib/jetty/org/eclipse/jetty/io/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/io/ssl/SslClientConnectionFactory.java b/lib/jetty/org/eclipse/jetty/io/ssl/SslClientConnectionFactory.java index ce3be14a..c1ec55fa 100644 --- a/lib/jetty/org/eclipse/jetty/io/ssl/SslClientConnectionFactory.java +++ b/lib/jetty/org/eclipse/jetty/io/ssl/SslClientConnectionFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/io/ssl/SslConnection.java b/lib/jetty/org/eclipse/jetty/io/ssl/SslConnection.java index ee9e449b..c68cc06c 100644 --- a/lib/jetty/org/eclipse/jetty/io/ssl/SslConnection.java +++ b/lib/jetty/org/eclipse/jetty/io/ssl/SslConnection.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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) diff --git a/lib/jetty/org/eclipse/jetty/io/ssl/package-info.java b/lib/jetty/org/eclipse/jetty/io/ssl/package-info.java index f8676c3c..2a23b1f0 100644 --- a/lib/jetty/org/eclipse/jetty/io/ssl/package-info.java +++ b/lib/jetty/org/eclipse/jetty/io/ssl/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/security/AbstractUserAuthentication.java b/lib/jetty/org/eclipse/jetty/security/AbstractUserAuthentication.java index bc049fd5..d3865832 100644 --- a/lib/jetty/org/eclipse/jetty/security/AbstractUserAuthentication.java +++ b/lib/jetty/org/eclipse/jetty/security/AbstractUserAuthentication.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/security/Authenticator.java b/lib/jetty/org/eclipse/jetty/security/Authenticator.java index e36a3b30..83a965d6 100644 --- a/lib/jetty/org/eclipse/jetty/security/Authenticator.java +++ b/lib/jetty/org/eclipse/jetty/security/Authenticator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/security/ConstraintAware.java b/lib/jetty/org/eclipse/jetty/security/ConstraintAware.java index 5cf1348a..bf0e027d 100644 --- a/lib/jetty/org/eclipse/jetty/security/ConstraintAware.java +++ b/lib/jetty/org/eclipse/jetty/security/ConstraintAware.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/security/ConstraintMapping.java b/lib/jetty/org/eclipse/jetty/security/ConstraintMapping.java index dd99c5bf..9b25c061 100644 --- a/lib/jetty/org/eclipse/jetty/security/ConstraintMapping.java +++ b/lib/jetty/org/eclipse/jetty/security/ConstraintMapping.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/security/ConstraintSecurityHandler.java b/lib/jetty/org/eclipse/jetty/security/ConstraintSecurityHandler.java index 201618d8..47efd256 100644 --- a/lib/jetty/org/eclipse/jetty/security/ConstraintSecurityHandler.java +++ b/lib/jetty/org/eclipse/jetty/security/ConstraintSecurityHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 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 mappings = (Map)_constraintMap.match(pathInContext); + Map 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); } diff --git a/lib/jetty/org/eclipse/jetty/security/CrossContextPsuedoSession.java b/lib/jetty/org/eclipse/jetty/security/CrossContextPsuedoSession.java index e2de9f7d..9e82addb 100644 --- a/lib/jetty/org/eclipse/jetty/security/CrossContextPsuedoSession.java +++ b/lib/jetty/org/eclipse/jetty/security/CrossContextPsuedoSession.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 { diff --git a/lib/jetty/org/eclipse/jetty/security/DefaultAuthenticatorFactory.java b/lib/jetty/org/eclipse/jetty/security/DefaultAuthenticatorFactory.java index 534a6d40..e68dd71b 100644 --- a/lib/jetty/org/eclipse/jetty/security/DefaultAuthenticatorFactory.java +++ b/lib/jetty/org/eclipse/jetty/security/DefaultAuthenticatorFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/security/DefaultIdentityService.java b/lib/jetty/org/eclipse/jetty/security/DefaultIdentityService.java index c8ae0c29..e3001146 100644 --- a/lib/jetty/org/eclipse/jetty/security/DefaultIdentityService.java +++ b/lib/jetty/org/eclipse/jetty/security/DefaultIdentityService.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/security/DefaultUserIdentity.java b/lib/jetty/org/eclipse/jetty/security/DefaultUserIdentity.java index 65e083d5..1cdc8ccd 100644 --- a/lib/jetty/org/eclipse/jetty/security/DefaultUserIdentity.java +++ b/lib/jetty/org/eclipse/jetty/security/DefaultUserIdentity.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/security/HashCrossContextPsuedoSession.java b/lib/jetty/org/eclipse/jetty/security/HashCrossContextPsuedoSession.java index 8499a609..e205d774 100644 --- a/lib/jetty/org/eclipse/jetty/security/HashCrossContextPsuedoSession.java +++ b/lib/jetty/org/eclipse/jetty/security/HashCrossContextPsuedoSession.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 implements CrossContextPsuedoSession { diff --git a/lib/jetty/org/eclipse/jetty/security/HashLoginService.java b/lib/jetty/org/eclipse/jetty/security/HashLoginService.java index 335aabd7..beb051b6 100644 --- a/lib/jetty/org/eclipse/jetty/security/HashLoginService.java +++ b/lib/jetty/org/eclipse/jetty/security/HashLoginService.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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; } /* ------------------------------------------------------------ */ diff --git a/lib/jetty/org/eclipse/jetty/security/IdentityService.java b/lib/jetty/org/eclipse/jetty/security/IdentityService.java index 99094c17..b37cc5cc 100644 --- a/lib/jetty/org/eclipse/jetty/security/IdentityService.java +++ b/lib/jetty/org/eclipse/jetty/security/IdentityService.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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; /* ------------------------------------------------------------ */ diff --git a/lib/jetty/org/eclipse/jetty/security/JDBCLoginService.java b/lib/jetty/org/eclipse/jetty/security/JDBCLoginService.java index 30b0a831..98f7664a 100644 --- a/lib/jetty/org/eclipse/jetty/security/JDBCLoginService.java +++ b/lib/jetty/org/eclipse/jetty/security/JDBCLoginService.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 diff --git a/lib/jetty/org/eclipse/jetty/security/LoginService.java b/lib/jetty/org/eclipse/jetty/security/LoginService.java index 1e64141f..b1d9aa43 100644 --- a/lib/jetty/org/eclipse/jetty/security/LoginService.java +++ b/lib/jetty/org/eclipse/jetty/security/LoginService.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/security/MappedLoginService.java b/lib/jetty/org/eclipse/jetty/security/MappedLoginService.java index 480131de..4cec9b37 100644 --- a/lib/jetty/org/eclipse/jetty/security/MappedLoginService.java +++ b/lib/jetty/org/eclipse/jetty/security/MappedLoginService.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/security/PropertyUserStore.java b/lib/jetty/org/eclipse/jetty/security/PropertyUserStore.java index 7a8b5e75..cbd3bfdd 100644 --- a/lib/jetty/org/eclipse/jetty/security/PropertyUserStore.java +++ b/lib/jetty/org/eclipse/jetty/security/PropertyUserStore.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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); diff --git a/lib/jetty/org/eclipse/jetty/security/RoleInfo.java b/lib/jetty/org/eclipse/jetty/security/RoleInfo.java index 55f1ae2e..d52afd4e 100644 --- a/lib/jetty/org/eclipse/jetty/security/RoleInfo.java +++ b/lib/jetty/org/eclipse/jetty/security/RoleInfo.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/security/RoleRunAsToken.java b/lib/jetty/org/eclipse/jetty/security/RoleRunAsToken.java index 13a7ea74..49368608 100644 --- a/lib/jetty/org/eclipse/jetty/security/RoleRunAsToken.java +++ b/lib/jetty/org/eclipse/jetty/security/RoleRunAsToken.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/security/RunAsToken.java b/lib/jetty/org/eclipse/jetty/security/RunAsToken.java index 639c9726..afef9fee 100644 --- a/lib/jetty/org/eclipse/jetty/security/RunAsToken.java +++ b/lib/jetty/org/eclipse/jetty/security/RunAsToken.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/security/SecurityHandler.java b/lib/jetty/org/eclipse/jetty/security/SecurityHandler.java index a6e108e9..bfcb8fa6 100644 --- a/lib/jetty/org/eclipse/jetty/security/SecurityHandler.java +++ b/lib/jetty/org/eclipse/jetty/security/SecurityHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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; diff --git a/lib/jetty/org/eclipse/jetty/security/ServerAuthException.java b/lib/jetty/org/eclipse/jetty/security/ServerAuthException.java index 85f532fa..1cd51198 100644 --- a/lib/jetty/org/eclipse/jetty/security/ServerAuthException.java +++ b/lib/jetty/org/eclipse/jetty/security/ServerAuthException.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/security/SpnegoLoginService.java b/lib/jetty/org/eclipse/jetty/security/SpnegoLoginService.java index ba160f06..3155b43c 100644 --- a/lib/jetty/org/eclipse/jetty/security/SpnegoLoginService.java +++ b/lib/jetty/org/eclipse/jetty/security/SpnegoLoginService.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/security/SpnegoUserIdentity.java b/lib/jetty/org/eclipse/jetty/security/SpnegoUserIdentity.java index 13cf0bb1..4951ecfd 100644 --- a/lib/jetty/org/eclipse/jetty/security/SpnegoUserIdentity.java +++ b/lib/jetty/org/eclipse/jetty/security/SpnegoUserIdentity.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/security/SpnegoUserPrincipal.java b/lib/jetty/org/eclipse/jetty/security/SpnegoUserPrincipal.java index 3fe9445f..ff297b51 100644 --- a/lib/jetty/org/eclipse/jetty/security/SpnegoUserPrincipal.java +++ b/lib/jetty/org/eclipse/jetty/security/SpnegoUserPrincipal.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/security/UserAuthentication.java b/lib/jetty/org/eclipse/jetty/security/UserAuthentication.java index 9174a06c..20777616 100644 --- a/lib/jetty/org/eclipse/jetty/security/UserAuthentication.java +++ b/lib/jetty/org/eclipse/jetty/security/UserAuthentication.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/security/UserDataConstraint.java b/lib/jetty/org/eclipse/jetty/security/UserDataConstraint.java index c288e1dc..e8bd1718 100644 --- a/lib/jetty/org/eclipse/jetty/security/UserDataConstraint.java +++ b/lib/jetty/org/eclipse/jetty/security/UserDataConstraint.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/security/authentication/BasicAuthenticator.java b/lib/jetty/org/eclipse/jetty/security/authentication/BasicAuthenticator.java index caa784f0..c3b3e113 100644 --- a/lib/jetty/org/eclipse/jetty/security/authentication/BasicAuthenticator.java +++ b/lib/jetty/org/eclipse/jetty/security/authentication/BasicAuthenticator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/security/authentication/ClientCertAuthenticator.java b/lib/jetty/org/eclipse/jetty/security/authentication/ClientCertAuthenticator.java index 9694cf15..bfdeb73b 100644 --- a/lib/jetty/org/eclipse/jetty/security/authentication/ClientCertAuthenticator.java +++ b/lib/jetty/org/eclipse/jetty/security/authentication/ClientCertAuthenticator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/security/authentication/DeferredAuthentication.java b/lib/jetty/org/eclipse/jetty/security/authentication/DeferredAuthentication.java index df0f7d92..32f04610 100644 --- a/lib/jetty/org/eclipse/jetty/security/authentication/DeferredAuthentication.java +++ b/lib/jetty/org/eclipse/jetty/security/authentication/DeferredAuthentication.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 getHeaderNames() - { - return Collections.emptyList(); - } + public Collection getHeaderNames() + { + return Collections.emptyList(); + } - @Override - public String getHeader(String arg0) - { - return null; - } + @Override + public String getHeader(String arg0) + { + return null; + } - @Override - public Collection getHeaders(String arg0) - { + @Override + public Collection getHeaders(String arg0) + { return Collections.emptyList(); - } + } - @Override - public int getStatus() - { - return 0; - } + @Override + public int getStatus() + { + return 0; + } }; diff --git a/lib/jetty/org/eclipse/jetty/security/authentication/DigestAuthenticator.java b/lib/jetty/org/eclipse/jetty/security/authentication/DigestAuthenticator.java index 13537e6c..99a46a37 100644 --- a/lib/jetty/org/eclipse/jetty/security/authentication/DigestAuthenticator.java +++ b/lib/jetty/org/eclipse/jetty/security/authentication/DigestAuthenticator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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; diff --git a/lib/jetty/org/eclipse/jetty/security/authentication/FormAuthenticator.java b/lib/jetty/org/eclipse/jetty/security/authentication/FormAuthenticator.java index dcfea416..6a5b2a61 100644 --- a/lib/jetty/org/eclipse/jetty/security/authentication/FormAuthenticator.java +++ b/lib/jetty/org/eclipse/jetty/security/authentication/FormAuthenticator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/security/authentication/LoginAuthenticator.java b/lib/jetty/org/eclipse/jetty/security/authentication/LoginAuthenticator.java index 9a1940d8..4f5a9ec9 100644 --- a/lib/jetty/org/eclipse/jetty/security/authentication/LoginAuthenticator.java +++ b/lib/jetty/org/eclipse/jetty/security/authentication/LoginAuthenticator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/security/authentication/LoginCallback.java b/lib/jetty/org/eclipse/jetty/security/authentication/LoginCallback.java index e123b221..92eeea33 100644 --- a/lib/jetty/org/eclipse/jetty/security/authentication/LoginCallback.java +++ b/lib/jetty/org/eclipse/jetty/security/authentication/LoginCallback.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/security/authentication/LoginCallbackImpl.java b/lib/jetty/org/eclipse/jetty/security/authentication/LoginCallbackImpl.java index 5939caf7..c9223ab0 100644 --- a/lib/jetty/org/eclipse/jetty/security/authentication/LoginCallbackImpl.java +++ b/lib/jetty/org/eclipse/jetty/security/authentication/LoginCallbackImpl.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/security/authentication/SessionAuthentication.java b/lib/jetty/org/eclipse/jetty/security/authentication/SessionAuthentication.java index e3be5846..6f589472 100644 --- a/lib/jetty/org/eclipse/jetty/security/authentication/SessionAuthentication.java +++ b/lib/jetty/org/eclipse/jetty/security/authentication/SessionAuthentication.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/security/authentication/SpnegoAuthenticator.java b/lib/jetty/org/eclipse/jetty/security/authentication/SpnegoAuthenticator.java index 8469c0a8..182635a2 100644 --- a/lib/jetty/org/eclipse/jetty/security/authentication/SpnegoAuthenticator.java +++ b/lib/jetty/org/eclipse/jetty/security/authentication/SpnegoAuthenticator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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()); diff --git a/lib/jetty/org/eclipse/jetty/security/authentication/package-info.java b/lib/jetty/org/eclipse/jetty/security/authentication/package-info.java index 0e0c617b..9f28e686 100644 --- a/lib/jetty/org/eclipse/jetty/security/authentication/package-info.java +++ b/lib/jetty/org/eclipse/jetty/security/authentication/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/security/package-info.java b/lib/jetty/org/eclipse/jetty/security/package-info.java index edb5ea4e..bda98bc2 100644 --- a/lib/jetty/org/eclipse/jetty/security/package-info.java +++ b/lib/jetty/org/eclipse/jetty/security/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/AbstractConnectionFactory.java b/lib/jetty/org/eclipse/jetty/server/AbstractConnectionFactory.java index 96fb3a2d..bbbb1658 100644 --- a/lib/jetty/org/eclipse/jetty/server/AbstractConnectionFactory.java +++ b/lib/jetty/org/eclipse/jetty/server/AbstractConnectionFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/AbstractConnector.java b/lib/jetty/org/eclipse/jetty/server/AbstractConnector.java index 7d3402fb..c758addd 100644 --- a/lib/jetty/org/eclipse/jetty/server/AbstractConnector.java +++ b/lib/jetty/org/eclipse/jetty/server/AbstractConnector.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 _endpoints = Collections.newSetFromMap(new ConcurrentHashMap()); + private final Set _endpoints = Collections.newSetFromMap(new ConcurrentHashMap()); private final Set _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. + *

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

+ * @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; + } + } diff --git a/lib/jetty/org/eclipse/jetty/server/AbstractNCSARequestLog.java b/lib/jetty/org/eclipse/jetty/server/AbstractNCSARequestLog.java index dcaecbe5..7861d1a4 100644 --- a/lib/jetty/org/eclipse/jetty/server/AbstractNCSARequestLog.java +++ b/lib/jetty/org/eclipse/jetty/server/AbstractNCSARequestLog.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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) diff --git a/lib/jetty/org/eclipse/jetty/server/AbstractNetworkConnector.java b/lib/jetty/org/eclipse/jetty/server/AbstractNetworkConnector.java index 08b65bc4..c5b84018 100644 --- a/lib/jetty/org/eclipse/jetty/server/AbstractNetworkConnector.java +++ b/lib/jetty/org/eclipse/jetty/server/AbstractNetworkConnector.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/AsyncContextEvent.java b/lib/jetty/org/eclipse/jetty/server/AsyncContextEvent.java index cc0eec89..4c8d3fa2 100644 --- a/lib/jetty/org/eclipse/jetty/server/AsyncContextEvent.java +++ b/lib/jetty/org/eclipse/jetty/server/AsyncContextEvent.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/AsyncContextState.java b/lib/jetty/org/eclipse/jetty/server/AsyncContextState.java index 6503424d..40e4a096 100644 --- a/lib/jetty/org/eclipse/jetty/server/AsyncContextState.java +++ b/lib/jetty/org/eclipse/jetty/server/AsyncContextState.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/AsyncNCSARequestLog.java b/lib/jetty/org/eclipse/jetty/server/AsyncNCSARequestLog.java index 33ba21d7..8f639b7f 100644 --- a/lib/jetty/org/eclipse/jetty/server/AsyncNCSARequestLog.java +++ b/lib/jetty/org/eclipse/jetty/server/AsyncNCSARequestLog.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/Authentication.java b/lib/jetty/org/eclipse/jetty/server/Authentication.java index ccdf4c0f..7bacc3e1 100644 --- a/lib/jetty/org/eclipse/jetty/server/Authentication.java +++ b/lib/jetty/org/eclipse/jetty/server/Authentication.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/ByteBufferQueuedHttpInput.java b/lib/jetty/org/eclipse/jetty/server/ByteBufferQueuedHttpInput.java index cd2d12e8..60e62a33 100644 --- a/lib/jetty/org/eclipse/jetty/server/ByteBufferQueuedHttpInput.java +++ b/lib/jetty/org/eclipse/jetty/server/ByteBufferQueuedHttpInput.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/ClassLoaderDump.java b/lib/jetty/org/eclipse/jetty/server/ClassLoaderDump.java index 466775e4..56c3b6d7 100644 --- a/lib/jetty/org/eclipse/jetty/server/ClassLoaderDump.java +++ b/lib/jetty/org/eclipse/jetty/server/ClassLoaderDump.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/ConnectionFactory.java b/lib/jetty/org/eclipse/jetty/server/ConnectionFactory.java index e23739d8..a9599c4b 100644 --- a/lib/jetty/org/eclipse/jetty/server/ConnectionFactory.java +++ b/lib/jetty/org/eclipse/jetty/server/ConnectionFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/Connector.java b/lib/jetty/org/eclipse/jetty/server/Connector.java index ce4544c9..be958ada 100644 --- a/lib/jetty/org/eclipse/jetty/server/Connector.java +++ b/lib/jetty/org/eclipse/jetty/server/Connector.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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; diff --git a/lib/jetty/org/eclipse/jetty/server/ConnectorStatistics.java b/lib/jetty/org/eclipse/jetty/server/ConnectorStatistics.java index cae5e6eb..d5d7fcd0 100644 --- a/lib/jetty/org/eclipse/jetty/server/ConnectorStatistics.java +++ b/lib/jetty/org/eclipse/jetty/server/ConnectorStatistics.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/CookieCutter.java b/lib/jetty/org/eclipse/jetty/server/CookieCutter.java index 703f8049..8ccfcbe7 100644 --- a/lib/jetty/org/eclipse/jetty/server/CookieCutter.java +++ b/lib/jetty/org/eclipse/jetty/server/CookieCutter.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/Dispatcher.java b/lib/jetty/org/eclipse/jetty/server/Dispatcher.java index 25672897..a34a83de 100644 --- a/lib/jetty/org/eclipse/jetty/server/Dispatcher.java +++ b/lib/jetty/org/eclipse/jetty/server/Dispatcher.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/EncodingHttpWriter.java b/lib/jetty/org/eclipse/jetty/server/EncodingHttpWriter.java index 88301d4b..e49cb009 100644 --- a/lib/jetty/org/eclipse/jetty/server/EncodingHttpWriter.java +++ b/lib/jetty/org/eclipse/jetty/server/EncodingHttpWriter.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/ForwardedRequestCustomizer.java b/lib/jetty/org/eclipse/jetty/server/ForwardedRequestCustomizer.java index 891e8ee1..1e9d1740 100644 --- a/lib/jetty/org/eclipse/jetty/server/ForwardedRequestCustomizer.java +++ b/lib/jetty/org/eclipse/jetty/server/ForwardedRequestCustomizer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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; diff --git a/lib/jetty/org/eclipse/jetty/server/Handler.java b/lib/jetty/org/eclipse/jetty/server/Handler.java index cfe7b9a2..b32cc821 100644 --- a/lib/jetty/org/eclipse/jetty/server/Handler.java +++ b/lib/jetty/org/eclipse/jetty/server/Handler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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; diff --git a/lib/jetty/org/eclipse/jetty/server/HandlerContainer.java b/lib/jetty/org/eclipse/jetty/server/HandlerContainer.java index 51fd4791..5f675274 100644 --- a/lib/jetty/org/eclipse/jetty/server/HandlerContainer.java +++ b/lib/jetty/org/eclipse/jetty/server/HandlerContainer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 index 00000000..d3af3cb8 --- /dev/null +++ b/lib/jetty/org/eclipse/jetty/server/HomeBaseWarning.java @@ -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. + *

+ * 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()); + } + } +} diff --git a/lib/jetty/org/eclipse/jetty/server/HostHeaderCustomizer.java b/lib/jetty/org/eclipse/jetty/server/HostHeaderCustomizer.java index b39b25dc..464f1d26 100644 --- a/lib/jetty/org/eclipse/jetty/server/HostHeaderCustomizer.java +++ b/lib/jetty/org/eclipse/jetty/server/HostHeaderCustomizer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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). *

diff --git a/lib/jetty/org/eclipse/jetty/server/HttpChannel.java b/lib/jetty/org/eclipse/jetty/server/HttpChannel.java index 07b09ab7..8093f46d 100644 --- a/lib/jetty/org/eclipse/jetty/server/HttpChannel.java +++ b/lib/jetty/org/eclipse/jetty/server/HttpChannel.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 implements HttpParser.RequestHandler, 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 implements HttpParser.RequestHandler, 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 implements HttpParser.RequestHandler, Runnable, H { return _transport; } - + + /** + * Get the idle timeout. + *

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. + *

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 implements HttpParser.RequestHandler, Runnable, H */ public boolean handle() { - LOG.debug("{} handle enter", this); + if (LOG.isDebugEnabled()) + LOG.debug("{} handle enter", this); final HttpChannellast = setCurrentHttpChannel(this); @@ -270,7 +292,8 @@ public class HttpChannel implements HttpParser.RequestHandler, 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 implements HttpParser.RequestHandler, Runnable, H _response.getHttpOutput().reopen(); _request.setDispatcherType(DispatcherType.REQUEST); - for (HttpConfiguration.Customizer customizer : _configuration.getCustomizers()) - customizer.customize(getConnector(),_configuration,_request); + List 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 implements HttpParser.RequestHandler, 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 implements HttpParser.RequestHandler, Runnable, H else _response.getHttpOutput().run(); break; - } + } default: break loop; @@ -354,7 +381,10 @@ public class HttpChannel implements HttpParser.RequestHandler, 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 implements HttpParser.RequestHandler, 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 implements HttpParser.RequestHandler, 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 implements HttpParser.RequestHandler, 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 implements HttpParser.RequestHandler, 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 implements HttpParser.RequestHandler, 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 implements HttpParser.RequestHandler, 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 implements HttpParser.RequestHandler, 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 implements HttpParser.RequestHandler, 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 implements HttpParser.RequestHandler, 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 implements HttpParser.RequestHandler, 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 boolean committing = _committed.compareAndSet(false, true); if (committing) { @@ -720,7 +755,7 @@ public class HttpChannel implements HttpParser.RequestHandler, 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 implements HttpParser.RequestHandler, 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 implements HttpParser.RequestHandler, Runnable, H @Override public void succeeded() { - _committed.set(false); - super.succeeded(); + if (_committed.compareAndSet(true, false)) + super.succeeded(); + else + super.failed(new IllegalStateException()); } } diff --git a/lib/jetty/org/eclipse/jetty/server/HttpChannelState.java b/lib/jetty/org/eclipse/jetty/server/HttpChannelState.java index 7ff4d5a2..c0cfa2f0 100644 --- a/lib/jetty/org/eclipse/jetty/server/HttpChannelState.java +++ b/lib/jetty/org/eclipse/jetty/server/HttpChannelState.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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() { diff --git a/lib/jetty/org/eclipse/jetty/server/HttpConfiguration.java b/lib/jetty/org/eclipse/jetty/server/HttpConfiguration.java index 352af25c..f1cce65c 100644 --- a/lib/jetty/org/eclipse/jetty/server/HttpConfiguration.java +++ b/lib/jetty/org/eclipse/jetty/server/HttpConfiguration.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 _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; + /* ------------------------------------------------------------ */ + /** + *

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. + * + *

Typically Customizers perform tasks such as:

    + *
  • process header fields that may be injected by a proxy or load balancer. + *
  • setup attributes that may come from the connection/connector such as SSL Session IDs + *
  • 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 + *
  • Set request attributes/fields that are determined by the connector on which the + * request was received + *
+ */ 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 getCustomizer(Class 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; + } + /* ------------------------------------------------------------ */ /** *

Set the {@link Customizer}s that are invoked for every * request received.

- *

Customisers are often used to interpret optional headers (eg {@link ForwardedRequestCustomizer}) or + *

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 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. *

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); } } diff --git a/lib/jetty/org/eclipse/jetty/server/HttpConnection.java b/lib/jetty/org/eclipse/jetty/server/HttpConnection.java index 16cbbf93..c489ae9b 100644 --- a/lib/jetty/org/eclipse/jetty/server/HttpConnection.java +++ b/lib/jetty/org/eclipse/jetty/server/HttpConnection.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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; /** *

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

*/ -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 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 newHttpInput() { return new HttpInputOverHTTP(this); } - + protected HttpChannelOverHttp newHttpChannel(HttpInput 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 { public HttpChannelOverHttp(Connector connector, HttpConfiguration config, EndPoint endPoint, HttpTransport transport, HttpInput 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(); - } - } diff --git a/lib/jetty/org/eclipse/jetty/server/HttpConnectionFactory.java b/lib/jetty/org/eclipse/jetty/server/HttpConnectionFactory.java index ce6ffdb7..1f402a88 100644 --- a/lib/jetty/org/eclipse/jetty/server/HttpConnectionFactory.java +++ b/lib/jetty/org/eclipse/jetty/server/HttpConnectionFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/HttpInput.java b/lib/jetty/org/eclipse/jetty/server/HttpInput.java index 833ecded..963d66b5 100644 --- a/lib/jetty/org/eclipse/jetty/server/HttpInput.java +++ b/lib/jetty/org/eclipse/jetty/server/HttpInput.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 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 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 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 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 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 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 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 extends ServletInputStream implements Runnabl } } + @Override public boolean isReady() { @@ -346,16 +366,30 @@ public abstract class HttpInput 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 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 extends ServletInputStream implements Runnabl @Override public int noContent() throws IOException { - throw new EofException(); + throw new EofException("Early EOF"); } @Override diff --git a/lib/jetty/org/eclipse/jetty/server/HttpInputOverHTTP.java b/lib/jetty/org/eclipse/jetty/server/HttpInputOverHTTP.java index 35524500..f91becc6 100644 --- a/lib/jetty/org/eclipse/jetty/server/HttpInputOverHTTP.java +++ b/lib/jetty/org/eclipse/jetty/server/HttpInputOverHTTP.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 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(); } diff --git a/lib/jetty/org/eclipse/jetty/server/HttpOutput.java b/lib/jetty/org/eclipse/jetty/server/HttpOutput.java index 7c0fd899..47346cb1 100644 --- a/lib/jetty/org/eclipse/jetty/server/HttpOutput.java +++ b/lib/jetty/org/eclipse/jetty/server/HttpOutput.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 } } } - } diff --git a/lib/jetty/org/eclipse/jetty/server/HttpTransport.java b/lib/jetty/org/eclipse/jetty/server/HttpTransport.java index 7058425f..d3922467 100644 --- a/lib/jetty/org/eclipse/jetty/server/HttpTransport.java +++ b/lib/jetty/org/eclipse/jetty/server/HttpTransport.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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); diff --git a/lib/jetty/org/eclipse/jetty/server/HttpWriter.java b/lib/jetty/org/eclipse/jetty/server/HttpWriter.java index d02a8c4b..bdef4f84 100644 --- a/lib/jetty/org/eclipse/jetty/server/HttpWriter.java +++ b/lib/jetty/org/eclipse/jetty/server/HttpWriter.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/InclusiveByteRange.java b/lib/jetty/org/eclipse/jetty/server/InclusiveByteRange.java index cb81d3c9..4340cabb 100644 --- a/lib/jetty/org/eclipse/jetty/server/InclusiveByteRange.java +++ b/lib/jetty/org/eclipse/jetty/server/InclusiveByteRange.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 satisfiableRanges(Enumeration headers, long size) + public static List satisfiableRanges(Enumeration 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 diff --git a/lib/jetty/org/eclipse/jetty/server/Iso88591HttpWriter.java b/lib/jetty/org/eclipse/jetty/server/Iso88591HttpWriter.java index b4cdf8ff..3baac05d 100644 --- a/lib/jetty/org/eclipse/jetty/server/Iso88591HttpWriter.java +++ b/lib/jetty/org/eclipse/jetty/server/Iso88591HttpWriter.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/LocalConnector.java b/lib/jetty/org/eclipse/jetty/server/LocalConnector.java index 57962263..b41891c5 100644 --- a/lib/jetty/org/eclipse/jetty/server/LocalConnector.java +++ b/lib/jetty/org/eclipse/jetty/server/LocalConnector.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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(); diff --git a/lib/jetty/org/eclipse/jetty/server/LowResourceMonitor.java b/lib/jetty/org/eclipse/jetty/server/LowResourceMonitor.java index 1aad488e..4c379916 100644 --- a/lib/jetty/org/eclipse/jetty/server/LowResourceMonitor.java +++ b/lib/jetty/org/eclipse/jetty/server/LowResourceMonitor.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/NCSARequestLog.java b/lib/jetty/org/eclipse/jetty/server/NCSARequestLog.java index 2c2286e2..0aa5aade 100644 --- a/lib/jetty/org/eclipse/jetty/server/NCSARequestLog.java +++ b/lib/jetty/org/eclipse/jetty/server/NCSARequestLog.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/NegotiatingServerConnection.java b/lib/jetty/org/eclipse/jetty/server/NegotiatingServerConnection.java index 3d010699..be4149df 100644 --- a/lib/jetty/org/eclipse/jetty/server/NegotiatingServerConnection.java +++ b/lib/jetty/org/eclipse/jetty/server/NegotiatingServerConnection.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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,15 +19,15 @@ 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 diff --git a/lib/jetty/org/eclipse/jetty/server/NegotiatingServerConnectionFactory.java b/lib/jetty/org/eclipse/jetty/server/NegotiatingServerConnectionFactory.java index f826d711..10547c2e 100644 --- a/lib/jetty/org/eclipse/jetty/server/NegotiatingServerConnectionFactory.java +++ b/lib/jetty/org/eclipse/jetty/server/NegotiatingServerConnectionFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/NetworkConnector.java b/lib/jetty/org/eclipse/jetty/server/NetworkConnector.java index 58fdc988..7e6ecee4 100644 --- a/lib/jetty/org/eclipse/jetty/server/NetworkConnector.java +++ b/lib/jetty/org/eclipse/jetty/server/NetworkConnector.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/NetworkTrafficServerConnector.java b/lib/jetty/org/eclipse/jetty/server/NetworkTrafficServerConnector.java index 34de615b..9bf0dee4 100644 --- a/lib/jetty/org/eclipse/jetty/server/NetworkTrafficServerConnector.java +++ b/lib/jetty/org/eclipse/jetty/server/NetworkTrafficServerConnector.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/QueuedHttpInput.java b/lib/jetty/org/eclipse/jetty/server/QueuedHttpInput.java index 881fbfa0..e0888979 100644 --- a/lib/jetty/org/eclipse/jetty/server/QueuedHttpInput.java +++ b/lib/jetty/org/eclipse/jetty/server/QueuedHttpInput.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 extends HttpInput { 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 extends HttpInput { _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 extends HttpInput { try { - LOG.debug("{} waiting for content", this); + if (LOG.isDebugEnabled()) + LOG.debug("{} waiting for content", this); lock().wait(); } catch (InterruptedException e) diff --git a/lib/jetty/org/eclipse/jetty/server/QuietServletException.java b/lib/jetty/org/eclipse/jetty/server/QuietServletException.java index 5221d638..fe64bf67 100644 --- a/lib/jetty/org/eclipse/jetty/server/QuietServletException.java +++ b/lib/jetty/org/eclipse/jetty/server/QuietServletException.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/Request.java b/lib/jetty/org/eclipse/jetty/server/Request.java index 77c80abc..a39a1397 100644 --- a/lib/jetty/org/eclipse/jetty/server/Request.java +++ b/lib/jetty/org/eclipse/jetty/server/Request.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 _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 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) diff --git a/lib/jetty/org/eclipse/jetty/server/RequestLog.java b/lib/jetty/org/eclipse/jetty/server/RequestLog.java index 0cb1a530..4391e272 100644 --- a/lib/jetty/org/eclipse/jetty/server/RequestLog.java +++ b/lib/jetty/org/eclipse/jetty/server/RequestLog.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/ResourceCache.java b/lib/jetty/org/eclipse/jetty/server/ResourceCache.java index e39c4a60..187f89f3 100644 --- a/lib/jetty/org/eclipse/jetty/server/ResourceCache.java +++ b/lib/jetty/org/eclipse/jetty/server/ResourceCache.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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()", ">"); - } + message=StringUtil.sanitizeXmlString(message); String uri= request.getRequestURI(); - if (uri!=null) - { - uri= StringUtil.replace(uri, "&", "&"); - uri= StringUtil.replace(uri, "<", "<"); - uri= StringUtil.replace(uri, ">", ">"); - } + uri=StringUtil.sanitizeXmlString(uri); writer.write("\n\n\n"); writer.write("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()); } diff --git a/lib/jetty/org/eclipse/jetty/server/SecureRequestCustomizer.java b/lib/jetty/org/eclipse/jetty/server/SecureRequestCustomizer.java index b0174613..bf364465 100644 --- a/lib/jetty/org/eclipse/jetty/server/SecureRequestCustomizer.java +++ b/lib/jetty/org/eclipse/jetty/server/SecureRequestCustomizer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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() diff --git a/lib/jetty/org/eclipse/jetty/server/Server.java b/lib/jetty/org/eclipse/jetty/server/Server.java index b1437d6d..ba0655e5 100644 --- a/lib/jetty/org/eclipse/jetty/server/Server.java +++ b/lib/jetty/org/eclipse/jetty/server/Server.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 { diff --git a/lib/jetty/org/eclipse/jetty/server/ServerConnector.java b/lib/jetty/org/eclipse/jetty/server/ServerConnector.java index a7d5fe0f..2766a89f 100644 --- a/lib/jetty/org/eclipse/jetty/server/ServerConnector.java +++ b/lib/jetty/org/eclipse/jetty/server/ServerConnector.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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) diff --git a/lib/jetty/org/eclipse/jetty/server/ServletRequestHttpWrapper.java b/lib/jetty/org/eclipse/jetty/server/ServletRequestHttpWrapper.java index 11f249e1..e0d5a6fa 100644 --- a/lib/jetty/org/eclipse/jetty/server/ServletRequestHttpWrapper.java +++ b/lib/jetty/org/eclipse/jetty/server/ServletRequestHttpWrapper.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 { diff --git a/lib/jetty/org/eclipse/jetty/server/ServletResponseHttpWrapper.java b/lib/jetty/org/eclipse/jetty/server/ServletResponseHttpWrapper.java index 076ab1b2..39c77116 100644 --- a/lib/jetty/org/eclipse/jetty/server/ServletResponseHttpWrapper.java +++ b/lib/jetty/org/eclipse/jetty/server/ServletResponseHttpWrapper.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/SessionIdManager.java b/lib/jetty/org/eclipse/jetty/server/SessionIdManager.java index ef7ee623..13e6c80b 100644 --- a/lib/jetty/org/eclipse/jetty/server/SessionIdManager.java +++ b/lib/jetty/org/eclipse/jetty/server/SessionIdManager.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/SessionManager.java b/lib/jetty/org/eclipse/jetty/server/SessionManager.java index 267391b5..d7f7f332 100644 --- a/lib/jetty/org/eclipse/jetty/server/SessionManager.java +++ b/lib/jetty/org/eclipse/jetty/server/SessionManager.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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; diff --git a/lib/jetty/org/eclipse/jetty/server/ShutdownMonitor.java b/lib/jetty/org/eclipse/jetty/server/ShutdownMonitor.java index abc6d61e..d49b2888 100644 --- a/lib/jetty/org/eclipse/jetty/server/ShutdownMonitor.java +++ b/lib/jetty/org/eclipse/jetty/server/ShutdownMonitor.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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; } diff --git a/lib/jetty/org/eclipse/jetty/server/SslConnectionFactory.java b/lib/jetty/org/eclipse/jetty/server/SslConnectionFactory.java index 5fcc1038..eafa594a 100644 --- a/lib/jetty/org/eclipse/jetty/server/SslConnectionFactory.java +++ b/lib/jetty/org/eclipse/jetty/server/SslConnectionFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/UserIdentity.java b/lib/jetty/org/eclipse/jetty/server/UserIdentity.java index 4e20331d..3b67f2c7 100644 --- a/lib/jetty/org/eclipse/jetty/server/UserIdentity.java +++ b/lib/jetty/org/eclipse/jetty/server/UserIdentity.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/Utf8HttpWriter.java b/lib/jetty/org/eclipse/jetty/server/Utf8HttpWriter.java index cbd1adb9..2ff31190 100644 --- a/lib/jetty/org/eclipse/jetty/server/Utf8HttpWriter.java +++ b/lib/jetty/org/eclipse/jetty/server/Utf8HttpWriter.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/AbstractHandler.java b/lib/jetty/org/eclipse/jetty/server/handler/AbstractHandler.java index 3d92512c..107f5c98 100644 --- a/lib/jetty/org/eclipse/jetty/server/handler/AbstractHandler.java +++ b/lib/jetty/org/eclipse/jetty/server/handler/AbstractHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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(); } diff --git a/lib/jetty/org/eclipse/jetty/server/handler/AbstractHandlerContainer.java b/lib/jetty/org/eclipse/jetty/server/handler/AbstractHandlerContainer.java index 0d54e536..1cb75387 100644 --- a/lib/jetty/org/eclipse/jetty/server/handler/AbstractHandlerContainer.java +++ b/lib/jetty/org/eclipse/jetty/server/handler/AbstractHandlerContainer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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) diff --git a/lib/jetty/org/eclipse/jetty/server/handler/AllowSymLinkAliasChecker.java b/lib/jetty/org/eclipse/jetty/server/handler/AllowSymLinkAliasChecker.java index c3d8b593..0df51cb8 100644 --- a/lib/jetty/org/eclipse/jetty/server/handler/AllowSymLinkAliasChecker.java +++ b/lib/jetty/org/eclipse/jetty/server/handler/AllowSymLinkAliasChecker.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 index 00000000..9fd87d35 --- /dev/null +++ b/lib/jetty/org/eclipse/jetty/server/handler/AsyncDelayHandler.java @@ -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) + { + + } + + +} diff --git a/lib/jetty/org/eclipse/jetty/server/handler/ContextHandler.java b/lib/jetty/org/eclipse/jetty/server/handler/ContextHandler.java index 397cde1f..928f850b 100644 --- a/lib/jetty/org/eclipse/jetty/server/handler/ContextHandler.java +++ b/lib/jetty/org/eclipse/jetty/server/handler/ContextHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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(); } diff --git a/lib/jetty/org/eclipse/jetty/server/handler/ContextHandlerCollection.java b/lib/jetty/org/eclipse/jetty/server/handler/ContextHandlerCollection.java index 4ade3649..b4f359b3 100644 --- a/lib/jetty/org/eclipse/jetty/server/handler/ContextHandlerCollection.java +++ b/lib/jetty/org/eclipse/jetty/server/handler/ContextHandlerCollection.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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,15 @@ 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)); + } + } + } diff --git a/lib/jetty/org/eclipse/jetty/server/handler/DebugHandler.java b/lib/jetty/org/eclipse/jetty/server/handler/DebugHandler.java index 0ed72612..651abd8a 100644 --- a/lib/jetty/org/eclipse/jetty/server/handler/DebugHandler.java +++ b/lib/jetty/org/eclipse/jetty/server/handler/DebugHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/DefaultHandler.java b/lib/jetty/org/eclipse/jetty/server/handler/DefaultHandler.java index f71720af..fbc59c27 100644 --- a/lib/jetty/org/eclipse/jetty/server/handler/DefaultHandler.java +++ b/lib/jetty/org/eclipse/jetty/server/handler/DefaultHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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("\n\n

Error 404 - Not Found.

\n"); - writer.write("No context on this server matched or handled this request.
"); - writer.write("Contexts known to this server are:
"); + writer.write(" "); + writer.write("Powered by Jetty:// Java Web Server
\n"); - writer.write("\n\n\n"); - writer.flush(); - response.setContentLength(writer.size()); - try (OutputStream out=response.getOutputStream()) - { - writer.writeTo(out); - } + writer.write("\n\n\n"); + writer.flush(); + response.setContentLength(writer.size()); + try (OutputStream out=response.getOutputStream()) + { + writer.writeTo(out); + } + } } /* ------------------------------------------------------------ */ diff --git a/lib/jetty/org/eclipse/jetty/server/handler/ErrorHandler.java b/lib/jetty/org/eclipse/jetty/server/handler/ErrorHandler.java index b1af5208..f1094317 100644 --- a/lib/jetty/org/eclipse/jetty/server/handler/ErrorHandler.java +++ b/lib/jetty/org/eclipse/jetty/server/handler/ErrorHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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' : - writer.write(">"); - break; - - default: - if (Character.isISOControl(c) && !Character.isWhitespace(c)) - writer.write('?'); - else - writer.write(c); - } - } + writer.write(StringUtil.sanitizeXmlString(string)); } /* ------------------------------------------------------------ */ diff --git a/lib/jetty/org/eclipse/jetty/server/handler/HandlerCollection.java b/lib/jetty/org/eclipse/jetty/server/handler/HandlerCollection.java index c118c7ec..21c3a329 100644 --- a/lib/jetty/org/eclipse/jetty/server/handler/HandlerCollection.java +++ b/lib/jetty/org/eclipse/jetty/server/handler/HandlerCollection.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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()); + } } diff --git a/lib/jetty/org/eclipse/jetty/server/handler/HandlerList.java b/lib/jetty/org/eclipse/jetty/server/handler/HandlerList.java index 74320b08..06f19945 100644 --- a/lib/jetty/org/eclipse/jetty/server/handler/HandlerList.java +++ b/lib/jetty/org/eclipse/jetty/server/handler/HandlerList.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/HandlerWrapper.java b/lib/jetty/org/eclipse/jetty/server/handler/HandlerWrapper.java index dcbf6ff5..82f9b346 100644 --- a/lib/jetty/org/eclipse/jetty/server/handler/HandlerWrapper.java +++ b/lib/jetty/org/eclipse/jetty/server/handler/HandlerWrapper.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 HandlerWrapper acts as a {@link Handler} but delegates the {@link Handler#handle handle} method and diff --git a/lib/jetty/org/eclipse/jetty/server/handler/HotSwapHandler.java b/lib/jetty/org/eclipse/jetty/server/handler/HotSwapHandler.java index 162a719e..6da22cf4 100644 --- a/lib/jetty/org/eclipse/jetty/server/handler/HotSwapHandler.java +++ b/lib/jetty/org/eclipse/jetty/server/handler/HotSwapHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/IPAccessHandler.java b/lib/jetty/org/eclipse/jetty/server/handler/IPAccessHandler.java index 97a3ac8d..cec075e9 100644 --- a/lib/jetty/org/eclipse/jetty/server/handler/IPAccessHandler.java +++ b/lib/jetty/org/eclipse/jetty/server/handler/IPAccessHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/IdleTimeoutHandler.java b/lib/jetty/org/eclipse/jetty/server/handler/IdleTimeoutHandler.java index 04a90f17..9cbc84c4 100644 --- a/lib/jetty/org/eclipse/jetty/server/handler/IdleTimeoutHandler.java +++ b/lib/jetty/org/eclipse/jetty/server/handler/IdleTimeoutHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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); } } } diff --git a/lib/jetty/org/eclipse/jetty/server/handler/MovedContextHandler.java b/lib/jetty/org/eclipse/jetty/server/handler/MovedContextHandler.java index 5e9fd854..2a90f712 100644 --- a/lib/jetty/org/eclipse/jetty/server/handler/MovedContextHandler.java +++ b/lib/jetty/org/eclipse/jetty/server/handler/MovedContextHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/RequestLogHandler.java b/lib/jetty/org/eclipse/jetty/server/handler/RequestLogHandler.java index 706b988b..00ec275c 100644 --- a/lib/jetty/org/eclipse/jetty/server/handler/RequestLogHandler.java +++ b/lib/jetty/org/eclipse/jetty/server/handler/RequestLogHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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)) diff --git a/lib/jetty/org/eclipse/jetty/server/handler/ResourceHandler.java b/lib/jetty/org/eclipse/jetty/server/handler/ResourceHandler.java index 10d1e051..286284d9 100644 --- a/lib/jetty/org/eclipse/jetty/server/handler/ResourceHandler.java +++ b/lib/jetty/org/eclipse/jetty/server/handler/ResourceHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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() + * 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 diff --git a/lib/jetty/org/eclipse/jetty/server/handler/ShutdownHandler.java b/lib/jetty/org/eclipse/jetty/server/handler/ShutdownHandler.java index e946fb67..6a4daa37 100644 --- a/lib/jetty/org/eclipse/jetty/server/handler/ShutdownHandler.java +++ b/lib/jetty/org/eclipse/jetty/server/handler/ShutdownHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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("secret password") }); + { someOtherHandler, new ShutdownHandler("secret password", false, true) }); server.setHandler(handlers); server.start(); @@ -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); } diff --git a/lib/jetty/org/eclipse/jetty/server/handler/StatisticsHandler.java b/lib/jetty/org/eclipse/jetty/server/handler/StatisticsHandler.java index 98bb4134..d2694eeb 100644 --- a/lib/jetty/org/eclipse/jetty/server/handler/StatisticsHandler.java +++ b/lib/jetty/org/eclipse/jetty/server/handler/StatisticsHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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()); } diff --git a/lib/jetty/org/eclipse/jetty/server/handler/package-info.java b/lib/jetty/org/eclipse/jetty/server/handler/package-info.java index 1571d7b9..eb5a1600 100644 --- a/lib/jetty/org/eclipse/jetty/server/handler/package-info.java +++ b/lib/jetty/org/eclipse/jetty/server/handler/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/nio/NetworkTrafficSelectChannelConnector.java b/lib/jetty/org/eclipse/jetty/server/nio/NetworkTrafficSelectChannelConnector.java index f4c59583..7857564f 100644 --- a/lib/jetty/org/eclipse/jetty/server/nio/NetworkTrafficSelectChannelConnector.java +++ b/lib/jetty/org/eclipse/jetty/server/nio/NetworkTrafficSelectChannelConnector.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/nio/package-info.java b/lib/jetty/org/eclipse/jetty/server/nio/package-info.java index 8450e18b..846b6dc0 100644 --- a/lib/jetty/org/eclipse/jetty/server/nio/package-info.java +++ b/lib/jetty/org/eclipse/jetty/server/nio/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/package-info.java b/lib/jetty/org/eclipse/jetty/server/package-info.java index 46883049..5ed92376 100644 --- a/lib/jetty/org/eclipse/jetty/server/package-info.java +++ b/lib/jetty/org/eclipse/jetty/server/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/session/AbstractSession.java b/lib/jetty/org/eclipse/jetty/server/session/AbstractSession.java index 809d9d98..64718e31 100644 --- a/lib/jetty/org/eclipse/jetty/server/session/AbstractSession.java +++ b/lib/jetty/org/eclipse/jetty/server/session/AbstractSession.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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,13 +19,10 @@ 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 getAttributeNames() { diff --git a/lib/jetty/org/eclipse/jetty/server/session/AbstractSessionIdManager.java b/lib/jetty/org/eclipse/jetty/server/session/AbstractSessionIdManager.java index 94144083..9d482701 100644 --- a/lib/jetty/org/eclipse/jetty/server/session/AbstractSessionIdManager.java +++ b/lib/jetty/org/eclipse/jetty/server/session/AbstractSessionIdManager.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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; diff --git a/lib/jetty/org/eclipse/jetty/server/session/AbstractSessionManager.java b/lib/jetty/org/eclipse/jetty/server/session/AbstractSessionManager.java index 1f966c59..d2539464 100644 --- a/lib/jetty/org/eclipse/jetty/server/session/AbstractSessionManager.java +++ b/lib/jetty/org/eclipse/jetty/server/session/AbstractSessionManager.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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); } /* ------------------------------------------------------------ */ diff --git a/lib/jetty/org/eclipse/jetty/server/session/HashSessionIdManager.java b/lib/jetty/org/eclipse/jetty/server/session/HashSessionIdManager.java index a17bc06f..fd2aa4d9 100644 --- a/lib/jetty/org/eclipse/jetty/server/session/HashSessionIdManager.java +++ b/lib/jetty/org/eclipse/jetty/server/session/HashSessionIdManager.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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. diff --git a/lib/jetty/org/eclipse/jetty/server/session/HashSessionManager.java b/lib/jetty/org/eclipse/jetty/server/session/HashSessionManager.java index 1effd32f..33962329 100644 --- a/lib/jetty/org/eclipse/jetty/server/session/HashSessionManager.java +++ b/lib/jetty/org/eclipse/jetty/server/session/HashSessionManager.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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= (_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 diff --git a/lib/jetty/org/eclipse/jetty/server/session/MemSession.java b/lib/jetty/org/eclipse/jetty/server/session/MemSession.java index 72dbea8f..8ebed7ec 100644 --- a/lib/jetty/org/eclipse/jetty/server/session/MemSession.java +++ b/lib/jetty/org/eclipse/jetty/server/session/MemSession.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/session/SessionHandler.java b/lib/jetty/org/eclipse/jetty/server/session/SessionHandler.java index e6aedc5b..f89aaa46 100644 --- a/lib/jetty/org/eclipse/jetty/server/session/SessionHandler.java +++ b/lib/jetty/org/eclipse/jetty/server/session/SessionHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 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[] 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) { diff --git a/lib/jetty/org/eclipse/jetty/server/session/package-info.java b/lib/jetty/org/eclipse/jetty/server/session/package-info.java index ed180a18..fe4ece1f 100644 --- a/lib/jetty/org/eclipse/jetty/server/session/package-info.java +++ b/lib/jetty/org/eclipse/jetty/server/session/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/servlet/BaseHolder.java b/lib/jetty/org/eclipse/jetty/servlet/BaseHolder.java index a32e1a61..f0525b12 100644 --- a/lib/jetty/org/eclipse/jetty/servlet/BaseHolder.java +++ b/lib/jetty/org/eclipse/jetty/servlet/BaseHolder.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/servlet/DefaultServlet.java b/lib/jetty/org/eclipse/jetty/servlet/DefaultServlet.java index c3787395..3909259e 100644 --- a/lib/jetty/org/eclipse/jetty/servlet/DefaultServlet.java +++ b/lib/jetty/org/eclipse/jetty/servlet/DefaultServlet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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" * * * @@ -164,6 +171,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory private String _relativeResourceBase; private ServletHandler _servletHandler; private ServletHolder _defaultHolder; + private List _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 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 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 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()); diff --git a/lib/jetty/org/eclipse/jetty/servlet/ErrorPageErrorHandler.java b/lib/jetty/org/eclipse/jetty/servlet/ErrorPageErrorHandler.java index b8efeb18..976fb34a 100644 --- a/lib/jetty/org/eclipse/jetty/servlet/ErrorPageErrorHandler.java +++ b/lib/jetty/org/eclipse/jetty/servlet/ErrorPageErrorHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/servlet/FilterHolder.java b/lib/jetty/org/eclipse/jetty/servlet/FilterHolder.java index d9635fae..cb6210c5 100644 --- a/lib/jetty/org/eclipse/jetty/servlet/FilterHolder.java +++ b/lib/jetty/org/eclipse/jetty/servlet/FilterHolder.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 } _config=new Config(); - LOG.debug("Filter.init {}",_filter); + if (LOG.isDebugEnabled()) + LOG.debug("Filter.init {}",_filter); _filter.init(_config); } diff --git a/lib/jetty/org/eclipse/jetty/servlet/FilterMapping.java b/lib/jetty/org/eclipse/jetty/servlet/FilterMapping.java index 1d5a9a42..749928cb 100644 --- a/lib/jetty/org/eclipse/jetty/servlet/FilterMapping.java +++ b/lib/jetty/org/eclipse/jetty/servlet/FilterMapping.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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; } diff --git a/lib/jetty/org/eclipse/jetty/servlet/Holder.java b/lib/jetty/org/eclipse/jetty/servlet/Holder.java index 2f690b17..2c8fa7ba 100644 --- a/lib/jetty/org/eclipse/jetty/servlet/Holder.java +++ b/lib/jetty/org/eclipse/jetty/servlet/Holder.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 extends BaseHolder } /* ------------------------------------------------------------ */ - public Enumeration getInitParameterNames() + public Enumeration getInitParameterNames() { if (_initParams==null) return Collections.enumeration(Collections.EMPTY_LIST); @@ -227,7 +227,7 @@ public class Holder extends BaseHolder } /* -------------------------------------------------------- */ - public Enumeration getInitParameterNames() + public Enumeration getInitParameterNames() { return Holder.this.getInitParameterNames(); } diff --git a/lib/jetty/org/eclipse/jetty/servlet/Invoker.java b/lib/jetty/org/eclipse/jetty/servlet/Invoker.java index 4613144b..52d9bea6 100644 --- a/lib/jetty/org/eclipse/jetty/servlet/Invoker.java +++ b/lib/jetty/org/eclipse/jetty/servlet/Invoker.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 _invokerEntry; + private Map _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 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(); _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 entry = _servletHandler.getHolderEntry(path); if (entry!=null && !entry.equals(_invokerEntry)) { diff --git a/lib/jetty/org/eclipse/jetty/servlet/JspPropertyGroupServlet.java b/lib/jetty/org/eclipse/jetty/servlet/JspPropertyGroupServlet.java index d0fcbfe1..aa14e2c3 100644 --- a/lib/jetty/org/eclipse/jetty/servlet/JspPropertyGroupServlet.java +++ b/lib/jetty/org/eclipse/jetty/servlet/JspPropertyGroupServlet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 *

- * 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); } - + } } diff --git a/lib/jetty/org/eclipse/jetty/servlet/ListenerHolder.java b/lib/jetty/org/eclipse/jetty/servlet/ListenerHolder.java index 346d4788..c306b13f 100644 --- a/lib/jetty/org/eclipse/jetty/servlet/ListenerHolder.java +++ b/lib/jetty/org/eclipse/jetty/servlet/ListenerHolder.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/servlet/NoJspServlet.java b/lib/jetty/org/eclipse/jetty/servlet/NoJspServlet.java index afd066bb..d4ee4a8c 100644 --- a/lib/jetty/org/eclipse/jetty/servlet/NoJspServlet.java +++ b/lib/jetty/org/eclipse/jetty/servlet/NoJspServlet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/servlet/ServletContextHandler.java b/lib/jetty/org/eclipse/jetty/servlet/ServletContextHandler.java index d01ddd2a..013ab5c8 100644 --- a/lib/jetty/org/eclipse/jetty/servlet/ServletContextHandler.java +++ b/lib/jetty/org/eclipse/jetty/servlet/ServletContextHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 diff --git a/lib/jetty/org/eclipse/jetty/servlet/ServletHandler.java b/lib/jetty/org/eclipse/jetty/servlet/ServletHandler.java index 81243e01..d5b2add1 100644 --- a/lib/jetty/org/eclipse/jetty/servlet/ServletHandler.java +++ b/lib/jetty/org/eclipse/jetty/servlet/ServletHandler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 _servletPathMappings = new HashMap(); - private final Map _filterNameMap= new HashMap<>(); private List _filterPathMappings; private MultiMap _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 _chainCache[] = new ConcurrentMap[FilterMapping.ALL]; + + @SuppressWarnings("unchecked") + protected final Queue[] _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 cache=(Map)_chainCache[dispatch]; - final Queue lru=(Queue)_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 cache=_chainCache[dispatch]; + final Queue 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 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); } } diff --git a/lib/jetty/org/eclipse/jetty/servlet/ServletHolder.java b/lib/jetty/org/eclipse/jetty/servlet/ServletHolder.java index 1df08b33..73e1ccf8 100644 --- a/lib/jetty/org/eclipse/jetty/servlet/ServletHolder.java +++ b/lib/jetty/org/eclipse/jetty/servlet/ServletHolder.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 implements UserIdentity.Scope, Comparable { - 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 _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 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 NO_MAPPED_ROLES = Collections.emptyMap(); + public static enum JspContainer {GLASSFISH, APACHE, OTHER}; /* ---------------------------------------------------------------- */ /** Constructor . @@ -289,11 +294,13 @@ public class ServletHolder extends Holder 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 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 entry:jsp.getInitParameters().entrySet()) @@ -313,9 +321,11 @@ public class ServletHolder extends Holder 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 implements UserIdentity.Scope if (_class!=null && javax.servlet.SingleThreadModel.class.isAssignableFrom(_class)) _servlet = new SingleThreadedWrapper(); - + } @@ -377,21 +387,24 @@ public class ServletHolder extends Holder 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 implements UserIdentity.Scope _servlet=null; _config=null; + _initialized = false; } /* ------------------------------------------------------------ */ @@ -565,7 +579,7 @@ public class ServletHolder extends Holder 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 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 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 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 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 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 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 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 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 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 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)); } diff --git a/lib/jetty/org/eclipse/jetty/servlet/ServletMapping.java b/lib/jetty/org/eclipse/jetty/servlet/ServletMapping.java index df026df6..4d132a65 100644 --- a/lib/jetty/org/eclipse/jetty/servlet/ServletMapping.java +++ b/lib/jetty/org/eclipse/jetty/servlet/ServletMapping.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/servlet/ServletTester.java b/lib/jetty/org/eclipse/jetty/servlet/ServletTester.java index 2317195a..4ad1fd9f 100644 --- a/lib/jetty/org/eclipse/jetty/servlet/ServletTester.java +++ b/lib/jetty/org/eclipse/jetty/servlet/ServletTester.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 getAttributeNames() { return _context.getAttributeNames(); } @@ -122,7 +128,7 @@ public class ServletTester extends ContainerLifeCycle return _context.setInitParameter(name,value); } - public Enumeration getInitParameterNames() + public Enumeration 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. diff --git a/lib/jetty/org/eclipse/jetty/servlet/StatisticsServlet.java b/lib/jetty/org/eclipse/jetty/servlet/StatisticsServlet.java index 6d1bf7d4..09bb2fe0 100644 --- a/lib/jetty/org/eclipse/jetty/servlet/StatisticsServlet.java +++ b/lib/jetty/org/eclipse/jetty/servlet/StatisticsServlet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/servlet/listener/ELContextCleaner.java b/lib/jetty/org/eclipse/jetty/servlet/listener/ELContextCleaner.java index 81b75288..0d07193c 100644 --- a/lib/jetty/org/eclipse/jetty/servlet/listener/ELContextCleaner.java +++ b/lib/jetty/org/eclipse/jetty/servlet/listener/ELContextCleaner.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 itor = map.keySet().iterator(); + Iterator> 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()); + } } } } diff --git a/lib/jetty/org/eclipse/jetty/servlet/listener/IntrospectorCleaner.java b/lib/jetty/org/eclipse/jetty/servlet/listener/IntrospectorCleaner.java index 72a6f0dd..21e13b3b 100644 --- a/lib/jetty/org/eclipse/jetty/servlet/listener/IntrospectorCleaner.java +++ b/lib/jetty/org/eclipse/jetty/servlet/listener/IntrospectorCleaner.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/servlet/listener/package-info.java b/lib/jetty/org/eclipse/jetty/servlet/listener/package-info.java index 2cb69e3b..52cca3ac 100644 --- a/lib/jetty/org/eclipse/jetty/servlet/listener/package-info.java +++ b/lib/jetty/org/eclipse/jetty/servlet/listener/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/servlet/package-info.java b/lib/jetty/org/eclipse/jetty/servlet/package-info.java index f7a9cd55..1ff7b8b1 100644 --- a/lib/jetty/org/eclipse/jetty/servlet/package-info.java +++ b/lib/jetty/org/eclipse/jetty/servlet/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/AbstractTrie.java b/lib/jetty/org/eclipse/jetty/util/AbstractTrie.java index b49bec11..c9b32866 100644 --- a/lib/jetty/org/eclipse/jetty/util/AbstractTrie.java +++ b/lib/jetty/org/eclipse/jetty/util/AbstractTrie.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/ArrayQueue.java b/lib/jetty/org/eclipse/jetty/util/ArrayQueue.java index 671439e5..44d35f14 100644 --- a/lib/jetty/org/eclipse/jetty/util/ArrayQueue.java +++ b/lib/jetty/org/eclipse/jetty/util/ArrayQueue.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/ArrayTernaryTrie.java b/lib/jetty/org/eclipse/jetty/util/ArrayTernaryTrie.java index fdca4ce1..79f08718 100644 --- a/lib/jetty/org/eclipse/jetty/util/ArrayTernaryTrie.java +++ b/lib/jetty/org/eclipse/jetty/util/ArrayTernaryTrie.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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. +/** + *

A Ternary Trie String lookup data structure.

* 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). *

* The Trie is stored in 3 arrays:

@@ -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. *
V[] _value
An array of values corresponding to the _key array
*
+ *

*

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. *

+ *

+ * This Trie may be instantiated either as case sensitive or insensitive. + *

+ *

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. + *

+ * * @param */ public class ArrayTernaryTrie extends AbstractTrie @@ -71,34 +83,60 @@ public class ArrayTernaryTrie extends AbstractTrie * 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 extends AbstractTrie } } - return (V)_value[t]; + return _value[t]; } diff --git a/lib/jetty/org/eclipse/jetty/util/ArrayTrie.java b/lib/jetty/org/eclipse/jetty/util/ArrayTrie.java index 73ccc424..9dbf994a 100644 --- a/lib/jetty/org/eclipse/jetty/util/ArrayTrie.java +++ b/lib/jetty/org/eclipse/jetty/util/ArrayTrie.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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. +/** + *

A Trie String lookup data structure using a fixed size array.

*

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. + *

+ *

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. + *

+ *

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. *

* @param */ @@ -47,8 +63,8 @@ public class ArrayTrie extends AbstractTrie 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 extends AbstractTrie * 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 extends AbstractTrie 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 extends AbstractTrie } } } + + 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 extends AbstractTrie return null; } } - return (V)_value[t]; + return _value[t]; } /* ------------------------------------------------------------ */ @@ -374,7 +406,7 @@ public class ArrayTrie extends AbstractTrie } - private void toString(Appendable out, int t) + private void toString(Appendable out, int t) { if (_value[t]!=null) { @@ -440,6 +472,6 @@ public class ArrayTrie extends AbstractTrie @Override public boolean isFull() { - return _rows+1==_key.length; + return _rows+1>=_key.length; } } diff --git a/lib/jetty/org/eclipse/jetty/util/ArrayUtil.java b/lib/jetty/org/eclipse/jetty/util/ArrayUtil.java index 76b195da..f1d38690 100644 --- a/lib/jetty/org/eclipse/jetty/util/ArrayUtil.java +++ b/lib/jetty/org/eclipse/jetty/util/ArrayUtil.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/Atomics.java b/lib/jetty/org/eclipse/jetty/util/Atomics.java index 42fb4890..a3cdff06 100644 --- a/lib/jetty/org/eclipse/jetty/util/Atomics.java +++ b/lib/jetty/org/eclipse/jetty/util/Atomics.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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; } } diff --git a/lib/jetty/org/eclipse/jetty/util/Attributes.java b/lib/jetty/org/eclipse/jetty/util/Attributes.java index c65abc26..159b3611 100644 --- a/lib/jetty/org/eclipse/jetty/util/Attributes.java +++ b/lib/jetty/org/eclipse/jetty/util/Attributes.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/AttributesMap.java b/lib/jetty/org/eclipse/jetty/util/AttributesMap.java index c605e099..073051e5 100644 --- a/lib/jetty/org/eclipse/jetty/util/AttributesMap.java +++ b/lib/jetty/org/eclipse/jetty/util/AttributesMap.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/B64Code.java b/lib/jetty/org/eclipse/jetty/util/B64Code.java index 7fbbb187..48bc6d9e 100644 --- a/lib/jetty/org/eclipse/jetty/util/B64Code.java +++ b/lib/jetty/org/eclipse/jetty/util/B64Code.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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. diff --git a/lib/jetty/org/eclipse/jetty/util/BlockingArrayQueue.java b/lib/jetty/org/eclipse/jetty/util/BlockingArrayQueue.java index 7acbdafc..fa2e8dd8 100644 --- a/lib/jetty/org/eclipse/jetty/util/BlockingArrayQueue.java +++ b/lib/jetty/org/eclipse/jetty/util/BlockingArrayQueue.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/BlockingCallback.java b/lib/jetty/org/eclipse/jetty/util/BlockingCallback.java index a3cf9dae..8601d8e9 100644 --- a/lib/jetty/org/eclipse/jetty/util/BlockingCallback.java +++ b/lib/jetty/org/eclipse/jetty/util/BlockingCallback.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/BufferUtil.java b/lib/jetty/org/eclipse/jetty/util/BufferUtil.java index bd7cb06e..9964c3ab 100644 --- a/lib/jetty/org/eclipse/jetty/util/BufferUtil.java +++ b/lib/jetty/org/eclipse/jetty/util/BufferUtil.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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}; diff --git a/lib/jetty/org/eclipse/jetty/util/ByteArrayISO8859Writer.java b/lib/jetty/org/eclipse/jetty/util/ByteArrayISO8859Writer.java index 80df8819..d31f7e98 100644 --- a/lib/jetty/org/eclipse/jetty/util/ByteArrayISO8859Writer.java +++ b/lib/jetty/org/eclipse/jetty/util/ByteArrayISO8859Writer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/ByteArrayOutputStream2.java b/lib/jetty/org/eclipse/jetty/util/ByteArrayOutputStream2.java index bfde0186..56f47cd9 100644 --- a/lib/jetty/org/eclipse/jetty/util/ByteArrayOutputStream2.java +++ b/lib/jetty/org/eclipse/jetty/util/ByteArrayOutputStream2.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/Callback.java b/lib/jetty/org/eclipse/jetty/util/Callback.java index 973d9413..6425e293 100644 --- a/lib/jetty/org/eclipse/jetty/util/Callback.java +++ b/lib/jetty/org/eclipse/jetty/util/Callback.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -16,28 +16,12 @@ // ======================================================================== // -/* - * 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; /** *

A callback abstraction that handles completed/failed events of asynchronous operations.

* - *

Semantically this is equivalent to an optimise Promise<Void>, but callback is a more meaningful + *

Semantically this is equivalent to an optimise Promise<Void>, but callback is a more meaningful * name than EmptyPromise

*/ public interface Callback diff --git a/lib/jetty/org/eclipse/jetty/util/ClassLoadingObjectInputStream.java b/lib/jetty/org/eclipse/jetty/util/ClassLoadingObjectInputStream.java index 5b734db7..f16e18e6 100644 --- a/lib/jetty/org/eclipse/jetty/util/ClassLoadingObjectInputStream.java +++ b/lib/jetty/org/eclipse/jetty/util/ClassLoadingObjectInputStream.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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) diff --git a/lib/jetty/org/eclipse/jetty/util/CompletableCallback.java b/lib/jetty/org/eclipse/jetty/util/CompletableCallback.java index ec5a30a8..674afd53 100644 --- a/lib/jetty/org/eclipse/jetty/util/CompletableCallback.java +++ b/lib/jetty/org/eclipse/jetty/util/CompletableCallback.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 = 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 - * after 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 } } diff --git a/lib/jetty/org/eclipse/jetty/util/ConcurrentArrayQueue.java b/lib/jetty/org/eclipse/jetty/util/ConcurrentArrayQueue.java index fc1326d6..86a0b364 100644 --- a/lib/jetty/org/eclipse/jetty/util/ConcurrentArrayQueue.java +++ b/lib/jetty/org/eclipse/jetty/util/ConcurrentArrayQueue.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 extends AbstractQueue return _blocks.compareAndSet(TAIL_OFFSET,current,update); } + @SuppressWarnings("unchecked") @Override public T poll() { @@ -276,7 +275,7 @@ public class ConcurrentArrayQueue extends AbstractQueue } 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 extends AbstractQueue } else { - return (T)element; + return element; } } } @@ -421,8 +420,11 @@ public class ConcurrentArrayQueue extends AbstractQueue 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 extends AbstractQueue 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) diff --git a/lib/jetty/org/eclipse/jetty/util/ConcurrentHashSet.java b/lib/jetty/org/eclipse/jetty/util/ConcurrentHashSet.java index 4a4c8e62..1b0bc6f9 100644 --- a/lib/jetty/org/eclipse/jetty/util/ConcurrentHashSet.java +++ b/lib/jetty/org/eclipse/jetty/util/ConcurrentHashSet.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 index 00000000..5ca4720f --- /dev/null +++ b/lib/jetty/org/eclipse/jetty/util/CountingCallback.java @@ -0,0 +1,98 @@ +// +// ======================================================================== +// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.util; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + *

A callback wrapper that succeeds the wrapped callback when the count is + * reached, or on first failure.

+ *

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.

+ *

Example:

+ *
+ * public void process(EndPoint endPoint, ByteBuffer buffer, Callback callback)
+ * {
+ *     ByteBuffer[] buffers = split(buffer);
+ *     CountCallback countCallback = new CountCallback(callback, buffers.length);
+ *     endPoint.write(countCallback, buffers);
+ * }
+ * 
+ */ +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()); + } +} diff --git a/lib/jetty/org/eclipse/jetty/util/DateCache.java b/lib/jetty/org/eclipse/jetty/util/DateCache.java index 31097ee7..924e7457 100644 --- a/lib/jetty/org/eclipse/jetty/util/DateCache.java +++ b/lib/jetty/org/eclipse/jetty/util/DateCache.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/Fields.java b/lib/jetty/org/eclipse/jetty/util/Fields.java index 152934de..9e9965c7 100644 --- a/lib/jetty/org/eclipse/jetty/util/Fields.java +++ b/lib/jetty/org/eclipse/jetty/util/Fields.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 index c15b313b..00000000 --- a/lib/jetty/org/eclipse/jetty/util/ForkInvoker.java +++ /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)}. - *

- * This class prevents {@link StackOverflowError}s in case of methods that end up invoking themselves, - * such is common for {@link Callback#succeeded()}. - *

- * Typical use case is: - *

- * public void reentrantMethod(Object param)
- * {
- *     if (condition || tooManyReenters)
- *         fork(param)
- *     else
- *         call(param)
- * }
- * 
- * 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. - *

- * The same code using this class becomes: - *

- * private final ForkInvoker invoker = ...;
- *
- * public void reentrantMethod(Object param)
- * {
- *     invoker.invoke(param);
- * }
- * 
- * - */ -public abstract class ForkInvoker -{ - private static final ThreadLocal __invocations = new ThreadLocal() - { - @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)} - *

- * 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); -} diff --git a/lib/jetty/org/eclipse/jetty/util/FutureCallback.java b/lib/jetty/org/eclipse/jetty/util/FutureCallback.java index 5bad6b2e..247535cb 100644 --- a/lib/jetty/org/eclipse/jetty/util/FutureCallback.java +++ b/lib/jetty/org/eclipse/jetty/util/FutureCallback.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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,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); } } diff --git a/lib/jetty/org/eclipse/jetty/util/FuturePromise.java b/lib/jetty/org/eclipse/jetty/util/FuturePromise.java index f781c850..09a770b2 100644 --- a/lib/jetty/org/eclipse/jetty/util/FuturePromise.java +++ b/lib/jetty/org/eclipse/jetty/util/FuturePromise.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 implements Future,Promise @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); } } diff --git a/lib/jetty/org/eclipse/jetty/util/HostMap.java b/lib/jetty/org/eclipse/jetty/util/HostMap.java index 23e10bb6..af6dfd4a 100644 --- a/lib/jetty/org/eclipse/jetty/util/HostMap.java +++ b/lib/jetty/org/eclipse/jetty/util/HostMap.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/HttpCookieStore.java b/lib/jetty/org/eclipse/jetty/util/HttpCookieStore.java index 99aa742d..a1f3f04d 100644 --- a/lib/jetty/org/eclipse/jetty/util/HttpCookieStore.java +++ b/lib/jetty/org/eclipse/jetty/util/HttpCookieStore.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/IO.java b/lib/jetty/org/eclipse/jetty/util/IO.java index 51fbed94..6e7b4824 100644 --- a/lib/jetty/org/eclipse/jetty/util/IO.java +++ b/lib/jetty/org/eclipse/jetty/util/IO.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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. + *

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;iMaintains a set of included and excluded elements. The method {@link #matches(Object)} + * will return true IFF the passed object is not in the excluded set AND ( either the + * included set is empty OR the object is in the included set) + *

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

+ * @param The type of element + */ +public class IncludeExclude +{ + private final Set _includes; + private final Predicate _includePredicate; + private final Set _excludes; + private final Predicate _excludePredicate; + + private static class SetContainsPredicate implements Predicate + { + private final Set set; + + public SetContainsPredicate(Set set) + { + this.set = set; + } + + @Override + public boolean test(ITEM item) + { + return set.contains(item); + } + } + + /** + * Default constructor over {@link HashSet} + */ + 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 > IncludeExclude(Class setClass) + { + try + { + _includes = setClass.newInstance(); + _excludes = setClass.newInstance(); + + if(_includes instanceof Predicate) { + _includePredicate = (Predicate)_includes; + } else { + _includePredicate = new SetContainsPredicate<>(_includes); + } + + if(_excludes instanceof Predicate) { + _excludePredicate = (Predicate)_excludes; + } else { + _excludePredicate = new SetContainsPredicate<>(_excludes); + } + } + catch (InstantiationException | IllegalAccessException e) + { + throw new RuntimeException(e); + } + } + + /** + * Construct an IncludeExclude + * + * @param includeSet the Set of items that represent the included space + * @param includePredicate the Predicate for included item testing (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 > IncludeExclude(Set includeSet, Predicate includePredicate, Set excludeSet, Predicate 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 getIncluded() + { + return _includes; + } + + public Set getExcluded() + { + return _excludes; + } + + public void clear() + { + _includes.clear(); + _excludes.clear(); + } + + @Override + public String toString() + { + return String.format("%s@%x{i=%s,ip=%s,e=%s,ep=%s}",this.getClass().getSimpleName(),hashCode(),_includes,_includePredicate,_excludes,_excludePredicate); + } +} diff --git a/lib/jetty/org/eclipse/jetty/util/IntrospectionUtil.java b/lib/jetty/org/eclipse/jetty/util/IntrospectionUtil.java index 8588675c..5f724cac 100644 --- a/lib/jetty/org/eclipse/jetty/util/IntrospectionUtil.java +++ b/lib/jetty/org/eclipse/jetty/util/IntrospectionUtil.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/IteratingCallback.java b/lib/jetty/org/eclipse/jetty/util/IteratingCallback.java index 1c74d5ea..8d24dd9d 100644 --- a/lib/jetty/org/eclipse/jetty/util/IteratingCallback.java +++ b/lib/jetty/org/eclipse/jetty/util/IteratingCallback.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 = new AtomicReference<>(State.INACTIVE); - + private final AtomicReference _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. *

@@ -91,129 +150,197 @@ public abstract class IteratingCallback implements Callback *

  • {@link Action#SCHEDULED} when the sub task asynchronous execution * has been started
  • *
  • {@link Action#SUCCEEDED} when the overall job is completed
  • - *
  • {@link Action#FAILED} when the overall job cannot be completed
  • * * * @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. - *

    - * 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. + *

    + * 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 - } } diff --git a/lib/jetty/org/eclipse/jetty/util/IteratingNestedCallback.java b/lib/jetty/org/eclipse/jetty/util/IteratingNestedCallback.java index e018f43a..1cf154ca 100644 --- a/lib/jetty/org/eclipse/jetty/util/IteratingNestedCallback.java +++ b/lib/jetty/org/eclipse/jetty/util/IteratingNestedCallback.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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); } diff --git a/lib/jetty/org/eclipse/jetty/util/Jetty.java b/lib/jetty/org/eclipse/jetty/util/Jetty.java index 5a9b2570..864c6af3 100644 --- a/lib/jetty/org/eclipse/jetty/util/Jetty.java +++ b/lib/jetty/org/eclipse/jetty/util/Jetty.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/LazyList.java b/lib/jetty/org/eclipse/jetty/util/LazyList.java index 6ff416e6..3b259c70 100644 --- a/lib/jetty/org/eclipse/jetty/util/LazyList.java +++ b/lib/jetty/org/eclipse/jetty/util/LazyList.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/LeakDetector.java b/lib/jetty/org/eclipse/jetty/util/LeakDetector.java index b0ac94e9..11b3b31a 100644 --- a/lib/jetty/org/eclipse/jetty/util/LeakDetector.java +++ b/lib/jetty/org/eclipse/jetty/util/LeakDetector.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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. *

    - * 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. *

    - * 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). *

    - * 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. *

    * IMPLEMENTATION NOTES *

    - * 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. *

    - * {@link LeakDetector} uses {@link PhantomReference}s to detect leaks. - * {@link PhantomReference}s are enqueued in their {@link ReferenceQueue} - * after they have been garbage collected (differently from - * {@link WeakReference}s that are enqueued before). - * 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} after they have been garbage collected (differently from {@link WeakReference}s that + * are enqueued before). 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 the resource type. */ @@ -80,26 +69,43 @@ public class LeakDetector 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 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 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 extends AbstractLifeCycle implements Runnable @Override protected void doStop() throws Exception { - thread.interrupt(); super.doStop(); + thread.interrupt(); } @Override @@ -138,7 +144,8 @@ public class LeakDetector 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 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 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(); diff --git a/lib/jetty/org/eclipse/jetty/util/Loader.java b/lib/jetty/org/eclipse/jetty/util/Loader.java index dfb87fd7..c045070e 100644 --- a/lib/jetty/org/eclipse/jetty/util/Loader.java +++ b/lib/jetty/org/eclipse/jetty/util/Loader.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/MemoryUtils.java b/lib/jetty/org/eclipse/jetty/util/MemoryUtils.java index 764ad600..514af036 100644 --- a/lib/jetty/org/eclipse/jetty/util/MemoryUtils.java +++ b/lib/jetty/org/eclipse/jetty/util/MemoryUtils.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/MultiException.java b/lib/jetty/org/eclipse/jetty/util/MultiException.java index 2e71f3c5..7653ca66 100644 --- a/lib/jetty/org/eclipse/jetty/util/MultiException.java +++ b/lib/jetty/org/eclipse/jetty/util/MultiException.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 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); - } - } - } - } diff --git a/lib/jetty/org/eclipse/jetty/util/MultiMap.java b/lib/jetty/org/eclipse/jetty/util/MultiMap.java index a3c905a3..1a057c62 100644 --- a/lib/jetty/org/eclipse/jetty/util/MultiMap.java +++ b/lib/jetty/org/eclipse/jetty/util/MultiMap.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/MultiPartInputStreamParser.java b/lib/jetty/org/eclipse/jetty/util/MultiPartInputStreamParser.java index 441d648e..4fbc2a7f 100644 --- a/lib/jetty/org/eclipse/jetty/util/MultiPartInputStreamParser.java +++ b/lib/jetty/org/eclipse/jetty/util/MultiPartInputStreamParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 _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 _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 headers) { _headers = headers; } @@ -359,9 +351,9 @@ public class MultiPartInputStreamParser if (_parts == null) return Collections.emptyList(); - Collection values = _parts.values(); + Collection> values = _parts.values(); List parts = new ArrayList(); - for (Object o: values) + for (List o: values) { List asList = LazyList.getList(o, false); parts.addAll(asList); @@ -406,9 +398,9 @@ public class MultiPartInputStreamParser throws IOException, ServletException { parse(); - Collection values = _parts.values(); + Collection> values = _parts.values(); List parts = new ArrayList(); - for (Object o: values) + for (List o: values) { List 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(); //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 headers = new MultiMap(); while(true) { line=((ReadLineInputStream)_in).readLine(); diff --git a/lib/jetty/org/eclipse/jetty/util/MultiPartOutputStream.java b/lib/jetty/org/eclipse/jetty/util/MultiPartOutputStream.java index f554e767..c39ae59f 100644 --- a/lib/jetty/org/eclipse/jetty/util/MultiPartOutputStream.java +++ b/lib/jetty/org/eclipse/jetty/util/MultiPartOutputStream.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/MultiPartWriter.java b/lib/jetty/org/eclipse/jetty/util/MultiPartWriter.java index 00217125..78f8ed9d 100644 --- a/lib/jetty/org/eclipse/jetty/util/MultiPartWriter.java +++ b/lib/jetty/org/eclipse/jetty/util/MultiPartWriter.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/PatternMatcher.java b/lib/jetty/org/eclipse/jetty/util/PatternMatcher.java index 0afda65a..dd314c0b 100644 --- a/lib/jetty/org/eclipse/jetty/util/PatternMatcher.java +++ b/lib/jetty/org/eclipse/jetty/util/PatternMatcher.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 index 00000000..9d26fa02 --- /dev/null +++ b/lib/jetty/org/eclipse/jetty/util/Predicate.java @@ -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 java.util.function.Predicate + *

    + * To be removed for Java 8 only versions of Jetty. + * + * @param the item to test + */ +public interface Predicate +{ + boolean test(ITEM item); +} diff --git a/lib/jetty/org/eclipse/jetty/util/Promise.java b/lib/jetty/org/eclipse/jetty/util/Promise.java index 6727fc4e..3a6512d3 100644 --- a/lib/jetty/org/eclipse/jetty/util/Promise.java +++ b/lib/jetty/org/eclipse/jetty/util/Promise.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/QuotedStringTokenizer.java b/lib/jetty/org/eclipse/jetty/util/QuotedStringTokenizer.java index 3a4d5189..3ea1d8d5 100644 --- a/lib/jetty/org/eclipse/jetty/util/QuotedStringTokenizer.java +++ b/lib/jetty/org/eclipse/jetty/util/QuotedStringTokenizer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/ReadLineInputStream.java b/lib/jetty/org/eclipse/jetty/util/ReadLineInputStream.java index 067b2c14..4c507a96 100644 --- a/lib/jetty/org/eclipse/jetty/util/ReadLineInputStream.java +++ b/lib/jetty/org/eclipse/jetty/util/ReadLineInputStream.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 index 00000000..7aacf9ee --- /dev/null +++ b/lib/jetty/org/eclipse/jetty/util/RegexSet.java @@ -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. + *

    + * Provides the efficient {@link #matches(String)} method to check for a match against all the combined Regex's + */ +public class RegexSet extends AbstractSet implements Predicate +{ + private final Set _patterns=new HashSet(); + private final Set _unmodifiable=Collections.unmodifiableSet(_patterns); + private Pattern _pattern; + + @Override + public Iterator 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(); + } +} diff --git a/lib/jetty/org/eclipse/jetty/util/RolloverFileOutputStream.java b/lib/jetty/org/eclipse/jetty/util/RolloverFileOutputStream.java index 60f5da4b..f154f9f6 100644 --- a/lib/jetty/org/eclipse/jetty/util/RolloverFileOutputStream.java +++ b/lib/jetty/org/eclipse/jetty/util/RolloverFileOutputStream.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/Scanner.java b/lib/jetty/org/eclipse/jetty/util/Scanner.java index f29db3da..2aba5b39 100644 --- a/lib/jetty/org/eclipse/jetty/util/Scanner.java +++ b/lib/jetty/org/eclipse/jetty/util/Scanner.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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. diff --git a/lib/jetty/org/eclipse/jetty/util/SharedBlockingCallback.java b/lib/jetty/org/eclipse/jetty/util/SharedBlockingCallback.java index 3085a687..5b4e5a31 100644 --- a/lib/jetty/org/eclipse/jetty/util/SharedBlockingCallback.java +++ b/lib/jetty/org/eclipse/jetty/util/SharedBlockingCallback.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 + { + } } diff --git a/lib/jetty/org/eclipse/jetty/util/SocketAddressResolver.java b/lib/jetty/org/eclipse/jetty/util/SocketAddressResolver.java index e75abfc0..f6eff3f0 100644 --- a/lib/jetty/org/eclipse/jetty/util/SocketAddressResolver.java +++ b/lib/jetty/org/eclipse/jetty/util/SocketAddressResolver.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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. - *

    - * {@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. - *

    - * Example usage: - *

    - * SocketAddressResolver resolver = new SocketAddressResolver(executor, scheduler);
    - * resolver.resolve("www.google.com", 80, new Promise<SocketAddress>()
    - * {
    - *     public void succeeded(SocketAddress result)
    - *     {
    - *         // The address was resolved
    - *     }
    - *
    - *     public void failed(Throwable failure)
    - *     {
    - *         // The address resolution failed
    - *     }
    - * });
    - * 
    + *

    Creates {@link SocketAddress} instances, returning them through a {@link Promise}.

    */ -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 promise) + public void resolve(String host, int port, Promise promise); + + /** + *

    Creates {@link SocketAddress} instances synchronously in the caller thread.

    + */ + public static class Sync implements SocketAddressResolver { - resolve(host, port, timeout, promise); + @Override + public void resolve(String host, int port, Promise 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. + *

    Creates {@link SocketAddress} instances asynchronously in a different thread.

    + *

    {@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.

    + *

    Example usage:

    + *
    +     * SocketAddressResolver resolver = new SocketAddressResolver.Async(executor, scheduler, timeout);
    +     * resolver.resolve("www.google.com", 80, new Promise<SocketAddress>()
    +     * {
    +     *     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
    +     *     }
    +     * });
    +     * 
    */ - protected void resolve(final String host, final int port, final long timeout, final Promise 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 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(); - } - } - }); + }); + } } } diff --git a/lib/jetty/org/eclipse/jetty/util/StringUtil.java b/lib/jetty/org/eclipse/jetty/util/StringUtil.java index 55868ad5..9dbd9e49 100644 --- a/lib/jetty/org/eclipse/jetty/util/StringUtil.java +++ b/lib/jetty/org/eclipse/jetty/util/StringUtil.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 + *

    + * This will return a result on the first occurrence of a control character, regardless if + * there are more than one. + *

    + *

    + * Note: uses codepoint version of {@link Character#isISOControl(int)} to support Unicode better. + *

    + * + *
    +     *   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
    +     * 
    + * + * @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 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 + *

    Handle rfc4180-like + * CSV strings, with the exceptions:

      + *
    • quoted values may contain double quotes escaped with back-slash + *
    • Non-quoted values are trimmed of leading trailing white space + *
    • trailing commas are ignored + *
    • double commas result in a empty string value + *
    + * @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 csvSplit(List 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' : + 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' : + out.append(">"); + break; + case '\'': + out.append("'"); + break; + case '"': + out.append("""); + break; + + default: + if (Character.isISOControl(c) && !Character.isWhitespace(c)) + out.append('?'); + else + out.append(c); + } + } + return out.toString(); } } diff --git a/lib/jetty/org/eclipse/jetty/util/TreeTrie.java b/lib/jetty/org/eclipse/jetty/util/TreeTrie.java index 42f3bdcc..d791151e 100644 --- a/lib/jetty/org/eclipse/jetty/util/TreeTrie.java +++ b/lib/jetty/org/eclipse/jetty/util/TreeTrie.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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; *

    This implementation is always case insensitive and is optimal for * a variable number of fixed strings with few special characters. *

    + *

    This Trie is stored in a Tree and is unlimited in capacity

    + * + *

    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. + *

    + * * @param */ public class TreeTrie extends AbstractTrie @@ -38,8 +47,8 @@ public class TreeTrie extends AbstractTrie 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, diff --git a/lib/jetty/org/eclipse/jetty/util/Trie.java b/lib/jetty/org/eclipse/jetty/util/Trie.java index 9c749241..fd4459b9 100644 --- a/lib/jetty/org/eclipse/jetty/util/Trie.java +++ b/lib/jetty/org/eclipse/jetty/util/Trie.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/TypeUtil.java b/lib/jetty/org/eclipse/jetty/util/TypeUtil.java index b96a520c..b71e29e8 100644 --- a/lib/jetty/org/eclipse/jetty/util/TypeUtil.java +++ b/lib/jetty/org/eclipse/jetty/util/TypeUtil.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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); } } } diff --git a/lib/jetty/org/eclipse/jetty/util/URIUtil.java b/lib/jetty/org/eclipse/jetty/util/URIUtil.java index f333fc3b..193a1180 100644 --- a/lib/jetty/org/eclipse/jetty/util/URIUtil.java +++ b/lib/jetty/org/eclipse/jetty/util/URIUtil.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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

    + * @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

    + * @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 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(); + } +} diff --git a/lib/jetty/org/eclipse/jetty/util/UrlEncoded.java b/lib/jetty/org/eclipse/jetty/util/UrlEncoded.java index ef7f2f5f..a893fc9b 100644 --- a/lib/jetty/org/eclipse/jetty/util/UrlEncoded.java +++ b/lib/jetty/org/eclipse/jetty/util/UrlEncoded.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 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),""); } } diff --git a/lib/jetty/org/eclipse/jetty/util/Utf8Appendable.java b/lib/jetty/org/eclipse/jetty/util/Utf8Appendable.java index ff58764a..d7136986 100644 --- a/lib/jetty/org/eclipse/jetty/util/Utf8Appendable.java +++ b/lib/jetty/org/eclipse/jetty/util/Utf8Appendable.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/Utf8LineParser.java b/lib/jetty/org/eclipse/jetty/util/Utf8LineParser.java index b54cf419..0332d989 100644 --- a/lib/jetty/org/eclipse/jetty/util/Utf8LineParser.java +++ b/lib/jetty/org/eclipse/jetty/util/Utf8LineParser.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 "\n" as a line termination character. *

    diff --git a/lib/jetty/org/eclipse/jetty/util/Utf8StringBuffer.java b/lib/jetty/org/eclipse/jetty/util/Utf8StringBuffer.java index 63fb1aca..4f6a0c50 100644 --- a/lib/jetty/org/eclipse/jetty/util/Utf8StringBuffer.java +++ b/lib/jetty/org/eclipse/jetty/util/Utf8StringBuffer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/Utf8StringBuilder.java b/lib/jetty/org/eclipse/jetty/util/Utf8StringBuilder.java index 28fa20b6..de691788 100644 --- a/lib/jetty/org/eclipse/jetty/util/Utf8StringBuilder.java +++ b/lib/jetty/org/eclipse/jetty/util/Utf8StringBuilder.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/annotation/ManagedAttribute.java b/lib/jetty/org/eclipse/jetty/util/annotation/ManagedAttribute.java index 29a805fe..a113c30f 100644 --- a/lib/jetty/org/eclipse/jetty/util/annotation/ManagedAttribute.java +++ b/lib/jetty/org/eclipse/jetty/util/annotation/ManagedAttribute.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/annotation/ManagedObject.java b/lib/jetty/org/eclipse/jetty/util/annotation/ManagedObject.java index 15f4b550..e2e7d1de 100644 --- a/lib/jetty/org/eclipse/jetty/util/annotation/ManagedObject.java +++ b/lib/jetty/org/eclipse/jetty/util/annotation/ManagedObject.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/annotation/ManagedOperation.java b/lib/jetty/org/eclipse/jetty/util/annotation/ManagedOperation.java index 3a29368f..1dd9791c 100644 --- a/lib/jetty/org/eclipse/jetty/util/annotation/ManagedOperation.java +++ b/lib/jetty/org/eclipse/jetty/util/annotation/ManagedOperation.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/annotation/Name.java b/lib/jetty/org/eclipse/jetty/util/annotation/Name.java index b79e76e9..c6905996 100644 --- a/lib/jetty/org/eclipse/jetty/util/annotation/Name.java +++ b/lib/jetty/org/eclipse/jetty/util/annotation/Name.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/annotation/package-info.java b/lib/jetty/org/eclipse/jetty/util/annotation/package-info.java index 5f0038b2..c91a83a1 100644 --- a/lib/jetty/org/eclipse/jetty/util/annotation/package-info.java +++ b/lib/jetty/org/eclipse/jetty/util/annotation/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/component/AbstractLifeCycle.java b/lib/jetty/org/eclipse/jetty/util/component/AbstractLifeCycle.java index 8f2d9dc7..4aef3418 100644 --- a/lib/jetty/org/eclipse/jetty/util/component/AbstractLifeCycle.java +++ b/lib/jetty/org/eclipse/jetty/util/component/AbstractLifeCycle.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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); } diff --git a/lib/jetty/org/eclipse/jetty/util/component/Container.java b/lib/jetty/org/eclipse/jetty/util/component/Container.java index a5a4c758..87880043 100644 --- a/lib/jetty/org/eclipse/jetty/util/component/Container.java +++ b/lib/jetty/org/eclipse/jetty/util/component/Container.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/component/ContainerLifeCycle.java b/lib/jetty/org/eclipse/jetty/util/component/ContainerLifeCycle.java index 464c0f7e..4756bc12 100644 --- a/lib/jetty/org/eclipse/jetty/util/component/ContainerLifeCycle.java +++ b/lib/jetty/org/eclipse/jetty/util/component/ContainerLifeCycle.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 { diff --git a/lib/jetty/org/eclipse/jetty/util/component/Destroyable.java b/lib/jetty/org/eclipse/jetty/util/component/Destroyable.java index 2e7e441c..8a7730f2 100644 --- a/lib/jetty/org/eclipse/jetty/util/component/Destroyable.java +++ b/lib/jetty/org/eclipse/jetty/util/component/Destroyable.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/component/Dumpable.java b/lib/jetty/org/eclipse/jetty/util/component/Dumpable.java index 2a1882bc..6ac3d20d 100644 --- a/lib/jetty/org/eclipse/jetty/util/component/Dumpable.java +++ b/lib/jetty/org/eclipse/jetty/util/component/Dumpable.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/component/FileDestroyable.java b/lib/jetty/org/eclipse/jetty/util/component/FileDestroyable.java index 94936452..dd1a8c5a 100644 --- a/lib/jetty/org/eclipse/jetty/util/component/FileDestroyable.java +++ b/lib/jetty/org/eclipse/jetty/util/component/FileDestroyable.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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); } } diff --git a/lib/jetty/org/eclipse/jetty/util/component/FileNoticeLifeCycleListener.java b/lib/jetty/org/eclipse/jetty/util/component/FileNoticeLifeCycleListener.java index 1c4dcecd..4233b79b 100644 --- a/lib/jetty/org/eclipse/jetty/util/component/FileNoticeLifeCycleListener.java +++ b/lib/jetty/org/eclipse/jetty/util/component/FileNoticeLifeCycleListener.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/component/Graceful.java b/lib/jetty/org/eclipse/jetty/util/component/Graceful.java index 96bec336..02530922 100644 --- a/lib/jetty/org/eclipse/jetty/util/component/Graceful.java +++ b/lib/jetty/org/eclipse/jetty/util/component/Graceful.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/component/LifeCycle.java b/lib/jetty/org/eclipse/jetty/util/component/LifeCycle.java index f58fd1a5..b064d542 100644 --- a/lib/jetty/org/eclipse/jetty/util/component/LifeCycle.java +++ b/lib/jetty/org/eclipse/jetty/util/component/LifeCycle.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/component/package-info.java b/lib/jetty/org/eclipse/jetty/util/component/package-info.java index 2ae3d198..42b27e13 100644 --- a/lib/jetty/org/eclipse/jetty/util/component/package-info.java +++ b/lib/jetty/org/eclipse/jetty/util/component/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/log/AbstractLogger.java b/lib/jetty/org/eclipse/jetty/util/log/AbstractLogger.java index 66453768..e061ae7b 100644 --- a/lib/jetty/org/eclipse/jetty/util/log/AbstractLogger.java +++ b/lib/jetty/org/eclipse/jetty/util/log/AbstractLogger.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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) }); + } } } diff --git a/lib/jetty/org/eclipse/jetty/util/log/JavaUtilLog.java b/lib/jetty/org/eclipse/jetty/util/log/JavaUtilLog.java index 094d9783..70498e41 100644 --- a/lib/jetty/org/eclipse/jetty/util/log/JavaUtilLog.java +++ b/lib/jetty/org/eclipse/jetty/util/log/JavaUtilLog.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/log/Log.java b/lib/jetty/org/eclipse/jetty/util/log/Log.java index 91b61f9a..b33b5f2b 100644 --- a/lib/jetty/org/eclipse/jetty/util/log/Log.java +++ b/lib/jetty/org/eclipse/jetty/util/log/Log.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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())); } } diff --git a/lib/jetty/org/eclipse/jetty/util/log/Logger.java b/lib/jetty/org/eclipse/jetty/util/log/Logger.java index ac6e0861..e02acc4a 100644 --- a/lib/jetty/org/eclipse/jetty/util/log/Logger.java +++ b/lib/jetty/org/eclipse/jetty/util/log/Logger.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/log/LoggerLog.java b/lib/jetty/org/eclipse/jetty/util/log/LoggerLog.java index 1026cb07..d4a7d41d 100644 --- a/lib/jetty/org/eclipse/jetty/util/log/LoggerLog.java +++ b/lib/jetty/org/eclipse/jetty/util/log/LoggerLog.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/log/StacklessLogging.java b/lib/jetty/org/eclipse/jetty/util/log/StacklessLogging.java index fd6fb327..0b5de612 100644 --- a/lib/jetty/org/eclipse/jetty/util/log/StacklessLogging.java +++ b/lib/jetty/org/eclipse/jetty/util/log/StacklessLogging.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/log/StdErrLog.java b/lib/jetty/org/eclipse/jetty/util/log/StdErrLog.java index fda1c722..b8bf5aa8 100644 --- a/lib/jetty/org/eclipse/jetty/util/log/StdErrLog.java +++ b/lib/jetty/org/eclipse/jetty/util/log/StdErrLog.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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); } } } diff --git a/lib/jetty/org/eclipse/jetty/util/log/package-info.java b/lib/jetty/org/eclipse/jetty/util/log/package-info.java index 27166b69..5a791eae 100644 --- a/lib/jetty/org/eclipse/jetty/util/log/package-info.java +++ b/lib/jetty/org/eclipse/jetty/util/log/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/package-info.java b/lib/jetty/org/eclipse/jetty/util/package-info.java index 6545cbee..df73857a 100644 --- a/lib/jetty/org/eclipse/jetty/util/package-info.java +++ b/lib/jetty/org/eclipse/jetty/util/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/preventers/AWTLeakPreventer.java b/lib/jetty/org/eclipse/jetty/util/preventers/AWTLeakPreventer.java index 0f6caf9b..0c4439f4 100644 --- a/lib/jetty/org/eclipse/jetty/util/preventers/AWTLeakPreventer.java +++ b/lib/jetty/org/eclipse/jetty/util/preventers/AWTLeakPreventer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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(); } diff --git a/lib/jetty/org/eclipse/jetty/util/preventers/AbstractLeakPreventer.java b/lib/jetty/org/eclipse/jetty/util/preventers/AbstractLeakPreventer.java index 2322a762..48b449ae 100644 --- a/lib/jetty/org/eclipse/jetty/util/preventers/AbstractLeakPreventer.java +++ b/lib/jetty/org/eclipse/jetty/util/preventers/AbstractLeakPreventer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/preventers/AppContextLeakPreventer.java b/lib/jetty/org/eclipse/jetty/util/preventers/AppContextLeakPreventer.java index 0cfd3c95..abadd654 100644 --- a/lib/jetty/org/eclipse/jetty/util/preventers/AppContextLeakPreventer.java +++ b/lib/jetty/org/eclipse/jetty/util/preventers/AppContextLeakPreventer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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(); } diff --git a/lib/jetty/org/eclipse/jetty/util/preventers/DOMLeakPreventer.java b/lib/jetty/org/eclipse/jetty/util/preventers/DOMLeakPreventer.java index 5fee3659..cc0846ca 100644 --- a/lib/jetty/org/eclipse/jetty/util/preventers/DOMLeakPreventer.java +++ b/lib/jetty/org/eclipse/jetty/util/preventers/DOMLeakPreventer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/preventers/DriverManagerLeakPreventer.java b/lib/jetty/org/eclipse/jetty/util/preventers/DriverManagerLeakPreventer.java index d229ba74..b919af32 100644 --- a/lib/jetty/org/eclipse/jetty/util/preventers/DriverManagerLeakPreventer.java +++ b/lib/jetty/org/eclipse/jetty/util/preventers/DriverManagerLeakPreventer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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(); } diff --git a/lib/jetty/org/eclipse/jetty/util/preventers/GCThreadLeakPreventer.java b/lib/jetty/org/eclipse/jetty/util/preventers/GCThreadLeakPreventer.java index 6ea4de2e..037fa57e 100644 --- a/lib/jetty/org/eclipse/jetty/util/preventers/GCThreadLeakPreventer.java +++ b/lib/jetty/org/eclipse/jetty/util/preventers/GCThreadLeakPreventer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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)); } diff --git a/lib/jetty/org/eclipse/jetty/util/preventers/Java2DLeakPreventer.java b/lib/jetty/org/eclipse/jetty/util/preventers/Java2DLeakPreventer.java index 3a2ad823..9219889c 100644 --- a/lib/jetty/org/eclipse/jetty/util/preventers/Java2DLeakPreventer.java +++ b/lib/jetty/org/eclipse/jetty/util/preventers/Java2DLeakPreventer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/preventers/LDAPLeakPreventer.java b/lib/jetty/org/eclipse/jetty/util/preventers/LDAPLeakPreventer.java index 5c497d1c..966a45d9 100644 --- a/lib/jetty/org/eclipse/jetty/util/preventers/LDAPLeakPreventer.java +++ b/lib/jetty/org/eclipse/jetty/util/preventers/LDAPLeakPreventer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/preventers/LoginConfigurationLeakPreventer.java b/lib/jetty/org/eclipse/jetty/util/preventers/LoginConfigurationLeakPreventer.java index c1d9fe28..cb7a2a23 100644 --- a/lib/jetty/org/eclipse/jetty/util/preventers/LoginConfigurationLeakPreventer.java +++ b/lib/jetty/org/eclipse/jetty/util/preventers/LoginConfigurationLeakPreventer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/preventers/SecurityProviderLeakPreventer.java b/lib/jetty/org/eclipse/jetty/util/preventers/SecurityProviderLeakPreventer.java index 9976c560..a9487679 100644 --- a/lib/jetty/org/eclipse/jetty/util/preventers/SecurityProviderLeakPreventer.java +++ b/lib/jetty/org/eclipse/jetty/util/preventers/SecurityProviderLeakPreventer.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/preventers/package-info.java b/lib/jetty/org/eclipse/jetty/util/preventers/package-info.java index a6800e8a..10180214 100644 --- a/lib/jetty/org/eclipse/jetty/util/preventers/package-info.java +++ b/lib/jetty/org/eclipse/jetty/util/preventers/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/resource/BadResource.java b/lib/jetty/org/eclipse/jetty/util/resource/BadResource.java index 72a9ed4c..764aa307 100644 --- a/lib/jetty/org/eclipse/jetty/util/resource/BadResource.java +++ b/lib/jetty/org/eclipse/jetty/util/resource/BadResource.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/resource/EmptyResource.java b/lib/jetty/org/eclipse/jetty/util/resource/EmptyResource.java index 3dad17b3..e381432d 100644 --- a/lib/jetty/org/eclipse/jetty/util/resource/EmptyResource.java +++ b/lib/jetty/org/eclipse/jetty/util/resource/EmptyResource.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/resource/FileResource.java b/lib/jetty/org/eclipse/jetty/util/resource/FileResource.java index 44988424..dbc4670a 100644 --- a/lib/jetty/org/eclipse/jetty/util/resource/FileResource.java +++ b/lib/jetty/org/eclipse/jetty/util/resource/FileResource.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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() diff --git a/lib/jetty/org/eclipse/jetty/util/resource/JarFileResource.java b/lib/jetty/org/eclipse/jetty/util/resource/JarFileResource.java index 434aa887..ccb15ae0 100644 --- a/lib/jetty/org/eclipse/jetty/util/resource/JarFileResource.java +++ b/lib/jetty/org/eclipse/jetty/util/resource/JarFileResource.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 e=jarFile.entries(); + Enumeration 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); diff --git a/lib/jetty/org/eclipse/jetty/util/resource/JarResource.java b/lib/jetty/org/eclipse/jetty/util/resource/JarResource.java index 3dbb70a9..47eb1086 100644 --- a/lib/jetty/org/eclipse/jetty/util/resource/JarResource.java +++ b/lib/jetty/org/eclipse/jetty/util/resource/JarResource.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 index 00000000..8e773676 --- /dev/null +++ b/lib/jetty/org/eclipse/jetty/util/resource/PathResource.java @@ -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 dir = Files.newDirectoryStream(path)) + { + List 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 }; + } + } +} diff --git a/lib/jetty/org/eclipse/jetty/util/resource/Resource.java b/lib/jetty/org/eclipse/jetty/util/resource/Resource.java index b36a9355..7c9c8ecd 100644 --- a/lib/jetty/org/eclipse/jetty/util/resource/Resource.java +++ b/lib/jetty/org/eclipse/jetty/util/resource/Resource.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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(""); } buf.append("\n"); - buf.append("\n"); + buf.append("\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,"<","<"), ">", ">"); + return StringUtil.sanitizeXmlString(raw); } /* ------------------------------------------------------------ */ diff --git a/lib/jetty/org/eclipse/jetty/util/resource/ResourceCollection.java b/lib/jetty/org/eclipse/jetty/util/resource/ResourceCollection.java index 8135e0ba..178b156e 100644 --- a/lib/jetty/org/eclipse/jetty/util/resource/ResourceCollection.java +++ b/lib/jetty/org/eclipse/jetty/util/resource/ResourceCollection.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/resource/ResourceFactory.java b/lib/jetty/org/eclipse/jetty/util/resource/ResourceFactory.java index 707a6724..5219ae2b 100644 --- a/lib/jetty/org/eclipse/jetty/util/resource/ResourceFactory.java +++ b/lib/jetty/org/eclipse/jetty/util/resource/ResourceFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/resource/URLResource.java b/lib/jetty/org/eclipse/jetty/util/resource/URLResource.java index b696817e..5bba2c47 100644 --- a/lib/jetty/org/eclipse/jetty/util/resource/URLResource.java +++ b/lib/jetty/org/eclipse/jetty/util/resource/URLResource.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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); } /* ------------------------------------------------------------ */ diff --git a/lib/jetty/org/eclipse/jetty/util/resource/package-info.java b/lib/jetty/org/eclipse/jetty/util/resource/package-info.java index f8d2428a..03f46822 100644 --- a/lib/jetty/org/eclipse/jetty/util/resource/package-info.java +++ b/lib/jetty/org/eclipse/jetty/util/resource/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/security/CertificateUtils.java b/lib/jetty/org/eclipse/jetty/util/security/CertificateUtils.java index 4ed9ae21..86a4f9e3 100644 --- a/lib/jetty/org/eclipse/jetty/util/security/CertificateUtils.java +++ b/lib/jetty/org/eclipse/jetty/util/security/CertificateUtils.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/security/CertificateValidator.java b/lib/jetty/org/eclipse/jetty/util/security/CertificateValidator.java index 2ead3878..0093b204 100644 --- a/lib/jetty/org/eclipse/jetty/util/security/CertificateValidator.java +++ b/lib/jetty/org/eclipse/jetty/util/security/CertificateValidator.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/security/Constraint.java b/lib/jetty/org/eclipse/jetty/util/security/Constraint.java index 28c003b8..daf34333 100644 --- a/lib/jetty/org/eclipse/jetty/util/security/Constraint.java +++ b/lib/jetty/org/eclipse/jetty/util/security/Constraint.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/security/Credential.java b/lib/jetty/org/eclipse/jetty/util/security/Credential.java index 1feb6047..660116f5 100644 --- a/lib/jetty/org/eclipse/jetty/util/security/Credential.java +++ b/lib/jetty/org/eclipse/jetty/util/security/Credential.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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) { diff --git a/lib/jetty/org/eclipse/jetty/util/security/Password.java b/lib/jetty/org/eclipse/jetty/util/security/Password.java index 13160c1d..0b5fe909 100644 --- a/lib/jetty/org/eclipse/jetty/util/security/Password.java +++ b/lib/jetty/org/eclipse/jetty/util/security/Password.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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: - * + * *

      *  + 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.
      * 
    - * + * * 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 *
  • Prompting for a password *
  • Using promptDft if nothing was entered. * - * + * * @param realm The realm name for the password, used as a SystemProperty * name. * @param dft The default password. diff --git a/lib/jetty/org/eclipse/jetty/util/security/package-info.java b/lib/jetty/org/eclipse/jetty/util/security/package-info.java index a9271a5d..a83a0e17 100644 --- a/lib/jetty/org/eclipse/jetty/util/security/package-info.java +++ b/lib/jetty/org/eclipse/jetty/util/security/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/ssl/AliasedX509ExtendedKeyManager.java b/lib/jetty/org/eclipse/jetty/util/ssl/AliasedX509ExtendedKeyManager.java index b97aa344..53c7ca04 100644 --- a/lib/jetty/org/eclipse/jetty/util/ssl/AliasedX509ExtendedKeyManager.java +++ b/lib/jetty/org/eclipse/jetty/util/ssl/AliasedX509ExtendedKeyManager.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/ssl/AliasedX509KeyManager.java b/lib/jetty/org/eclipse/jetty/util/ssl/AliasedX509KeyManager.java index 29d33bb4..8da8f682 100644 --- a/lib/jetty/org/eclipse/jetty/util/ssl/AliasedX509KeyManager.java +++ b/lib/jetty/org/eclipse/jetty/util/ssl/AliasedX509KeyManager.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/ssl/SslContextFactory.java b/lib/jetty/org/eclipse/jetty/util/ssl/SslContextFactory.java index 016c8127..edf37897 100644 --- a/lib/jetty/org/eclipse/jetty/util/ssl/SslContextFactory.java +++ b/lib/jetty/org/eclipse/jetty/util/ssl/SslContextFactory.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 _excludeProtocols = new LinkedHashSet<>(); /** Included protocols. */ - private Set _includeProtocols = null; + private final Set _includeProtocols = new LinkedHashSet<>(); /** Excluded cipher suites. */ private final Set _excludeCipherSuites = new LinkedHashSet<>(); + /** Included cipher suites. */ - private Set _includeCipherSuites = null; + private final Set _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 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 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 selected_ciphers) + protected void processIncludeCipherSuites(String[] supportedCipherSuites, Set selected_ciphers) { for (String cipherSuite : _includeCipherSuites) { @@ -1088,7 +1095,7 @@ public class SslContextFactory extends AbstractLifeCycle } } - private void removeExcludedCipherSuites(Set selected_ciphers) + protected void removeExcludedCipherSuites(Set selected_ciphers) { for (String excludeCipherSuite : _excludeCipherSuites) { diff --git a/lib/jetty/org/eclipse/jetty/util/ssl/package-info.java b/lib/jetty/org/eclipse/jetty/util/ssl/package-info.java index 26ffa876..9270550e 100644 --- a/lib/jetty/org/eclipse/jetty/util/ssl/package-info.java +++ b/lib/jetty/org/eclipse/jetty/util/ssl/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/statistic/CounterStatistic.java b/lib/jetty/org/eclipse/jetty/util/statistic/CounterStatistic.java index 027dfe36..a57f0453 100644 --- a/lib/jetty/org/eclipse/jetty/util/statistic/CounterStatistic.java +++ b/lib/jetty/org/eclipse/jetty/util/statistic/CounterStatistic.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/statistic/SampleStatistic.java b/lib/jetty/org/eclipse/jetty/util/statistic/SampleStatistic.java index eae7d470..718be6e7 100644 --- a/lib/jetty/org/eclipse/jetty/util/statistic/SampleStatistic.java +++ b/lib/jetty/org/eclipse/jetty/util/statistic/SampleStatistic.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/statistic/package-info.java b/lib/jetty/org/eclipse/jetty/util/statistic/package-info.java index fac39e4e..7617b724 100644 --- a/lib/jetty/org/eclipse/jetty/util/statistic/package-info.java +++ b/lib/jetty/org/eclipse/jetty/util/statistic/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/thread/ExecutorThreadPool.java b/lib/jetty/org/eclipse/jetty/util/thread/ExecutorThreadPool.java index 4f6b5fe6..899babef 100644 --- a/lib/jetty/org/eclipse/jetty/util/thread/ExecutorThreadPool.java +++ b/lib/jetty/org/eclipse/jetty/util/thread/ExecutorThreadPool.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/thread/NonBlockingThread.java b/lib/jetty/org/eclipse/jetty/util/thread/NonBlockingThread.java index 4fb75c7f..db0545ff 100644 --- a/lib/jetty/org/eclipse/jetty/util/thread/NonBlockingThread.java +++ b/lib/jetty/org/eclipse/jetty/util/thread/NonBlockingThread.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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); } } } diff --git a/lib/jetty/org/eclipse/jetty/util/thread/QueuedThreadPool.java b/lib/jetty/org/eclipse/jetty/util/thread/QueuedThreadPool.java index 5cc75121..bb986b6f 100644 --- a/lib/jetty/org/eclipse/jetty/util/thread/QueuedThreadPool.java +++ b/lib/jetty/org/eclipse/jetty/util/thread/QueuedThreadPool.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 _threads = new ConcurrentLinkedQueue<>(); + private final ConcurrentHashSet _threads=new ConcurrentHashSet(); private final Object _joinLock = new Object(); private final BlockingQueue _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() 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 frames = Arrays.asList(thread.getStackTrace()); + ContainerLifeCycle.dump(out, indent, frames); + } + } + private class ScheduledFutureTask implements Task { private final ScheduledFuture scheduledFuture; diff --git a/lib/jetty/org/eclipse/jetty/util/thread/Scheduler.java b/lib/jetty/org/eclipse/jetty/util/thread/Scheduler.java index f5191846..c863914c 100644 --- a/lib/jetty/org/eclipse/jetty/util/thread/Scheduler.java +++ b/lib/jetty/org/eclipse/jetty/util/thread/Scheduler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/thread/ShutdownThread.java b/lib/jetty/org/eclipse/jetty/util/thread/ShutdownThread.java index 168b444c..db6ccf8e 100644 --- a/lib/jetty/org/eclipse/jetty/util/thread/ShutdownThread.java +++ b/lib/jetty/org/eclipse/jetty/util/thread/ShutdownThread.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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 index 00000000..fa199cc5 --- /dev/null +++ b/lib/jetty/org/eclipse/jetty/util/thread/SpinLock.java @@ -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; + +/** + *

    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.

    + *
    + * try(SpinLock.Lock lock = spinlock.lock())
    + * {
    + *   // something very quick and non blocking
    + * }
    + * 
    + *

    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.

    + * @deprecated Do not use it anymore, prefer normal locks + */ +@Deprecated +public class SpinLock +{ + private final AtomicReference _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 index 00000000..0ea8800e --- /dev/null +++ b/lib/jetty/org/eclipse/jetty/util/thread/Sweeper.java @@ -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; + +/** + *

    A utility class to perform periodic sweeping of resources.

    + *

    {@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.

    + *

    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.

    + *

    Typical usage is to add {@link Sweeper} as a bean to an existing + * container:

    + *
    + * Server server = new Server();
    + * server.addBean(new Sweeper(), true);
    + * server.start();
    + * 
    + * Code that knows it has sweepable resources can then lookup the + * {@link Sweeper} and offer the sweepable resources to it: + *
    + * 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;
    + *     }
    + *
    + *     @Override
    + *     public boolean sweep()
    + *     {
    + *         return destroyed;
    + *     }
    + * }
    + * 
    + */ +public class Sweeper extends AbstractLifeCycle implements Runnable +{ + private static final Logger LOG = Log.getLogger(Sweeper.class); + + private final AtomicReference> items = new AtomicReference<>(); + private final AtomicReference 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()); + activate(); + } + + @Override + protected void doStop() throws Exception + { + deactivate(); + items.set(null); + super.doStop(); + } + + public int getSize() + { + List refs = items.get(); + return refs == null ? 0 : refs.size(); + } + + public boolean offer(Sweepable sweepable) + { + List 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 refs = items.get(); + return refs != null && refs.remove(sweepable); + } + + @Override + public void run() + { + List 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); + } + } + + /** + *

    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.

    + *

    Typical implementations will check their own internal state + * and return true or false from {@link #sweep()} to indicate + * whether they should be swept.

    + */ + public interface Sweepable + { + /** + * @return whether this resource should be swept + */ + public boolean sweep(); + } +} diff --git a/lib/jetty/org/eclipse/jetty/util/thread/ThreadPool.java b/lib/jetty/org/eclipse/jetty/util/thread/ThreadPool.java index c2abcfc8..84b8390d 100644 --- a/lib/jetty/org/eclipse/jetty/util/thread/ThreadPool.java +++ b/lib/jetty/org/eclipse/jetty/util/thread/ThreadPool.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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. diff --git a/lib/jetty/org/eclipse/jetty/util/thread/TimerScheduler.java b/lib/jetty/org/eclipse/jetty/util/thread/TimerScheduler.java index c07390a7..c46394af 100644 --- a/lib/jetty/org/eclipse/jetty/util/thread/TimerScheduler.java +++ b/lib/jetty/org/eclipse/jetty/util/thread/TimerScheduler.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting 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/thread/package-info.java b/lib/jetty/org/eclipse/jetty/util/thread/package-info.java index 2637e49e..ec02bd64 100644 --- a/lib/jetty/org/eclipse/jetty/util/thread/package-info.java +++ b/lib/jetty/org/eclipse/jetty/util/thread/package-info.java @@ -1,6 +1,6 @@ // // ======================================================================== -// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 -- 2.39.2