Importing upstream Jetty jetty-9.2.1.v20140609
authorFelix Dörre <felix@dogcraft.de>
Thu, 19 Jun 2014 17:22:50 +0000 (19:22 +0200)
committerBenny Baumann <BenBE@geshi.org>
Fri, 20 Jun 2014 22:00:46 +0000 (00:00 +0200)
Imported packages:
* http
* io
* security
* server
* servlet
* util

Removed for compilance:
* Packages:
  - org.eclipse.jetty.server.session.jmx
  - org.eclipse.jetty.server.handler.jmx
  - org.eclipse.jetty.server.jmx
  - org.eclipse.jetty.servlet.jmx

* Classes:
  - org.eclipse.jetty.util.log.JettyAwareLogger
  - org.eclipse.jetty.util.log.Slf4jLog
  - org.eclipse.jetty.server.Slf4jRequestLog

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

index 342147deed9492586ed3c076b286d2fe31402d94..0fba86b0775db39f7ce4a9047b50948e78c78c21 100644 (file)
@@ -2,6 +2,7 @@
 <classpath>
        <classpathentry kind="src" path="src"/>
        <classpathentry kind="src" path="lib/servlet-api"/>
+       <classpathentry kind="src" path="lib/jetty"/>
        <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
        <classpathentry kind="output" path="bin"/>
 </classpath>
diff --git a/lib/jetty/org/eclipse/jetty/http/DateGenerator.java b/lib/jetty/org/eclipse/jetty/http/DateGenerator.java
new file mode 100644 (file)
index 0000000..3ecaad8
--- /dev/null
@@ -0,0 +1,164 @@
+//
+//  ========================================================================
+//  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.http;
+
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+
+import org.eclipse.jetty.util.StringUtil;
+
+/**
+ * ThreadLocal Date formatters for HTTP style dates.
+ *
+ */
+public class DateGenerator
+{
+    private static final TimeZone __GMT = TimeZone.getTimeZone("GMT");
+    static
+    {
+        __GMT.setID("GMT");
+    }
+    
+    static final String[] DAYS =
+        { "Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
+    static final String[] MONTHS =
+        { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Jan"};
+
+
+    private static final ThreadLocal<DateGenerator> __dateGenerator =new ThreadLocal<DateGenerator>()
+    {
+        @Override
+        protected DateGenerator initialValue()
+        {
+            return new DateGenerator();
+        }
+    };
+
+
+    public final static String __01Jan1970=DateGenerator.formatDate(0);
+    
+    /**
+     * Format HTTP date "EEE, dd MMM yyyy HH:mm:ss 'GMT'"
+     */
+    public static String formatDate(long date)
+    {
+        return __dateGenerator.get().doFormatDate(date);
+    }
+
+    /**
+     * Format "EEE, dd-MMM-yyyy HH:mm:ss 'GMT'" for cookies
+     */
+    public static void formatCookieDate(StringBuilder buf, long date)
+    {
+        __dateGenerator.get().doFormatCookieDate(buf,date);
+    }
+
+    /**
+     * Format "EEE, dd-MMM-yyyy HH:mm:ss 'GMT'" for cookies
+     */
+    public static String formatCookieDate(long date)
+    {
+        StringBuilder buf = new StringBuilder(28);
+        formatCookieDate(buf, date);
+        return buf.toString();
+    }
+    
+    private final StringBuilder buf = new StringBuilder(32);
+    private final GregorianCalendar gc = new GregorianCalendar(__GMT);
+
+    /**
+     * Format HTTP date "EEE, dd MMM yyyy HH:mm:ss 'GMT'"
+     */
+    public String doFormatDate(long date)
+    {
+        buf.setLength(0);
+        gc.setTimeInMillis(date);
+
+        int day_of_week = gc.get(Calendar.DAY_OF_WEEK);
+        int day_of_month = gc.get(Calendar.DAY_OF_MONTH);
+        int month = gc.get(Calendar.MONTH);
+        int year = gc.get(Calendar.YEAR);
+        int century = year / 100;
+        year = year % 100;
+
+        int hours = gc.get(Calendar.HOUR_OF_DAY);
+        int minutes = gc.get(Calendar.MINUTE);
+        int seconds = gc.get(Calendar.SECOND);
+
+        buf.append(DAYS[day_of_week]);
+        buf.append(',');
+        buf.append(' ');
+        StringUtil.append2digits(buf, day_of_month);
+
+        buf.append(' ');
+        buf.append(MONTHS[month]);
+        buf.append(' ');
+        StringUtil.append2digits(buf, century);
+        StringUtil.append2digits(buf, year);
+
+        buf.append(' ');
+        StringUtil.append2digits(buf, hours);
+        buf.append(':');
+        StringUtil.append2digits(buf, minutes);
+        buf.append(':');
+        StringUtil.append2digits(buf, seconds);
+        buf.append(" GMT");
+        return buf.toString();
+    }
+
+    /**
+     * Format "EEE, dd-MMM-yy HH:mm:ss 'GMT'" for cookies
+     */
+    public void doFormatCookieDate(StringBuilder buf, long date)
+    {
+        gc.setTimeInMillis(date);
+
+        int day_of_week = gc.get(Calendar.DAY_OF_WEEK);
+        int day_of_month = gc.get(Calendar.DAY_OF_MONTH);
+        int month = gc.get(Calendar.MONTH);
+        int year = gc.get(Calendar.YEAR);
+        year = year % 10000;
+
+        int epoch = (int) ((date / 1000) % (60 * 60 * 24));
+        int seconds = epoch % 60;
+        epoch = epoch / 60;
+        int minutes = epoch % 60;
+        int hours = epoch / 60;
+
+        buf.append(DAYS[day_of_week]);
+        buf.append(',');
+        buf.append(' ');
+        StringUtil.append2digits(buf, day_of_month);
+
+        buf.append('-');
+        buf.append(MONTHS[month]);
+        buf.append('-');
+        StringUtil.append2digits(buf, year/100);
+        StringUtil.append2digits(buf, year%100);
+
+        buf.append(' ');
+        StringUtil.append2digits(buf, hours);
+        buf.append(':');
+        StringUtil.append2digits(buf, minutes);
+        buf.append(':');
+        StringUtil.append2digits(buf, seconds);
+        buf.append(" GMT");
+    }
+}
diff --git a/lib/jetty/org/eclipse/jetty/http/DateParser.java b/lib/jetty/org/eclipse/jetty/http/DateParser.java
new file mode 100644 (file)
index 0000000..1ede4ce
--- /dev/null
@@ -0,0 +1,109 @@
+//
+//  ========================================================================
+//  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.http;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * ThreadLocal data parsers for HTTP style dates
+ *
+ */
+class DateParser
+{
+    private static final TimeZone __GMT = TimeZone.getTimeZone("GMT");
+    static
+    {
+        __GMT.setID("GMT");
+    }
+    
+    final static String __dateReceiveFmt[] =
+    {
+        "EEE, dd MMM yyyy HH:mm:ss zzz",
+        "EEE, dd-MMM-yy HH:mm:ss",
+        "EEE MMM dd HH:mm:ss yyyy",
+
+        "EEE, dd MMM yyyy HH:mm:ss", "EEE dd MMM yyyy HH:mm:ss zzz",
+        "EEE dd MMM yyyy HH:mm:ss", "EEE MMM dd yyyy HH:mm:ss zzz", "EEE MMM dd yyyy HH:mm:ss",
+        "EEE MMM-dd-yyyy HH:mm:ss zzz", "EEE MMM-dd-yyyy HH:mm:ss", "dd MMM yyyy HH:mm:ss zzz",
+        "dd MMM yyyy HH:mm:ss", "dd-MMM-yy HH:mm:ss zzz", "dd-MMM-yy HH:mm:ss", "MMM dd HH:mm:ss yyyy zzz",
+        "MMM dd HH:mm:ss yyyy", "EEE MMM dd HH:mm:ss yyyy zzz",
+        "EEE, MMM dd HH:mm:ss yyyy zzz", "EEE, MMM dd HH:mm:ss yyyy", "EEE, dd-MMM-yy HH:mm:ss zzz",
+        "EEE dd-MMM-yy HH:mm:ss zzz", "EEE dd-MMM-yy HH:mm:ss",
+    };
+
+    public static long parseDate(String date)
+    {
+        return __dateParser.get().parse(date);
+    }
+
+    private static final ThreadLocal<DateParser> __dateParser =new ThreadLocal<DateParser>()
+    {
+        @Override
+        protected DateParser initialValue()
+        {
+            return new DateParser();
+        }
+    };
+    
+    final SimpleDateFormat _dateReceive[]= new SimpleDateFormat[__dateReceiveFmt.length];
+
+    private long parse(final String dateVal)
+    {
+        for (int i = 0; i < _dateReceive.length; i++)
+        {
+            if (_dateReceive[i] == null)
+            {
+                _dateReceive[i] = new SimpleDateFormat(__dateReceiveFmt[i], Locale.US);
+                _dateReceive[i].setTimeZone(__GMT);
+            }
+
+            try
+            {
+                Date date = (Date) _dateReceive[i].parseObject(dateVal);
+                return date.getTime();
+            }
+            catch (java.lang.Exception e)
+            {
+                // LOG.ignore(e);
+            }
+        }
+
+        if (dateVal.endsWith(" GMT"))
+        {
+            final String val = dateVal.substring(0, dateVal.length() - 4);
+
+            for (SimpleDateFormat element : _dateReceive)
+            {
+                try
+                {
+                    Date date = (Date) element.parseObject(val);
+                    return date.getTime();
+                }
+                catch (java.lang.Exception e)
+                {
+                    // LOG.ignore(e);
+                }
+            }
+        }
+        return -1;
+    }
+}
diff --git a/lib/jetty/org/eclipse/jetty/http/HttpContent.java b/lib/jetty/org/eclipse/jetty/http/HttpContent.java
new file mode 100644 (file)
index 0000000..ebae56d
--- /dev/null
@@ -0,0 +1,172 @@
+//
+//  ========================================================================
+//  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.http;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.ReadableByteChannel;
+
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.resource.Resource;
+
+/* ------------------------------------------------------------ */
+/** HttpContent.
+ * 
+ *
+ */
+public interface HttpContent
+{
+    String getContentType();
+    String getLastModified();
+    ByteBuffer getIndirectBuffer();
+    ByteBuffer getDirectBuffer();
+    String getETag();
+    Resource getResource();
+    long getContentLength();
+    InputStream getInputStream() throws IOException;
+    ReadableByteChannel getReadableByteChannel() throws IOException;
+    void release();
+
+    /* ------------------------------------------------------------ */
+    /* ------------------------------------------------------------ */
+    /* ------------------------------------------------------------ */
+    public class ResourceAsHttpContent implements HttpContent
+    {
+        final Resource _resource;
+        final String _mimeType;
+        final int _maxBuffer;
+        final String _etag;
+
+        /* ------------------------------------------------------------ */
+        public ResourceAsHttpContent(final Resource resource, final String mimeType)
+        {
+            this(resource,mimeType,-1,false);
+        }
+
+        /* ------------------------------------------------------------ */
+        public ResourceAsHttpContent(final Resource resource, final String mimeType, int maxBuffer)
+        {
+            this(resource,mimeType,maxBuffer,false);
+        }
+
+        /* ------------------------------------------------------------ */
+        public ResourceAsHttpContent(final Resource resource, final String mimeType, boolean etag)
+        {
+            this(resource,mimeType,-1,etag);
+        }
+
+        /* ------------------------------------------------------------ */
+        public ResourceAsHttpContent(final Resource resource, final String mimeType, int maxBuffer, boolean etag)
+        {
+            _resource=resource;
+            _mimeType=mimeType;
+            _maxBuffer=maxBuffer;
+            _etag=etag?resource.getWeakETag():null;
+        }
+
+        /* ------------------------------------------------------------ */
+        @Override
+        public String getContentType()
+        {
+            return _mimeType;
+        }
+
+        /* ------------------------------------------------------------ */
+        @Override
+        public String getLastModified()
+        {
+            return null;
+        }
+
+        /* ------------------------------------------------------------ */
+        @Override
+        public ByteBuffer getDirectBuffer()
+        {
+            if (_resource.length()<=0 || _maxBuffer<_resource.length())
+                return null;
+            try
+            {
+                return BufferUtil.toBuffer(_resource,true);
+            }
+            catch(IOException e)
+            {
+                throw new RuntimeException(e);
+            }
+        }
+        
+        /* ------------------------------------------------------------ */
+        @Override
+        public String getETag()
+        {
+            return _etag;
+        }
+
+        /* ------------------------------------------------------------ */
+        @Override
+        public ByteBuffer getIndirectBuffer()
+        {
+            if (_resource.length()<=0 || _maxBuffer<_resource.length())
+                return null;
+            try
+            {
+                return BufferUtil.toBuffer(_resource,false);
+            }
+            catch(IOException e)
+            {
+                throw new RuntimeException(e);
+            }
+        }
+
+        /* ------------------------------------------------------------ */
+        @Override
+        public long getContentLength()
+        {
+            return _resource.length();
+        }
+
+        /* ------------------------------------------------------------ */
+        @Override
+        public InputStream getInputStream() throws IOException
+        {
+            return _resource.getInputStream();
+        }
+        
+        /* ------------------------------------------------------------ */
+        @Override
+        public ReadableByteChannel getReadableByteChannel() throws IOException
+        {
+            return _resource.getReadableByteChannel();
+        }
+
+        /* ------------------------------------------------------------ */
+        @Override
+        public Resource getResource()
+        {
+            return _resource;
+        }
+
+        /* ------------------------------------------------------------ */
+        @Override
+        public void release()
+        {
+            _resource.close();
+        }
+    }
+}
diff --git a/lib/jetty/org/eclipse/jetty/http/HttpCookie.java b/lib/jetty/org/eclipse/jetty/http/HttpCookie.java
new file mode 100644 (file)
index 0000000..1a2426b
--- /dev/null
@@ -0,0 +1,164 @@
+//
+//  ========================================================================
+//  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.http;
+
+import java.util.concurrent.TimeUnit;
+
+public class HttpCookie
+{
+    private final String _name;
+    private final String _value;
+    private final String _comment;
+    private final String _domain;
+    private final long _maxAge;
+    private final String _path;
+    private final boolean _secure;
+    private final int _version;
+    private final boolean _httpOnly;
+    private final long _expiration;
+
+    public HttpCookie(String name, String value)
+    {
+        this(name, value, -1);
+    }
+
+    public HttpCookie(String name, String value, String domain, String path)
+    {
+        this(name, value, domain, path, -1, false, false);
+    }
+
+    public HttpCookie(String name, String value, long maxAge)
+    {
+        this(name, value, null, null, maxAge, false, false);
+    }
+
+    public HttpCookie(String name, String value, String domain, String path, long maxAge, boolean httpOnly, boolean secure)
+    {
+        this(name, value, domain, path, maxAge, httpOnly, secure, null, 0);
+    }
+
+    public HttpCookie(String name, String value, String domain, String path, long maxAge, boolean httpOnly, boolean secure, String comment, int version)
+    {
+        _name = name;
+        _value = value;
+        _domain = domain;
+        _path = path;
+        _maxAge = maxAge;
+        _httpOnly = httpOnly;
+        _secure = secure;
+        _comment = comment;
+        _version = version;
+        _expiration = maxAge < 0 ? -1 : System.nanoTime() + TimeUnit.SECONDS.toNanos(maxAge);
+    }
+
+    /**
+     * @return the cookie name
+     */
+    public String getName()
+    {
+        return _name;
+    }
+
+    /**
+     * @return the cookie value
+     */
+    public String getValue()
+    {
+        return _value;
+    }
+
+    /**
+     * @return the cookie comment
+     */
+    public String getComment()
+    {
+        return _comment;
+    }
+
+    /**
+     * @return the cookie domain
+     */
+    public String getDomain()
+    {
+        return _domain;
+    }
+
+    /**
+     * @return the cookie max age in seconds
+     */
+    public long getMaxAge()
+    {
+        return _maxAge;
+    }
+
+    /**
+     * @return the cookie path
+     */
+    public String getPath()
+    {
+        return _path;
+    }
+
+    /**
+     * @return whether the cookie is valid for secure domains
+     */
+    public boolean isSecure()
+    {
+        return _secure;
+    }
+
+    /**
+     * @return the cookie version
+     */
+    public int getVersion()
+    {
+        return _version;
+    }
+
+    /**
+     * @return whether the cookie is valid for the http protocol only
+     */
+    public boolean isHttpOnly()
+    {
+        return _httpOnly;
+    }
+
+    /**
+     * @param timeNanos the time to check for cookie expiration, in nanoseconds
+     * @return whether the cookie is expired by the given time
+     */
+    public boolean isExpired(long timeNanos)
+    {
+        return _expiration >= 0 && timeNanos >= _expiration;
+    }
+
+    /**
+     * @return a string representation of this cookie
+     */
+    public String asString()
+    {
+        StringBuilder builder = new StringBuilder();
+        builder.append(getName()).append("=").append(getValue());
+        if (getDomain() != null)
+            builder.append(";$Domain=").append(getDomain());
+        if (getPath() != null)
+            builder.append(";$Path=").append(getPath());
+        return builder.toString();
+    }
+}
diff --git a/lib/jetty/org/eclipse/jetty/http/HttpField.java b/lib/jetty/org/eclipse/jetty/http/HttpField.java
new file mode 100644 (file)
index 0000000..50f29b1
--- /dev/null
@@ -0,0 +1,89 @@
+//
+//  ========================================================================
+//  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.http;
+
+
+/* ------------------------------------------------------------ */
+/** A HTTP Field
+ */
+public class HttpField
+{
+    private final HttpHeader _header;
+    private final String _name;
+    private final String _value;
+        
+    public HttpField(HttpHeader header, String name, String value)
+    {
+        _header = header;
+        _name = name;
+        _value = value;
+    }  
+    
+    public HttpField(HttpHeader header, String value)
+    {
+        this(header,header.asString(),value);
+    }
+    
+    public HttpField(HttpHeader header, HttpHeaderValue value)
+    {
+        this(header,header.asString(),value.asString());
+    }
+    
+    public HttpField(String name, String value)
+    {
+        this(HttpHeader.CACHE.get(name),name,value);
+    }
+
+    public HttpHeader getHeader()
+    {
+        return _header;
+    }
+
+    public String getName()
+    {
+        return _name;
+    }
+
+    public String getValue()
+    {
+        return _value;
+    }
+    
+    @Override
+    public String toString()
+    {
+        String v=getValue();
+        return getName() + ": " + (v==null?"":v);
+    }
+
+    public boolean isSame(HttpField field)
+    {
+        if (field==null)
+            return false;
+        if (field==this)
+            return true;
+        if (_header!=null && _header==field.getHeader())
+            return true;
+        if (_name.equalsIgnoreCase(field.getName()))
+            return true;
+        return false;
+    }
+    
+    
+}
diff --git a/lib/jetty/org/eclipse/jetty/http/HttpFields.java b/lib/jetty/org/eclipse/jetty/http/HttpFields.java
new file mode 100644 (file)
index 0000000..d474227
--- /dev/null
@@ -0,0 +1,784 @@
+//
+//  ========================================================================
+//  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.http;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.regex.Pattern;
+
+import org.eclipse.jetty.util.ArrayTernaryTrie;
+import org.eclipse.jetty.util.LazyList;
+import org.eclipse.jetty.util.QuotedStringTokenizer;
+import org.eclipse.jetty.util.StringUtil;
+import org.eclipse.jetty.util.Trie;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+
+/**
+ * HTTP Fields. A collection of HTTP header and or Trailer fields.
+ *
+ * <p>This class is not synchronized as it is expected that modifications will only be performed by a
+ * single thread.
+ * 
+ * <p>The cookie handling provided by this class is guided by the Servlet specification and RFC6265.
+ *
+ */
+public class HttpFields implements Iterable<HttpField>
+{
+    private static final Logger LOG = Log.getLogger(HttpFields.class);
+    private final static Pattern __splitter = Pattern.compile("\\s*,\\s*");     
+    public final static String __separators = ", \t";
+
+    private final ArrayList<HttpField> _fields = new ArrayList<>(20);
+
+    /**
+     * Constructor.
+     */
+    public HttpFields()
+    {
+    }
+
+    /**
+     * Get Collection of header names.
+     */
+    public Collection<String> getFieldNamesCollection()
+    {
+        final Set<String> list = new HashSet<>(_fields.size());
+        for (HttpField f : _fields)
+        {
+            if (f!=null)
+                list.add(f.getName());
+        }
+        return list;
+    }
+
+    /**
+     * Get enumeration of header _names. Returns an enumeration of strings representing the header
+     * _names for this request.
+     */
+    public Enumeration<String> getFieldNames()
+    {
+        return Collections.enumeration(getFieldNamesCollection());
+    }
+
+    public int size()
+    {
+        return _fields.size();
+    }
+
+    /**
+     * Get a Field by index.
+     * @return A Field value or null if the Field value has not been set
+     *
+     */
+    public HttpField getField(int i)
+    {
+        return _fields.get(i);
+    }
+
+    @Override
+    public Iterator<HttpField> iterator()
+    {
+        return _fields.iterator();
+    }
+
+    public HttpField getField(HttpHeader header)
+    {
+        for (int i=0;i<_fields.size();i++)
+        {
+            HttpField f=_fields.get(i);
+            if (f.getHeader()==header)
+                return f;
+        }
+        return null;
+    }
+
+    public HttpField getField(String name)
+    {
+        for (int i=0;i<_fields.size();i++)
+        {
+            HttpField f=_fields.get(i);
+            if (f.getName().equalsIgnoreCase(name))
+                return f;
+        }
+        return null;
+    }
+    
+    public boolean contains(HttpHeader header, String value)
+    {
+        for (int i=0;i<_fields.size();i++)
+        {
+            HttpField f=_fields.get(i);
+            if (f.getHeader()==header && contains(f,value))
+                return true;
+        }
+        return false;
+    }
+    
+    public boolean contains(String name, String value)
+    {
+        for (int i=0;i<_fields.size();i++)
+        {
+            HttpField f=_fields.get(i);
+            if (f.getName().equalsIgnoreCase(name) && contains(f,value))
+                return true;
+        }
+        return false;
+    }
+    
+    private boolean contains(HttpField field,String value)
+    {
+        String v = field.getValue();
+        if (v==null)
+            return false;
+
+        if (value.equalsIgnoreCase(v))
+            return true;
+
+        String[] split = __splitter.split(v);
+        for (int i = 0; split!=null && i < split.length; i++) 
+        {
+            if (value.equals(split[i]))
+                return true;
+        }
+
+        return false;
+    }
+    
+    public boolean containsKey(String name)
+    {
+        for (int i=0;i<_fields.size();i++)
+        {
+            HttpField f=_fields.get(i);
+            if (f.getName().equalsIgnoreCase(name))
+                return true;
+        }
+        return false;
+    }
+
+    public String getStringField(HttpHeader header)
+    {
+        return getStringField(header.asString());
+    }
+
+    public String get(HttpHeader header)
+    {
+        return getStringField(header.asString());
+    }
+
+    public String get(String header)
+    {
+        return getStringField(header);
+    }
+
+    /**
+     * @return the value of a field, or null if not found. For multiple fields of the same name,
+     *         only the first is returned.
+     * @param name the case-insensitive field name
+     */
+    public String getStringField(String name)
+    {
+        HttpField field = getField(name);
+        return field==null?null:field.getValue();
+    }
+
+    /**
+     * Get multi headers
+     *
+     * @return List the values
+     * @param name the case-insensitive field name
+     */
+    public List<String> getValuesList(String name)
+    {
+        final List<String> list = new ArrayList<>();
+        for (HttpField f : _fields)
+            if (f.getName().equalsIgnoreCase(name))
+                list.add(f.getValue());
+        return list;
+    }
+
+    /**
+     * Get multi headers
+     *
+     * @return Enumeration of the values
+     * @param name the case-insensitive field name
+     */
+    public Enumeration<String> getValues(final String name)
+    {
+        for (int i=0;i<_fields.size();i++)
+        {
+            final HttpField f = _fields.get(i);
+            
+            if (f.getName().equalsIgnoreCase(name) && f.getValue()!=null)
+            {
+                final int first=i;
+                return new Enumeration<String>()
+                {
+                    HttpField field=f;
+                    int i = first+1;
+
+                    @Override
+                    public boolean hasMoreElements()
+                    {
+                        if (field==null)
+                        {
+                            while (i<_fields.size()) 
+                            {
+                                field=_fields.get(i++);
+                                if (field.getName().equalsIgnoreCase(name) && field.getValue()!=null)
+                                    return true;
+                            }
+                            field=null;
+                            return false;
+                        }
+                        return true;
+                    }
+
+                    @Override
+                    public String nextElement() throws NoSuchElementException
+                    {
+                        if (hasMoreElements())
+                        {
+                            String value=field.getValue();
+                            field=null;
+                            return value;
+                        }
+                        throw new NoSuchElementException();
+                    }
+
+                };
+            }
+        }
+
+        List<String> empty=Collections.emptyList();
+        return Collections.enumeration(empty);
+    }
+
+    /**
+     * Get multi field values with separator. The multiple values can be represented as separate
+     * headers of the same name, or by a single header using the separator(s), or a combination of
+     * both. Separators may be quoted.
+     *
+     * @param name the case-insensitive field name
+     * @param separators String of separators.
+     * @return Enumeration of the values, or null if no such header.
+     */
+    public Enumeration<String> getValues(String name, final String separators)
+    {
+        final Enumeration<String> e = getValues(name);
+        if (e == null)
+            return null;
+        return new Enumeration<String>()
+        {
+            QuotedStringTokenizer tok = null;
+
+            @Override
+            public boolean hasMoreElements()
+            {
+                if (tok != null && tok.hasMoreElements()) return true;
+                while (e.hasMoreElements())
+                {
+                    String value = e.nextElement();
+                    if (value!=null)
+                    {
+                        tok = new QuotedStringTokenizer(value, separators, false, false);
+                        if (tok.hasMoreElements()) return true;
+                    }
+                }
+                tok = null;
+                return false;
+            }
+
+            @Override
+            public String nextElement() throws NoSuchElementException
+            {
+                if (!hasMoreElements()) throw new NoSuchElementException();
+                String next = (String) tok.nextElement();
+                if (next != null) next = next.trim();
+                return next;
+            }
+        };
+    }
+
+    public void put(HttpField field)
+    {
+        boolean put=false;
+        for (int i=_fields.size();i-->0;)
+        {
+            HttpField f=_fields.get(i);
+            if (f.isSame(field))
+            {
+                if (put)
+                    _fields.remove(i);
+                else
+                {
+                    _fields.set(i,field);
+                    put=true;
+                }
+            }
+        }
+        if (!put)
+            _fields.add(field);
+    }
+    
+    /**
+     * Set a field.
+     *
+     * @param name the name of the field
+     * @param value the value of the field. If null the field is cleared.
+     */
+    public void put(String name, String value)
+    {
+        if (value == null)
+            remove(name);
+        else
+            put(new HttpField(name, value));
+    }
+
+    public void put(HttpHeader header, HttpHeaderValue value)
+    {
+        put(header,value.toString());
+    }
+
+    /**
+     * Set a field.
+     *
+     * @param header the header name of the field
+     * @param value the value of the field. If null the field is cleared.
+     */
+    public void put(HttpHeader header, String value)
+    {
+        if (value == null)
+            remove(header);
+        else
+            put(new HttpField(header, value));
+    }
+
+    /**
+     * Set a field.
+     *
+     * @param name the name of the field
+     * @param list the List value of the field. If null the field is cleared.
+     */
+    public void put(String name, List<String> list)
+    {
+        remove(name);
+        for (String v : list)
+            if (v!=null)
+                add(name,v);
+    }
+
+    /**
+     * Add to or set a field. If the field is allowed to have multiple values, add will add multiple
+     * headers of the same name.
+     *
+     * @param name the name of the field
+     * @param value the value of the field.
+     * @exception IllegalArgumentException If the name is a single valued field and already has a
+     *                value.
+     */
+    public void add(String name, String value) throws IllegalArgumentException
+    {
+        if (value == null)
+            return;
+
+        HttpField field = new HttpField(name, value);
+        _fields.add(field);
+    }
+
+    public void add(HttpHeader header, HttpHeaderValue value) throws IllegalArgumentException
+    {
+        add(header,value.toString());
+    }
+
+    /**
+     * Add to or set a field. If the field is allowed to have multiple values, add will add multiple
+     * headers of the same name.
+     *
+     * @param header the header
+     * @param value the value of the field.
+     * @exception IllegalArgumentException 
+     */
+    public void add(HttpHeader header, String value) throws IllegalArgumentException
+    {
+        if (value == null) throw new IllegalArgumentException("null value");
+
+        HttpField field = new HttpField(header, value);
+        _fields.add(field);
+    }
+
+    /**
+     * Remove a field.
+     *
+     * @param name the field to remove
+     */
+    public HttpField remove(HttpHeader name)
+    {
+        for (int i=_fields.size();i-->0;)
+        {
+            HttpField f=_fields.get(i);
+            if (f.getHeader()==name)
+                return _fields.remove(i);
+        }
+        return null;
+    }
+
+    /**
+     * Remove a field.
+     *
+     * @param name the field to remove
+     */
+    public HttpField remove(String name)
+    {
+        for (int i=_fields.size();i-->0;)
+        {
+            HttpField f=_fields.get(i);
+            if (f.getName().equalsIgnoreCase(name))
+                return _fields.remove(i);
+        }
+        return null;
+    }
+
+    /**
+     * Get a header as an long value. Returns the value of an integer field or -1 if not found. The
+     * case of the field name is ignored.
+     *
+     * @param name the case-insensitive field name
+     * @exception NumberFormatException If bad long found
+     */
+    public long getLongField(String name) throws NumberFormatException
+    {
+        HttpField field = getField(name);
+        return field==null?-1L:StringUtil.toLong(field.getValue());
+    }
+
+    /**
+     * Get a header as a date value. Returns the value of a date field, or -1 if not found. The case
+     * of the field name is ignored.
+     *
+     * @param name the case-insensitive field name
+     */
+    public long getDateField(String name)
+    {
+        HttpField field = getField(name);
+        if (field == null)
+            return -1;
+
+        String val = valueParameters(field.getValue(), null);
+        if (val == null)
+            return -1;
+
+        final long date = DateParser.parseDate(val);
+        if (date==-1)
+            throw new IllegalArgumentException("Cannot convert date: " + val);
+        return date;
+    }
+
+
+    /**
+     * Sets the value of an long field.
+     *
+     * @param name the field name
+     * @param value the field long value
+     */
+    public void putLongField(HttpHeader name, long value)
+    {
+        String v = Long.toString(value);
+        put(name, v);
+    }
+
+    /**
+     * Sets the value of an long field.
+     *
+     * @param name the field name
+     * @param value the field long value
+     */
+    public void putLongField(String name, long value)
+    {
+        String v = Long.toString(value);
+        put(name, v);
+    }
+
+
+    /**
+     * Sets the value of a date field.
+     *
+     * @param name the field name
+     * @param date the field date value
+     */
+    public void putDateField(HttpHeader name, long date)
+    {
+        String d=DateGenerator.formatDate(date);
+        put(name, d);
+    }
+
+    /**
+     * Sets the value of a date field.
+     *
+     * @param name the field name
+     * @param date the field date value
+     */
+    public void putDateField(String name, long date)
+    {
+        String d=DateGenerator.formatDate(date);
+        put(name, d);
+    }
+
+    /**
+     * Sets the value of a date field.
+     *
+     * @param name the field name
+     * @param date the field date value
+     */
+    public void addDateField(String name, long date)
+    {
+        String d=DateGenerator.formatDate(date);
+        add(name,d);
+    }
+
+    @Override
+    public String
+    toString()
+    {
+        try
+        {
+            StringBuilder buffer = new StringBuilder();
+            for (HttpField field : _fields)
+            {
+                if (field != null)
+                {
+                    String tmp = field.getName();
+                    if (tmp != null) buffer.append(tmp);
+                    buffer.append(": ");
+                    tmp = field.getValue();
+                    if (tmp != null) buffer.append(tmp);
+                    buffer.append("\r\n");
+                }
+            }
+            buffer.append("\r\n");
+            return buffer.toString();
+        }
+        catch (Exception e)
+        {
+            LOG.warn(e);
+            return e.toString();
+        }
+    }
+
+    /**
+     * Clear the header.
+     */
+    public void clear()
+    {
+        _fields.clear();
+    }
+
+    public void add(HttpField field)
+    {
+        _fields.add(field);
+    }
+
+    
+    
+    /**
+     * Add fields from another HttpFields instance. Single valued fields are replaced, while all
+     * others are added.
+     *
+     * @param fields the fields to add
+     */
+    public void add(HttpFields fields)
+    {
+        if (fields == null) return;
+
+        Enumeration<String> e = fields.getFieldNames();
+        while (e.hasMoreElements())
+        {
+            String name = e.nextElement();
+            Enumeration<String> values = fields.getValues(name);
+            while (values.hasMoreElements())
+                add(name, values.nextElement());
+        }
+    }
+
+    /**
+     * Get field value parameters. Some field values can have parameters. This method separates the
+     * value from the parameters and optionally populates a map with the parameters. For example:
+     *
+     * <PRE>
+     *
+     * FieldName : Value ; param1=val1 ; param2=val2
+     *
+     * </PRE>
+     *
+     * @param value The Field value, possibly with parameteres.
+     * @param parameters A map to populate with the parameters, or null
+     * @return The value.
+     */
+    public static String valueParameters(String value, Map<String,String> parameters)
+    {
+        if (value == null) return null;
+
+        int i = value.indexOf(';');
+        if (i < 0) return value;
+        if (parameters == null) return value.substring(0, i).trim();
+
+        StringTokenizer tok1 = new QuotedStringTokenizer(value.substring(i), ";", false, true);
+        while (tok1.hasMoreTokens())
+        {
+            String token = tok1.nextToken();
+            StringTokenizer tok2 = new QuotedStringTokenizer(token, "= ");
+            if (tok2.hasMoreTokens())
+            {
+                String paramName = tok2.nextToken();
+                String paramVal = null;
+                if (tok2.hasMoreTokens()) paramVal = tok2.nextToken();
+                parameters.put(paramName, paramVal);
+            }
+        }
+
+        return value.substring(0, i).trim();
+    }
+
+    private static final Float __one = new Float("1.0");
+    private static final Float __zero = new Float("0.0");
+    private static final Trie<Float> __qualities = new ArrayTernaryTrie<>();
+    static
+    {
+        __qualities.put("*", __one);
+        __qualities.put("1.0", __one);
+        __qualities.put("1", __one);
+        __qualities.put("0.9", new Float("0.9"));
+        __qualities.put("0.8", new Float("0.8"));
+        __qualities.put("0.7", new Float("0.7"));
+        __qualities.put("0.66", new Float("0.66"));
+        __qualities.put("0.6", new Float("0.6"));
+        __qualities.put("0.5", new Float("0.5"));
+        __qualities.put("0.4", new Float("0.4"));
+        __qualities.put("0.33", new Float("0.33"));
+        __qualities.put("0.3", new Float("0.3"));
+        __qualities.put("0.2", new Float("0.2"));
+        __qualities.put("0.1", new Float("0.1"));
+        __qualities.put("0", __zero);
+        __qualities.put("0.0", __zero);
+    }
+
+    public static Float getQuality(String value)
+    {
+        if (value == null) return __zero;
+
+        int qe = value.indexOf(";");
+        if (qe++ < 0 || qe == value.length()) return __one;
+
+        if (value.charAt(qe++) == 'q')
+        {
+            qe++;
+            Float q = __qualities.get(value, qe, value.length() - qe);
+            if (q != null)
+                return q;
+        }
+
+        Map<String,String> params = new HashMap<>(4);
+        valueParameters(value, params);
+        String qs = params.get("q");
+        if (qs==null)
+            qs="*";
+        Float q = __qualities.get(qs);
+        if (q == null)
+        {
+            try
+            {
+                q = new Float(qs);
+            }
+            catch (Exception e)
+            {
+                q = __one;
+            }
+        }
+        return q;
+    }
+
+    /**
+     * List values in quality order.
+     *
+     * @param e Enumeration of values with quality parameters
+     * @return values in quality order.
+     */
+    public static List<String> qualityList(Enumeration<String> e)
+    {
+        if (e == null || !e.hasMoreElements())
+            return Collections.emptyList();
+
+        Object list = null;
+        Object qual = null;
+
+        // Assume list will be well ordered and just add nonzero
+        while (e.hasMoreElements())
+        {
+            String v = e.nextElement();
+            Float q = getQuality(v);
+
+            if (q >= 0.001)
+            {
+                list = LazyList.add(list, v);
+                qual = LazyList.add(qual, q);
+            }
+        }
+
+        List<String> vl = LazyList.getList(list, false);
+        if (vl.size() < 2) 
+            return vl;
+
+        List<Float> ql = LazyList.getList(qual, false);
+
+        // sort list with swaps
+        Float last = __zero;
+        for (int i = vl.size(); i-- > 0;)
+        {
+            Float q = ql.get(i);
+            if (last.compareTo(q) > 0)
+            {
+                String tmp = vl.get(i);
+                vl.set(i, vl.get(i + 1));
+                vl.set(i + 1, tmp);
+                ql.set(i, ql.get(i + 1));
+                ql.set(i + 1, q);
+                last = __zero;
+                i = vl.size();
+                continue;
+            }
+            last = q;
+        }
+        ql.clear();
+        return vl;
+    }
+
+
+
+}
diff --git a/lib/jetty/org/eclipse/jetty/http/HttpGenerator.java b/lib/jetty/org/eclipse/jetty/http/HttpGenerator.java
new file mode 100644 (file)
index 0000000..a51e4ba
--- /dev/null
@@ -0,0 +1,1104 @@
+//
+//  ========================================================================
+//  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.http;
+
+import java.io.IOException;
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+
+import org.eclipse.jetty.http.HttpTokens.EndOfContent;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.StringUtil;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+/* ------------------------------------------------------------ */
+/**
+ * HttpGenerator. Builds HTTP Messages.
+ *
+ * If the system property "org.eclipse.jetty.http.HttpGenerator.STRICT" is set to true,
+ * then the generator will strictly pass on the exact strings received from methods and header
+ * fields.  Otherwise a fast case insensitive string lookup is used that may alter the
+ * case and white space of some methods/headers
+ * </p>
+ */
+public class HttpGenerator
+{
+    private final static Logger LOG = Log.getLogger(HttpGenerator.class);
+
+    public final static boolean __STRICT=Boolean.getBoolean("org.eclipse.jetty.http.HttpGenerator.STRICT"); 
+
+    private final static byte[] __colon_space = new byte[] {':',' '};
+    private final static HttpHeaderValue[] CLOSE = {HttpHeaderValue.CLOSE};
+    public static final ResponseInfo CONTINUE_100_INFO = new ResponseInfo(HttpVersion.HTTP_1_1,null,-1,100,null,false);
+    public static final ResponseInfo PROGRESS_102_INFO = new ResponseInfo(HttpVersion.HTTP_1_1,null,-1,102,null,false);
+    public final static ResponseInfo RESPONSE_500_INFO =
+        new ResponseInfo(HttpVersion.HTTP_1_1,new HttpFields(){{put(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE);}},0,HttpStatus.INTERNAL_SERVER_ERROR_500,null,false);
+
+    // states
+    public enum State { START, COMMITTED, COMPLETING, COMPLETING_1XX, END }
+    public enum Result { NEED_CHUNK,NEED_INFO,NEED_HEADER,FLUSH,CONTINUE,SHUTDOWN_OUT,DONE}
+
+    // other statics
+    public static final int CHUNK_SIZE = 12;
+
+    private State _state = State.START;
+    private EndOfContent _endOfContent = EndOfContent.UNKNOWN_CONTENT;
+
+    private long _contentPrepared = 0;
+    private boolean _noContent = false;
+    private Boolean _persistent = null;
+
+    private final int _send;
+    private final static int SEND_SERVER = 0x01;
+    private final static int SEND_XPOWEREDBY = 0x02;
+
+
+    /* ------------------------------------------------------------------------------- */
+    public static void setJettyVersion(String serverVersion)
+    {
+        SEND[SEND_SERVER] = StringUtil.getBytes("Server: " + serverVersion + "\015\012");
+        SEND[SEND_XPOWEREDBY] = StringUtil.getBytes("X-Powered-By: " + serverVersion + "\015\012");
+        SEND[SEND_SERVER | SEND_XPOWEREDBY] = StringUtil.getBytes("Server: " + serverVersion + "\015\012X-Powered-By: " +
+                serverVersion + "\015\012");
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    // data
+    private boolean _needCRLF = false;
+
+    /* ------------------------------------------------------------------------------- */
+    public HttpGenerator()
+    {
+        this(false,false);
+    }
+    
+    /* ------------------------------------------------------------------------------- */
+    public HttpGenerator(boolean sendServerVersion,boolean sendXPoweredBy)
+    {
+        _send=(sendServerVersion?SEND_SERVER:0) | (sendXPoweredBy?SEND_XPOWEREDBY:0);
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    public void reset()
+    {
+        _state = State.START;
+        _endOfContent = EndOfContent.UNKNOWN_CONTENT;
+        _noContent=false;
+        _persistent = null;
+        _contentPrepared = 0;
+        _needCRLF = false;
+    }
+
+    /* ------------------------------------------------------------ */
+    @Deprecated
+    public boolean getSendServerVersion ()
+    {
+        return (_send&SEND_SERVER)!=0;
+    }
+
+    /* ------------------------------------------------------------ */
+    @Deprecated
+    public void setSendServerVersion (boolean sendServerVersion)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    /* ------------------------------------------------------------ */
+    public State getState()
+    {
+        return _state;
+    }
+
+    /* ------------------------------------------------------------ */
+    public boolean isState(State state)
+    {
+        return _state == state;
+    }
+
+    /* ------------------------------------------------------------ */
+    public boolean isIdle()
+    {
+        return _state == State.START;
+    }
+
+    /* ------------------------------------------------------------ */
+    public boolean isEnd()
+    {
+        return _state == State.END;
+    }
+
+    /* ------------------------------------------------------------ */
+    public boolean isCommitted()
+    {
+        return _state.ordinal() >= State.COMMITTED.ordinal();
+    }
+
+    /* ------------------------------------------------------------ */
+    public boolean isChunking()
+    {
+        return _endOfContent==EndOfContent.CHUNKED_CONTENT;
+    }
+
+    /* ------------------------------------------------------------ */
+    public void setPersistent(boolean persistent)
+    {
+        _persistent=persistent;
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @return true if known to be persistent
+     */
+    public boolean isPersistent()
+    {
+        return Boolean.TRUE.equals(_persistent);
+    }
+
+    /* ------------------------------------------------------------ */
+    public boolean isWritten()
+    {
+        return _contentPrepared>0;
+    }
+
+    /* ------------------------------------------------------------ */
+    public long getContentPrepared()
+    {
+        return _contentPrepared;
+    }
+
+    /* ------------------------------------------------------------ */
+    public void abort()
+    {
+        _persistent=false;
+        _state=State.END;
+        _endOfContent=null;
+    }
+
+    /* ------------------------------------------------------------ */
+    public Result generateRequest(RequestInfo info, ByteBuffer header, ByteBuffer chunk, ByteBuffer content, boolean last) throws IOException
+    {
+        switch(_state)
+        {
+            case START:
+            {
+                if (info==null)
+                    return Result.NEED_INFO;
+
+                // Do we need a request header
+                if (header==null)
+                    return Result.NEED_HEADER;
+
+                // If we have not been told our persistence, set the default
+                if (_persistent==null)
+                    _persistent=(info.getHttpVersion().ordinal() > HttpVersion.HTTP_1_0.ordinal());
+
+                // prepare the header
+                int pos=BufferUtil.flipToFill(header);
+                try
+                {
+                    // generate ResponseLine
+                    generateRequestLine(info,header);
+
+                    if (info.getHttpVersion()==HttpVersion.HTTP_0_9)
+                        _noContent=true;
+                    else
+                        generateHeaders(info,header,content,last);
+
+                    boolean expect100 = info.getHttpFields().contains(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString());
+
+                    if (expect100)
+                    {
+                        _state = State.COMMITTED;
+                    }
+                    else
+                    {
+                        // handle the content.
+                        int len = BufferUtil.length(content);
+                        if (len>0)
+                        {
+                            _contentPrepared+=len;
+                            if (isChunking())
+                                prepareChunk(header,len);
+                        }
+                        _state = last?State.COMPLETING:State.COMMITTED;
+                    }
+
+                    return Result.FLUSH;
+                }
+                catch(Exception e)
+                {
+                    String message= (e instanceof BufferOverflowException)?"Response header too large":e.getMessage();
+                    throw new IOException(message,e);
+                }
+                finally
+                {
+                    BufferUtil.flipToFlush(header,pos);
+                }
+            }
+
+            case COMMITTED:
+            {
+                int len = BufferUtil.length(content);
+
+                if (len>0)
+                {
+                    // Do we need a chunk buffer?
+                    if (isChunking())
+                    {
+                        // Do we need a chunk buffer?
+                        if (chunk==null)
+                            return Result.NEED_CHUNK;
+                        BufferUtil.clearToFill(chunk);
+                        prepareChunk(chunk,len);
+                        BufferUtil.flipToFlush(chunk,0);
+                    }
+                    _contentPrepared+=len;
+                }
+
+                if (last)
+                {
+                    _state=State.COMPLETING;
+                    return len>0?Result.FLUSH:Result.CONTINUE;
+                }
+
+                return Result.FLUSH;
+            }
+
+            case COMPLETING:
+            {
+                if (BufferUtil.hasContent(content))
+                {
+                    LOG.debug("discarding content in COMPLETING");
+                    BufferUtil.clear(content);
+                }
+
+                if (isChunking())
+                {
+                    // Do we need a chunk buffer?
+                    if (chunk==null)
+                        return Result.NEED_CHUNK;
+                    BufferUtil.clearToFill(chunk);
+                    prepareChunk(chunk,0);
+                    BufferUtil.flipToFlush(chunk,0);
+                    _endOfContent=EndOfContent.UNKNOWN_CONTENT;
+                    return Result.FLUSH;
+                }
+
+                _state=State.END;
+               return Boolean.TRUE.equals(_persistent)?Result.DONE:Result.SHUTDOWN_OUT;
+            }
+
+            case END:
+                if (BufferUtil.hasContent(content))
+                {
+                    LOG.debug("discarding content in COMPLETING");
+                    BufferUtil.clear(content);
+                }
+                return Result.DONE;
+
+            default:
+                throw new IllegalStateException();
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    public Result generateResponse(ResponseInfo info, ByteBuffer header, ByteBuffer chunk, ByteBuffer content, boolean last) throws IOException
+    {
+        switch(_state)
+        {
+            case START:
+            {
+                if (info==null)
+                    return Result.NEED_INFO;
+
+                // Handle 0.9
+                if (info.getHttpVersion() == HttpVersion.HTTP_0_9)
+                {
+                    _persistent = false;
+                    _endOfContent=EndOfContent.EOF_CONTENT;
+                    if (BufferUtil.hasContent(content))
+                        _contentPrepared+=content.remaining();
+                    _state = last?State.COMPLETING:State.COMMITTED;
+                    return Result.FLUSH;
+                }
+
+                // Do we need a response header
+                if (header==null)
+                    return Result.NEED_HEADER;
+
+                // If we have not been told our persistence, set the default
+                if (_persistent==null)
+                    _persistent=(info.getHttpVersion().ordinal() > HttpVersion.HTTP_1_0.ordinal());
+
+                // prepare the header
+                int pos=BufferUtil.flipToFill(header);
+                try
+                {
+                    // generate ResponseLine
+                    generateResponseLine(info,header);
+
+                    // Handle 1xx and no content responses
+                    int status=info.getStatus();
+                    if (status>=100 && status<200 )
+                    {
+                        _noContent=true;
+
+                        if (status!=HttpStatus.SWITCHING_PROTOCOLS_101 )
+                        {
+                            header.put(HttpTokens.CRLF);
+                            _state=State.COMPLETING_1XX;
+                            return Result.FLUSH;
+                        }
+                    }
+                    else if (status==HttpStatus.NO_CONTENT_204 || status==HttpStatus.NOT_MODIFIED_304)
+                    {
+                        _noContent=true;
+                    }
+
+                    generateHeaders(info,header,content,last);
+
+                    // handle the content.
+                    int len = BufferUtil.length(content);
+                    if (len>0)
+                    {
+                        _contentPrepared+=len;
+                        if (isChunking() && !info.isHead())
+                            prepareChunk(header,len);
+                    }
+                    _state = last?State.COMPLETING:State.COMMITTED;
+                }
+                catch(Exception e)
+                {
+                    String message= (e instanceof BufferOverflowException)?"Response header too large":e.getMessage();
+                    throw new IOException(message,e);
+                }
+                finally
+                {
+                    BufferUtil.flipToFlush(header,pos);
+                }
+
+                return Result.FLUSH;
+            }
+
+            case COMMITTED:
+            {
+                int len = BufferUtil.length(content);
+
+                // handle the content.
+                if (len>0)
+                {
+                    if (isChunking())
+                    {
+                        if (chunk==null)
+                            return Result.NEED_CHUNK;
+                        BufferUtil.clearToFill(chunk);
+                        prepareChunk(chunk,len);
+                        BufferUtil.flipToFlush(chunk,0);
+                    }
+                    _contentPrepared+=len;
+                }
+
+                if (last)
+                {
+                    _state=State.COMPLETING;
+                    return len>0?Result.FLUSH:Result.CONTINUE;
+                }
+                return len>0?Result.FLUSH:Result.DONE;
+
+            }
+
+            case COMPLETING_1XX:
+            {
+                reset();
+                return Result.DONE;
+            }
+
+            case COMPLETING:
+            {
+                if (BufferUtil.hasContent(content))
+                {
+                    LOG.debug("discarding content in COMPLETING");
+                    BufferUtil.clear(content);
+                }
+
+                if (isChunking())
+                {
+                    // Do we need a chunk buffer?
+                    if (chunk==null)
+                        return Result.NEED_CHUNK;
+
+                    // Write the last chunk
+                    BufferUtil.clearToFill(chunk);
+                    prepareChunk(chunk,0);
+                    BufferUtil.flipToFlush(chunk,0);
+                    _endOfContent=EndOfContent.UNKNOWN_CONTENT;
+                    return Result.FLUSH;
+                }
+
+                _state=State.END;
+
+               return Boolean.TRUE.equals(_persistent)?Result.DONE:Result.SHUTDOWN_OUT;
+            }
+
+            case END:
+                if (BufferUtil.hasContent(content))
+                {
+                    LOG.debug("discarding content in COMPLETING");
+                    BufferUtil.clear(content);
+                }
+                return Result.DONE;
+
+            default:
+                throw new IllegalStateException();
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    private void prepareChunk(ByteBuffer chunk, int remaining)
+    {
+        // if we need CRLF add this to header
+        if (_needCRLF)
+            BufferUtil.putCRLF(chunk);
+
+        // Add the chunk size to the header
+        if (remaining>0)
+        {
+            BufferUtil.putHexInt(chunk, remaining);
+            BufferUtil.putCRLF(chunk);
+            _needCRLF=true;
+        }
+        else
+        {
+            chunk.put(LAST_CHUNK);
+            _needCRLF=false;
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    private void generateRequestLine(RequestInfo request,ByteBuffer header)
+    {
+        header.put(StringUtil.getBytes(request.getMethod()));
+        header.put((byte)' ');
+        header.put(StringUtil.getBytes(request.getUri()));
+        switch(request.getHttpVersion())
+        {
+            case HTTP_1_0:
+            case HTTP_1_1:
+                header.put((byte)' ');
+                header.put(request.getHttpVersion().toBytes());
+                break;
+            default:
+                throw new IllegalStateException();
+        }
+        header.put(HttpTokens.CRLF);
+    }
+
+    /* ------------------------------------------------------------ */
+    private void generateResponseLine(ResponseInfo response, ByteBuffer header)
+    {
+        // Look for prepared response line
+        int status=response.getStatus();
+        PreparedResponse preprepared = status<__preprepared.length?__preprepared[status]:null;
+        String reason=response.getReason();
+        if (preprepared!=null)
+        {
+            if (reason==null)
+                header.put(preprepared._responseLine);
+            else
+            {
+                header.put(preprepared._schemeCode);
+                header.put(getReasonBytes(reason));
+                header.put(HttpTokens.CRLF);
+            }
+        }
+        else // generate response line
+        {
+            header.put(HTTP_1_1_SPACE);
+            header.put((byte) ('0' + status / 100));
+            header.put((byte) ('0' + (status % 100) / 10));
+            header.put((byte) ('0' + (status % 10)));
+            header.put((byte) ' ');
+            if (reason==null)
+            {
+                header.put((byte) ('0' + status / 100));
+                header.put((byte) ('0' + (status % 100) / 10));
+                header.put((byte) ('0' + (status % 10)));
+            }
+            else
+                header.put(getReasonBytes(reason));
+            header.put(HttpTokens.CRLF);
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    private byte[] getReasonBytes(String reason)
+    {
+        if (reason.length()>1024)
+            reason=reason.substring(0,1024);
+        byte[] _bytes = StringUtil.getBytes(reason);
+
+        for (int i=_bytes.length;i-->0;)
+            if (_bytes[i]=='\r' || _bytes[i]=='\n')
+                _bytes[i]='?';
+        return _bytes;
+    }
+
+    /* ------------------------------------------------------------ */
+    private void generateHeaders(Info _info,ByteBuffer header,ByteBuffer content,boolean last)
+    {
+        final RequestInfo request=(_info instanceof RequestInfo)?(RequestInfo)_info:null;
+        final ResponseInfo response=(_info instanceof ResponseInfo)?(ResponseInfo)_info:null;
+
+        // default field values
+        int send=_send;
+        HttpField transfer_encoding=null;
+        boolean keep_alive=false;
+        boolean close=false;
+        boolean content_type=false;
+        StringBuilder connection = null;
+
+        // Generate fields
+        if (_info.getHttpFields() != null)
+        {
+            for (HttpField field : _info.getHttpFields())
+            {
+                HttpHeader h = field.getHeader();
+
+                switch (h==null?HttpHeader.UNKNOWN:h)
+                {
+                    case CONTENT_LENGTH:
+                        // handle specially below
+                        if (_info.getContentLength()>=0)
+                            _endOfContent=EndOfContent.CONTENT_LENGTH;
+                        break;
+
+                    case CONTENT_TYPE:
+                    {
+                        if (field.getValue().startsWith(MimeTypes.Type.MULTIPART_BYTERANGES.toString()))
+                            _endOfContent=EndOfContent.SELF_DEFINING_CONTENT;
+
+                        // write the field to the header
+                        content_type=true;
+                        putTo(field,header);
+                        break;
+                    }
+
+                    case TRANSFER_ENCODING:
+                    {
+                        if (_info.getHttpVersion() == HttpVersion.HTTP_1_1)
+                            transfer_encoding = field;
+                        // Do NOT add yet!
+                        break;
+                    }
+
+                    case CONNECTION:
+                    {
+                        if (request!=null)
+                            putTo(field,header);
+
+                        // Lookup and/or split connection value field
+                        HttpHeaderValue[] values = HttpHeaderValue.CLOSE.is(field.getValue())?CLOSE:new HttpHeaderValue[]{HttpHeaderValue.CACHE.get(field.getValue())};
+                        String[] split = null;
+
+                        if (values[0]==null)
+                        {
+                            split = field.getValue().split("\\s*,\\s*");
+                            if (split.length>0)
+                            {
+                                values=new HttpHeaderValue[split.length];
+                                for (int i=0;i<split.length;i++)
+                                    values[i]=HttpHeaderValue.CACHE.get(split[i]);
+                            }
+                        }
+
+                        // Handle connection values
+                        for (int i=0;i<values.length;i++)
+                        {
+                            HttpHeaderValue value=values[i];
+                            switch (value==null?HttpHeaderValue.UNKNOWN:value)
+                            {
+                                case UPGRADE:
+                                {
+                                    // special case for websocket connection ordering
+                                    header.put(HttpHeader.CONNECTION.getBytesColonSpace()).put(HttpHeader.UPGRADE.getBytes());
+                                    header.put(CRLF);
+                                    break;
+                                }
+
+                                case CLOSE:
+                                {
+                                    close=true;
+                                    if (response!=null)
+                                    {
+                                        _persistent=false;
+                                        if (_endOfContent == EndOfContent.UNKNOWN_CONTENT)
+                                            _endOfContent=EndOfContent.EOF_CONTENT;
+                                    }
+                                    break;
+                                }
+
+                                case KEEP_ALIVE:
+                                {
+                                    if (_info.getHttpVersion() == HttpVersion.HTTP_1_0)
+                                    {
+                                        keep_alive = true;
+                                        if (response!=null)
+                                            _persistent=true;
+                                    }
+                                    break;
+                                }
+
+                                default:
+                                {
+                                    if (connection==null)
+                                        connection=new StringBuilder();
+                                    else
+                                        connection.append(',');
+                                    connection.append(split==null?field.getValue():split[i]);
+                                }
+                            }
+                        }
+
+                        // Do NOT add yet!
+                        break;
+                    }
+
+                    case SERVER:
+                    {
+                        send=send&~SEND_SERVER;
+                        putTo(field,header);
+                        break;
+                    }
+
+                    default:
+                        putTo(field,header);
+                }
+            }
+        }
+
+
+        // Calculate how to end _content and connection, _content length and transfer encoding
+        // settings.
+        // From RFC 2616 4.4:
+        // 1. No body for 1xx, 204, 304 & HEAD response
+        // 2. Force _content-length?
+        // 3. If Transfer-Encoding!=identity && HTTP/1.1 && !HttpConnection==close then chunk
+        // 4. Content-Length
+        // 5. multipart/byteranges
+        // 6. close
+        int status=response!=null?response.getStatus():-1;
+        switch (_endOfContent)
+        {
+            case UNKNOWN_CONTENT:
+                // It may be that we have no _content, or perhaps _content just has not been
+                // written yet?
+
+                // Response known not to have a body
+                if (_contentPrepared == 0 && response!=null && (status < 200 || status == 204 || status == 304))
+                    _endOfContent=EndOfContent.NO_CONTENT;
+                else if (_info.getContentLength()>0)
+                {
+                    // we have been given a content length
+                    _endOfContent=EndOfContent.CONTENT_LENGTH;
+                    long content_length = _info.getContentLength();
+                    if ((response!=null || content_length>0 || content_type ) && !_noContent)
+                    {
+                        // known length but not actually set.
+                        header.put(HttpHeader.CONTENT_LENGTH.getBytesColonSpace());
+                        BufferUtil.putDecLong(header, content_length);
+                        header.put(HttpTokens.CRLF);
+                    }
+                }
+                else if (last)
+                {
+                    // we have seen all the _content there is, so we can be content-length limited.
+                    _endOfContent=EndOfContent.CONTENT_LENGTH;
+                    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)
+                    {
+                        header.put(HttpHeader.CONTENT_LENGTH.getBytesColonSpace());
+                        BufferUtil.putDecLong(header, content_length);
+                        header.put(HttpTokens.CRLF);
+                    }
+                }
+                else
+                {
+                    // No idea, so we must assume that a body is coming.
+                    _endOfContent = EndOfContent.CHUNKED_CONTENT;
+                    // HTTP 1.0 does not understand chunked content, so we must use EOF content.
+                    // For a request with HTTP 1.0 & Connection: keep-alive
+                    // we *must* close the connection, otherwise the client
+                    // has no way to detect the end of the content.
+                    if (!isPersistent() || _info.getHttpVersion().ordinal() < HttpVersion.HTTP_1_1.ordinal())
+                        _endOfContent = EndOfContent.EOF_CONTENT;
+                }
+                break;
+
+            case CONTENT_LENGTH:
+                long content_length = _info.getContentLength();
+                if ((response!=null || content_length>0 || content_type ) && !_noContent)
+                {
+                    // known length but not actually set.
+                    header.put(HttpHeader.CONTENT_LENGTH.getBytesColonSpace());
+                    BufferUtil.putDecLong(header, content_length);
+                    header.put(HttpTokens.CRLF);
+                }
+                break;
+
+            case NO_CONTENT:
+                if (response!=null && status >= 200 && status != 204 && status != 304)
+                    header.put(CONTENT_LENGTH_0);
+                break;
+
+            case EOF_CONTENT:
+                _persistent = request!=null;
+                break;
+
+            case CHUNKED_CONTENT:
+                break;
+
+            default:
+                break;
+        }
+
+        // Add transfer_encoding if needed
+        if (isChunking())
+        {
+            // try to use user supplied encoding as it may have other values.
+            if (transfer_encoding != null && !HttpHeaderValue.CHUNKED.toString().equalsIgnoreCase(transfer_encoding.getValue()))
+            {
+                String c = transfer_encoding.getValue();
+                if (c.endsWith(HttpHeaderValue.CHUNKED.toString()))
+                    putTo(transfer_encoding,header);
+                else
+                    throw new IllegalArgumentException("BAD TE");
+            }
+            else
+                header.put(TRANSFER_ENCODING_CHUNKED);
+        }
+
+        // Handle connection if need be
+        if (_endOfContent==EndOfContent.EOF_CONTENT)
+        {
+            keep_alive=false;
+            _persistent=false;
+        }
+
+        // If this is a response, work out persistence
+        if (response!=null)
+        {
+            if (!isPersistent() && (close || _info.getHttpVersion().ordinal() > HttpVersion.HTTP_1_0.ordinal()))
+            {
+                if (connection==null)
+                    header.put(CONNECTION_CLOSE);
+                else
+                {
+                    header.put(CONNECTION_CLOSE,0,CONNECTION_CLOSE.length-2);
+                    header.put((byte)',');
+                    header.put(StringUtil.getBytes(connection.toString()));
+                    header.put(CRLF);
+                }
+            }
+            else if (keep_alive)
+            {
+                if (connection==null)
+                    header.put(CONNECTION_KEEP_ALIVE);
+                else
+                {
+                    header.put(CONNECTION_KEEP_ALIVE,0,CONNECTION_KEEP_ALIVE.length-2);
+                    header.put((byte)',');
+                    header.put(StringUtil.getBytes(connection.toString()));
+                    header.put(CRLF);
+                }
+            }
+            else if (connection!=null)
+            {
+                header.put(HttpHeader.CONNECTION.getBytesColonSpace());
+                header.put(StringUtil.getBytes(connection.toString()));
+                header.put(CRLF);
+            }
+        }
+
+        if (status>199)
+            header.put(SEND[send]);
+
+        // end the header.
+        header.put(HttpTokens.CRLF);
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    public static byte[] getReasonBuffer(int code)
+    {
+        PreparedResponse status = code<__preprepared.length?__preprepared[code]:null;
+        if (status!=null)
+            return status._reason;
+        return null;
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    @Override
+    public String toString()
+    {
+        return String.format("%s{s=%s}",
+                getClass().getSimpleName(),
+                _state);
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    /* ------------------------------------------------------------------------------- */
+    /* ------------------------------------------------------------------------------- */
+    // common _content
+    private static final byte[] LAST_CHUNK =    { (byte) '0', (byte) '\015', (byte) '\012', (byte) '\015', (byte) '\012'};
+    private static final byte[] CONTENT_LENGTH_0 = StringUtil.getBytes("Content-Length: 0\015\012");
+    private static final byte[] CONNECTION_KEEP_ALIVE = StringUtil.getBytes("Connection: keep-alive\015\012");
+    private static final byte[] CONNECTION_CLOSE = StringUtil.getBytes("Connection: close\015\012");
+    private static final byte[] HTTP_1_1_SPACE = StringUtil.getBytes(HttpVersion.HTTP_1_1+" ");
+    private static final byte[] CRLF = StringUtil.getBytes("\015\012");
+    private static final byte[] TRANSFER_ENCODING_CHUNKED = StringUtil.getBytes("Transfer-Encoding: chunked\015\012");
+    private static final byte[][] SEND = new byte[][]{
+            new byte[0],
+            StringUtil.getBytes("Server: Jetty(9.x.x)\015\012"),
+        StringUtil.getBytes("X-Powered-By: Jetty(9.x.x)\015\012"),
+        StringUtil.getBytes("Server: Jetty(9.x.x)\015\012X-Powered-By: Jetty(9.x.x)\015\012")
+    };
+
+    /* ------------------------------------------------------------------------------- */
+    /* ------------------------------------------------------------------------------- */
+    /* ------------------------------------------------------------------------------- */
+    // Build cache of response lines for status
+    private static class PreparedResponse
+    {
+        byte[] _reason;
+        byte[] _schemeCode;
+        byte[] _responseLine;
+    }
+    private static final PreparedResponse[] __preprepared = new PreparedResponse[HttpStatus.MAX_CODE+1];
+    static
+    {
+        int versionLength=HttpVersion.HTTP_1_1.toString().length();
+
+        for (int i=0;i<__preprepared.length;i++)
+        {
+            HttpStatus.Code code = HttpStatus.getCode(i);
+            if (code==null)
+                continue;
+            String reason=code.getMessage();
+            byte[] line=new byte[versionLength+5+reason.length()+2];
+            HttpVersion.HTTP_1_1.toBuffer().get(line,0,versionLength);
+            line[versionLength+0]=' ';
+            line[versionLength+1]=(byte)('0'+i/100);
+            line[versionLength+2]=(byte)('0'+(i%100)/10);
+            line[versionLength+3]=(byte)('0'+(i%10));
+            line[versionLength+4]=' ';
+            for (int j=0;j<reason.length();j++)
+                line[versionLength+5+j]=(byte)reason.charAt(j);
+            line[versionLength+5+reason.length()]=HttpTokens.CARRIAGE_RETURN;
+            line[versionLength+6+reason.length()]=HttpTokens.LINE_FEED;
+
+            __preprepared[i] = new PreparedResponse();
+            __preprepared[i]._schemeCode = Arrays.copyOfRange(line, 0,versionLength+5);
+            __preprepared[i]._reason = Arrays.copyOfRange(line, versionLength+5, line.length-2);
+            __preprepared[i]._responseLine=line;
+        }
+    }
+
+    public static class Info
+    {
+        final HttpVersion _httpVersion;
+        final HttpFields _httpFields;
+        final long _contentLength;
+
+        private Info(HttpVersion httpVersion, HttpFields httpFields, long contentLength)
+        {
+            _httpVersion = httpVersion;
+            _httpFields = httpFields;
+            _contentLength = contentLength;
+        }
+
+        public HttpVersion getHttpVersion()
+        {
+            return _httpVersion;
+        }
+        public HttpFields getHttpFields()
+        {
+            return _httpFields;
+        }
+        public long getContentLength()
+        {
+            return _contentLength;
+        }
+    }
+
+    public static class RequestInfo extends Info
+    {
+        private final String _method;
+        private final String _uri;
+
+        public RequestInfo(HttpVersion httpVersion, HttpFields httpFields, long contentLength, String method, String uri)
+        {
+            super(httpVersion,httpFields,contentLength);
+            _method = method;
+            _uri = uri;
+        }
+
+        public String getMethod()
+        {
+            return _method;
+        }
+
+        public String getUri()
+        {
+            return _uri;
+        }
+
+        @Override
+        public String toString()
+        {
+            return String.format("RequestInfo{%s %s %s,%d}",_method,_uri,_httpVersion,_contentLength);
+        }
+    }
+
+    public static class ResponseInfo extends Info
+    {
+        private final int _status;
+        private final String _reason;
+        private final boolean _head;
+
+        public ResponseInfo(HttpVersion httpVersion, HttpFields httpFields, long contentLength, int status, String reason, boolean head)
+        {
+            super(httpVersion,httpFields,contentLength);
+            _status = status;
+            _reason = reason;
+            _head = head;
+        }
+
+        public boolean isInformational()
+        {
+            return _status>=100 && _status<200;
+        }
+
+        public int getStatus()
+        {
+            return _status;
+        }
+
+        public String getReason()
+        {
+            return _reason;
+        }
+
+        public boolean isHead()
+        {
+            return _head;
+        }
+
+        @Override
+        public String toString()
+        {
+            return String.format("ResponseInfo{%s %s %s,%d,%b}",_httpVersion,_status,_reason,_contentLength,_head);
+        }
+    } 
+
+    private static void putSanitisedName(String s,ByteBuffer buffer)
+    {
+        int l=s.length();
+        for (int i=0;i<l;i++)
+        {
+            char c=s.charAt(i);
+            
+            if (c<0 || c>0xff || c=='\r' || c=='\n'|| c==':')
+                buffer.put((byte)'?');
+            else
+                buffer.put((byte)(0xff&c));
+        }
+    }
+
+    private static void putSanitisedValue(String s,ByteBuffer buffer)
+    {
+        int l=s.length();
+        for (int i=0;i<l;i++)
+        {
+            char c=s.charAt(i);
+            
+            if (c<0 || c>0xff || c=='\r' || c=='\n')
+                buffer.put((byte)'?');
+            else
+                buffer.put((byte)(0xff&c));
+        }
+    }
+
+    public static void putTo(HttpField field, ByteBuffer bufferInFillMode)
+    {
+        if (field instanceof CachedHttpField)
+        {
+            ((CachedHttpField)field).putTo(bufferInFillMode);
+        }
+        else
+        {
+            HttpHeader header=field.getHeader();
+            if (header!=null)
+            {
+                bufferInFillMode.put(header.getBytesColonSpace());
+                putSanitisedValue(field.getValue(),bufferInFillMode);
+            }
+            else
+            {
+                putSanitisedName(field.getName(),bufferInFillMode);
+                bufferInFillMode.put(__colon_space);
+                putSanitisedValue(field.getValue(),bufferInFillMode);
+            }
+
+            BufferUtil.putCRLF(bufferInFillMode);
+        }
+    }
+
+    public static void putTo(HttpFields fields, ByteBuffer bufferInFillMode) 
+    {
+        for (HttpField field : fields)
+        {
+            if (field != null)
+                putTo(field,bufferInFillMode);
+        }
+        BufferUtil.putCRLF(bufferInFillMode);
+    }
+    
+    public static class CachedHttpField extends HttpField
+    {
+        private final byte[] _bytes;
+        public CachedHttpField(HttpHeader header,String value)
+        {
+            super(header,value);
+            int cbl=header.getBytesColonSpace().length;
+            _bytes=Arrays.copyOf(header.getBytesColonSpace(), cbl+value.length()+2);
+            System.arraycopy(value.getBytes(StandardCharsets.ISO_8859_1),0,_bytes,cbl,value.length());
+            _bytes[_bytes.length-2]=(byte)'\r';
+            _bytes[_bytes.length-1]=(byte)'\n';
+        }
+        
+        public void putTo(ByteBuffer bufferInFillMode)
+        {
+            bufferInFillMode.put(_bytes);
+        }
+    }
+}
diff --git a/lib/jetty/org/eclipse/jetty/http/HttpHeader.java b/lib/jetty/org/eclipse/jetty/http/HttpHeader.java
new file mode 100644 (file)
index 0000000..ab0ddcf
--- /dev/null
@@ -0,0 +1,178 @@
+//
+//  ========================================================================
+//  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.http;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.util.ArrayTrie;
+import org.eclipse.jetty.util.StringUtil;
+import org.eclipse.jetty.util.Trie;
+
+
+public enum HttpHeader
+{
+    /* ------------------------------------------------------------ */
+    /** General Fields.
+     */
+    CONNECTION("Connection"),
+    CACHE_CONTROL("Cache-Control"),
+    DATE("Date"),
+    PRAGMA("Pragma"),
+    PROXY_CONNECTION ("Proxy-Connection"),
+    TRAILER("Trailer"),
+    TRANSFER_ENCODING("Transfer-Encoding"),
+    UPGRADE("Upgrade"),
+    VIA("Via"),
+    WARNING("Warning"),
+    NEGOTIATE("Negotiate"),
+
+    /* ------------------------------------------------------------ */
+    /** Entity Fields.
+     */
+    ALLOW("Allow"),
+    CONTENT_ENCODING("Content-Encoding"),
+    CONTENT_LANGUAGE("Content-Language"),
+    CONTENT_LENGTH("Content-Length"),
+    CONTENT_LOCATION("Content-Location"),
+    CONTENT_MD5("Content-MD5"),
+    CONTENT_RANGE("Content-Range"),
+    CONTENT_TYPE("Content-Type"),
+    EXPIRES("Expires"),
+    LAST_MODIFIED("Last-Modified"),
+
+    /* ------------------------------------------------------------ */
+    /** Request Fields.
+     */
+    ACCEPT("Accept"),
+    ACCEPT_CHARSET("Accept-Charset"),
+    ACCEPT_ENCODING("Accept-Encoding"),
+    ACCEPT_LANGUAGE("Accept-Language"),
+    AUTHORIZATION("Authorization"),
+    EXPECT("Expect"),
+    FORWARDED("Forwarded"),
+    FROM("From"),
+    HOST("Host"),
+    IF_MATCH("If-Match"),
+    IF_MODIFIED_SINCE("If-Modified-Since"),
+    IF_NONE_MATCH("If-None-Match"),
+    IF_RANGE("If-Range"),
+    IF_UNMODIFIED_SINCE("If-Unmodified-Since"),
+    KEEP_ALIVE("Keep-Alive"),
+    MAX_FORWARDS("Max-Forwards"),
+    PROXY_AUTHORIZATION("Proxy-Authorization"),
+    RANGE("Range"),
+    REQUEST_RANGE("Request-Range"),
+    REFERER("Referer"),
+    TE("TE"),
+    USER_AGENT("User-Agent"),
+    X_FORWARDED_FOR("X-Forwarded-For"),
+    X_FORWARDED_PROTO("X-Forwarded-Proto"),
+    X_FORWARDED_SERVER("X-Forwarded-Server"),
+    X_FORWARDED_HOST("X-Forwarded-Host"),
+
+    /* ------------------------------------------------------------ */
+    /** Response Fields.
+     */
+    ACCEPT_RANGES("Accept-Ranges"),
+    AGE("Age"),
+    ETAG("ETag"),
+    LOCATION("Location"),
+    PROXY_AUTHENTICATE("Proxy-Authenticate"),
+    RETRY_AFTER("Retry-After"),
+    SERVER("Server"),
+    SERVLET_ENGINE("Servlet-Engine"),
+    VARY("Vary"),
+    WWW_AUTHENTICATE("WWW-Authenticate"),
+
+    /* ------------------------------------------------------------ */
+    /** Other Fields.
+     */
+    COOKIE("Cookie"),
+    SET_COOKIE("Set-Cookie"),
+    SET_COOKIE2("Set-Cookie2"),
+    MIME_VERSION("MIME-Version"),
+    IDENTITY("identity"),
+    
+    X_POWERED_BY("X-Powered-By"),
+
+    UNKNOWN("::UNKNOWN::");
+
+
+    /* ------------------------------------------------------------ */
+    public final static Trie<HttpHeader> CACHE= new ArrayTrie<>(512);
+    static
+    {
+        for (HttpHeader header : HttpHeader.values())
+            if (header!=UNKNOWN)
+                CACHE.put(header.toString(),header);
+    }
+    
+    private final String _string;
+    private final byte[] _bytes;
+    private final byte[] _bytesColonSpace;
+    private final ByteBuffer _buffer;
+
+    /* ------------------------------------------------------------ */
+    HttpHeader(String s)
+    {
+        _string=s;
+        _bytes=StringUtil.getBytes(s);
+        _bytesColonSpace=StringUtil.getBytes(s+": ");
+        _buffer=ByteBuffer.wrap(_bytes);
+    }
+
+    /* ------------------------------------------------------------ */
+    public ByteBuffer toBuffer()
+    {
+        return _buffer.asReadOnlyBuffer();
+    }
+
+    /* ------------------------------------------------------------ */
+    public byte[] getBytes()
+    {
+        return _bytes;
+    }
+
+    /* ------------------------------------------------------------ */
+    public byte[] getBytesColonSpace()
+    {
+        return _bytesColonSpace;
+    }
+
+    /* ------------------------------------------------------------ */
+    public boolean is(String s)
+    {
+        return _string.equalsIgnoreCase(s);    
+    }
+
+    /* ------------------------------------------------------------ */
+    public String asString()
+    {
+        return _string;
+    }
+    
+    /* ------------------------------------------------------------ */
+    @Override
+    public String toString()
+    {
+        return _string;
+    }
+    
+}
+
diff --git a/lib/jetty/org/eclipse/jetty/http/HttpHeaderValue.java b/lib/jetty/org/eclipse/jetty/http/HttpHeaderValue.java
new file mode 100644 (file)
index 0000000..8338a32
--- /dev/null
@@ -0,0 +1,104 @@
+//
+//  ========================================================================
+//  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.http;
+
+import java.nio.ByteBuffer;
+import java.util.EnumSet;
+
+import org.eclipse.jetty.util.ArrayTrie;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.Trie;
+
+
+/**
+ * 
+ */
+public enum HttpHeaderValue
+{
+    CLOSE("close"),
+    CHUNKED("chunked"),
+    GZIP("gzip"),
+    IDENTITY("identity"),
+    KEEP_ALIVE("keep-alive"),
+    CONTINUE("100-continue"),
+    PROCESSING("102-processing"),
+    TE("TE"),
+    BYTES("bytes"),
+    NO_CACHE("no-cache"),
+    UPGRADE("Upgrade"),
+    UNKNOWN("::UNKNOWN::");
+
+    /* ------------------------------------------------------------ */
+    public final static Trie<HttpHeaderValue> CACHE= new ArrayTrie<HttpHeaderValue>();
+    static
+    {
+        for (HttpHeaderValue value : HttpHeaderValue.values())
+            if (value!=UNKNOWN)
+                CACHE.put(value.toString(),value);
+    }
+
+    private final String _string;
+    private final ByteBuffer _buffer;
+
+    /* ------------------------------------------------------------ */
+    HttpHeaderValue(String s)
+    {
+        _string=s;
+        _buffer=BufferUtil.toBuffer(s);
+    }
+
+    /* ------------------------------------------------------------ */
+    public ByteBuffer toBuffer()
+    {
+        return _buffer.asReadOnlyBuffer();
+    }
+
+    /* ------------------------------------------------------------ */
+    public boolean is(String s)
+    {
+        return _string.equalsIgnoreCase(s);
+    }
+    
+    /* ------------------------------------------------------------ */
+    public String asString()
+    {
+        return _string;
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public String toString()
+    {
+        return _string;
+    }
+
+    /* ------------------------------------------------------------ */
+    private static EnumSet<HttpHeader> __known =
+            EnumSet.of(HttpHeader.CONNECTION,
+                    HttpHeader.TRANSFER_ENCODING,
+                    HttpHeader.CONTENT_ENCODING);
+
+    /* ------------------------------------------------------------ */
+    public static boolean hasKnownValues(HttpHeader header)
+    {
+        if (header==null)
+            return false;
+        return __known.contains(header);
+    }
+}
diff --git a/lib/jetty/org/eclipse/jetty/http/HttpMethod.java b/lib/jetty/org/eclipse/jetty/http/HttpMethod.java
new file mode 100644 (file)
index 0000000..8a26268
--- /dev/null
@@ -0,0 +1,174 @@
+//
+//  ========================================================================
+//  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.http;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.util.ArrayTrie;
+import org.eclipse.jetty.util.StringUtil;
+import org.eclipse.jetty.util.Trie;
+
+
+/* ------------------------------------------------------------------------------- */
+/**
+ */
+public enum HttpMethod
+{
+    GET,
+    POST,
+    HEAD,
+    PUT,
+    OPTIONS,
+    DELETE,
+    TRACE,
+    CONNECT,
+    MOVE,
+    PROXY;
+
+    /* ------------------------------------------------------------ */
+    /**
+     * Optimised 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
+     * @return A HttpMethod if a match or null if no easy match.
+     */
+    public static HttpMethod lookAheadGet(byte[] bytes, final int position, int limit)
+    {
+        int length=limit-position;
+        if (length<4)
+            return null;
+        switch(bytes[position])
+        {
+            case 'G':
+                if (bytes[position+1]=='E' && bytes[position+2]=='T' && bytes[position+3]==' ')
+                    return GET;
+                break;
+            case 'P':
+                if (bytes[position+1]=='O' && bytes[position+2]=='S' && bytes[position+3]=='T' && length>=5 && bytes[position+4]==' ')
+                    return POST;
+                if (bytes[position+1]=='R' && bytes[position+2]=='O' && bytes[position+3]=='X' && length>=6 && bytes[position+4]=='Y' && bytes[position+5]==' ')
+                    return PROXY;
+                if (bytes[position+1]=='U' && bytes[position+2]=='T' && bytes[position+3]==' ')
+                    return PUT;
+                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]==' ' )
+                    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]==' ' )
+                    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]==' ' )
+                    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]==' ' )
+                    return CONNECT;
+                break;
+            case 'M':
+                if (bytes[position+1]=='O' && bytes[position+2]=='V' && bytes[position+3]=='E' &&  bytes[position+4]==' ')
+                    return MOVE;
+                break;
+
+            default:
+                break;
+        }
+        return null;
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * Optimised lookup to find a method name and trailing space in a byte array.
+     * @param buffer buffer containing ISO-8859-1 characters
+     * @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());
+        return null;
+    }
+
+    /* ------------------------------------------------------------ */
+    public final static Trie<HttpMethod> CACHE= new ArrayTrie<>();
+    static
+    {
+        for (HttpMethod method : HttpMethod.values())
+            CACHE.put(method.toString(),method);
+    }
+
+    /* ------------------------------------------------------------ */
+    private final ByteBuffer _buffer;
+    private final byte[] _bytes;
+
+    /* ------------------------------------------------------------ */
+    HttpMethod()
+    {
+        _bytes=StringUtil.getBytes(toString());
+        _buffer=ByteBuffer.wrap(_bytes);
+    }
+
+    /* ------------------------------------------------------------ */
+    public byte[] getBytes()
+    {
+        return _bytes;
+    }
+
+    /* ------------------------------------------------------------ */
+    public boolean is(String s)
+    {
+        return toString().equalsIgnoreCase(s);
+    }
+
+    /* ------------------------------------------------------------ */
+    public ByteBuffer asBuffer()
+    {
+        return _buffer.asReadOnlyBuffer();
+    }
+
+    /* ------------------------------------------------------------ */
+    public String asString()
+    {
+        return toString();
+    }
+
+    /**
+     * Converts the given String parameter to an HttpMethod
+     * @param method the String to get the equivalent HttpMethod from
+     * @return the HttpMethod or null if the parameter method is unknown
+     */
+    public static HttpMethod fromString(String method)
+    {
+        return CACHE.get(method);
+    }
+}
diff --git a/lib/jetty/org/eclipse/jetty/http/HttpParser.java b/lib/jetty/org/eclipse/jetty/http/HttpParser.java
new file mode 100644 (file)
index 0000000..79f1c28
--- /dev/null
@@ -0,0 +1,1688 @@
+//
+//  ========================================================================
+//  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.http;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+
+import org.eclipse.jetty.http.HttpTokens.EndOfContent;
+import org.eclipse.jetty.util.ArrayTernaryTrie;
+import org.eclipse.jetty.util.ArrayTrie;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.StringUtil;
+import org.eclipse.jetty.util.Trie;
+import org.eclipse.jetty.util.TypeUtil;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+
+/* ------------------------------------------------------------ */
+/** A Parser for HTTP 0.9, 1.0 and 1.1
+ * <p>
+ * The is 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.
+ * If the passed handler is a {@link RequestHandler} then server side
+ * parsing is performed and if it is a {@link ResponseHandler}, then 
+ * client side parsing is done.
+ * </p>
+ * <p>
+ * The contract of the {@link HttpHandler} API is that if a call returns 
+ * true then the call to {@link #parseNext(ByteBuffer)} will return as 
+ * soon as possible also with a true response.  Typically this indicates
+ * that the parsing has reached a stage where the caller should process 
+ * the events accumulated by the handler.    It is the preferred calling
+ * style that handling such as calling a servlet to process a request, 
+ * should be done after a true return from {@link #parseNext(ByteBuffer)}
+ * rather than from within the scope of a call like 
+ * {@link RequestHandler#messageComplete()}
+ * </p>
+ * <p>
+ * For performance, the parse is heavily dependent on the 
+ * {@link Trie#getBest(ByteBuffer, int, int)} method to look ahead in a
+ * single pass for both the structure ( : and CRLF ) and semantic (which
+ * header and value) of a header.  Specifically the static {@link HttpHeader#CACHE}
+ * is used to lookup common combinations of headers and values 
+ * (eg. "Connection: close"), or just header names (eg. "Connection:" ).
+ * For headers who's value is not known statically (eg. Host, COOKIE) then a
+ * per parser dynamic Trie of {@link HttpFields} from previous parsed messages
+ * is used to help the parsing of subsequent messages.
+ * </p>
+ * <p>
+ * If the system property "org.eclipse.jetty.http.HttpParser.STRICT" is set to true,
+ * then the parser will strictly pass on the exact strings received for methods and header
+ * fields.  Otherwise a fast case insensitive string lookup is used that may alter the
+ * case of the method and/or headers
+ * </p>
+ */
+public class HttpParser
+{
+    public static final Logger LOG = Log.getLogger(HttpParser.class);
+    public final static boolean __STRICT=Boolean.getBoolean("org.eclipse.jetty.http.HttpParser.STRICT"); 
+    public final static int INITIAL_URI_LENGTH=256;
+
+    /**
+     * Cache of common {@link HttpField}s including: <UL>
+     * <LI>Common static combinations such as:<UL>
+     *   <li>Connection: close
+     *   <li>Accept-Encoding: gzip
+     *   <li>Content-Length: 0
+     * </ul>
+     * <li>Combinations of Content-Type header for common mime types by common charsets
+     * <li>Most common headers with null values so that a lookup will at least
+     * determine the header name even if the name:value combination is not cached
+     * </ul>
+     */
+    public final static Trie<HttpField> CACHE = new ArrayTrie<>(2048);
+    
+    // States
+    public enum State
+    {
+        START,
+        METHOD,
+        RESPONSE_VERSION,
+        SPACE1,
+        STATUS,
+        URI,
+        SPACE2,
+        REQUEST_VERSION,
+        REASON,
+        PROXY,
+        HEADER,
+        HEADER_IN_NAME,
+        HEADER_VALUE,
+        HEADER_IN_VALUE,
+        CONTENT,
+        EOF_CONTENT,
+        CHUNKED_CONTENT,
+        CHUNK_SIZE,
+        CHUNK_PARAMS,
+        CHUNK,
+        END,
+        CLOSED
+    }
+
+    private final boolean DEBUG=LOG.isDebugEnabled(); // Cache debug to help branch prediction
+    private final HttpHandler<ByteBuffer> _handler;
+    private final RequestHandler<ByteBuffer> _requestHandler;
+    private final ResponseHandler<ByteBuffer> _responseHandler;
+    private final int _maxHeaderBytes;
+    private final boolean _strict;
+    private HttpField _field;
+    private HttpHeader _header;
+    private String _headerString;
+    private HttpHeaderValue _value;
+    private String _valueString;
+    private int _responseStatus;
+    private int _headerBytes;
+    private boolean _host;
+
+    /* ------------------------------------------------------------------------------- */
+    private volatile State _state=State.START;
+    private volatile boolean _eof;
+    private volatile boolean _closed;
+    private HttpMethod _method;
+    private String _methodString;
+    private HttpVersion _version;
+    private ByteBuffer _uri=ByteBuffer.allocate(INITIAL_URI_LENGTH); // Tune?
+    private EndOfContent _endOfContent;
+    private long _contentLength;
+    private long _contentPosition;
+    private int _chunkLength;
+    private int _chunkPosition;
+    private boolean _headResponse;
+    private boolean _cr;
+    private ByteBuffer _contentChunk;
+    private Trie<HttpField> _connectionFields;
+
+    private int _length;
+    private final StringBuilder _string=new StringBuilder();
+
+    static
+    {
+        CACHE.put(new HttpField(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE));
+        CACHE.put(new HttpField(HttpHeader.CONNECTION,HttpHeaderValue.KEEP_ALIVE));
+        CACHE.put(new HttpField(HttpHeader.CONNECTION,HttpHeaderValue.UPGRADE));
+        CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING,"gzip"));
+        CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING,"gzip, deflate"));
+        CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING,"gzip,deflate,sdch"));
+        CACHE.put(new HttpField(HttpHeader.ACCEPT_LANGUAGE,"en-US,en;q=0.5"));
+        CACHE.put(new HttpField(HttpHeader.ACCEPT_LANGUAGE,"en-GB,en-US;q=0.8,en;q=0.6"));
+        CACHE.put(new HttpField(HttpHeader.ACCEPT_CHARSET,"ISO-8859-1,utf-8;q=0.7,*;q=0.3"));
+        CACHE.put(new HttpField(HttpHeader.ACCEPT,"*/*"));
+        CACHE.put(new HttpField(HttpHeader.ACCEPT,"image/png,image/*;q=0.8,*/*;q=0.5"));
+        CACHE.put(new HttpField(HttpHeader.ACCEPT,"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"));
+        CACHE.put(new HttpField(HttpHeader.PRAGMA,"no-cache"));
+        CACHE.put(new HttpField(HttpHeader.CACHE_CONTROL,"private, no-cache, no-cache=Set-Cookie, proxy-revalidate"));
+        CACHE.put(new HttpField(HttpHeader.CACHE_CONTROL,"no-cache"));
+        CACHE.put(new HttpField(HttpHeader.CONTENT_LENGTH,"0"));
+        CACHE.put(new HttpField(HttpHeader.CONTENT_ENCODING,"gzip"));
+        CACHE.put(new HttpField(HttpHeader.CONTENT_ENCODING,"deflate"));
+        CACHE.put(new HttpField(HttpHeader.TRANSFER_ENCODING,"chunked"));
+        CACHE.put(new HttpField(HttpHeader.EXPIRES,"Fri, 01 Jan 1990 00:00:00 GMT"));
+        
+        // Add common Content types as fields
+        for (String type : new String[]{"text/plain","text/html","text/xml","text/json","application/json","application/x-www-form-urlencoded"})
+        {
+            HttpField field=new HttpGenerator.CachedHttpField(HttpHeader.CONTENT_TYPE,type);
+            CACHE.put(field);
+            
+            for (String charset : new String[]{"UTF-8","ISO-8859-1"})
+            {
+                CACHE.put(new HttpGenerator.CachedHttpField(HttpHeader.CONTENT_TYPE,type+";charset="+charset));
+                CACHE.put(new HttpGenerator.CachedHttpField(HttpHeader.CONTENT_TYPE,type+"; charset="+charset));
+            }
+        }
+    
+        // Add headers with null values so HttpParser can avoid looking up name again for unknown values
+        for (HttpHeader h:HttpHeader.values())
+            if (!CACHE.put(new HttpField(h,(String)null)))
+                throw new IllegalStateException("CACHE FULL");
+        // Add some more common headers
+        CACHE.put(new HttpField(HttpHeader.REFERER,(String)null));
+        CACHE.put(new HttpField(HttpHeader.IF_MODIFIED_SINCE,(String)null));
+        CACHE.put(new HttpField(HttpHeader.IF_NONE_MATCH,(String)null));
+        CACHE.put(new HttpField(HttpHeader.AUTHORIZATION,(String)null));
+        CACHE.put(new HttpField(HttpHeader.COOKIE,(String)null));
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    public HttpParser(RequestHandler<ByteBuffer> handler)
+    {
+        this(handler,-1,__STRICT);
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    public HttpParser(ResponseHandler<ByteBuffer> handler)
+    {
+        this(handler,-1,__STRICT);
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    public HttpParser(RequestHandler<ByteBuffer> handler,int maxHeaderBytes)
+    {
+        this(handler,maxHeaderBytes,__STRICT);
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    public HttpParser(ResponseHandler<ByteBuffer> handler,int maxHeaderBytes)
+    {
+        this(handler,maxHeaderBytes,__STRICT);
+    }
+    
+    /* ------------------------------------------------------------------------------- */
+    public HttpParser(RequestHandler<ByteBuffer> handler,int maxHeaderBytes,boolean strict)
+    {
+        _handler=handler;
+        _requestHandler=handler;
+        _responseHandler=null;
+        _maxHeaderBytes=maxHeaderBytes;
+        _strict=strict;
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    public HttpParser(ResponseHandler<ByteBuffer> handler,int maxHeaderBytes,boolean strict)
+    {
+        _handler=handler;
+        _requestHandler=null;
+        _responseHandler=handler;
+        _maxHeaderBytes=maxHeaderBytes;
+        _strict=strict;
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    public long getContentLength()
+    {
+        return _contentLength;
+    }
+
+    /* ------------------------------------------------------------ */
+    public long getContentRead()
+    {
+        return _contentPosition;
+    }
+
+    /* ------------------------------------------------------------ */
+    /** Set if a HEAD response is expected
+     * @param head
+     */
+    public void setHeadResponse(boolean head)
+    {
+        _headResponse=head;
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    protected void setResponseStatus(int status)
+    {
+        _responseStatus=status;
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    public State getState()
+    {
+        return _state;
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    public boolean inContentState()
+    {
+        return _state.ordinal()>=State.CONTENT.ordinal() && _state.ordinal()<State.END.ordinal();
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    public boolean inHeaderState()
+    {
+        return _state.ordinal() < State.CONTENT.ordinal();
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    public boolean isChunking()
+    {
+        return _endOfContent==EndOfContent.CHUNKED_CONTENT;
+    }
+
+    /* ------------------------------------------------------------ */
+    public boolean isStart()
+    {
+        return isState(State.START);
+    }
+
+    /* ------------------------------------------------------------ */
+    public boolean isClosed()
+    {
+        return isState(State.CLOSED);
+    }
+
+    /* ------------------------------------------------------------ */
+    public boolean isIdle()
+    {
+        return isState(State.START)||isState(State.END)||isState(State.CLOSED);
+    }
+
+    /* ------------------------------------------------------------ */
+    public boolean isComplete()
+    {
+        return isState(State.END)||isState(State.CLOSED);
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    public boolean isState(State state)
+    {
+        return _state == state;
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    private static class BadMessage extends Error
+    {
+        private static final long serialVersionUID = 1L;
+        private final int _code;
+        private final String _message;
+
+        BadMessage()
+        {
+            this(400,null);
+        }
+        
+        BadMessage(int code)
+        {
+            this(code,null);
+        }
+        
+        BadMessage(String message)
+        {
+            this(400,message);
+        }
+        
+        BadMessage(int code,String message)
+        {
+            _code=code;
+            _message=message;
+        }
+        
+    }
+    
+    /* ------------------------------------------------------------------------------- */
+    private byte next(ByteBuffer buffer)
+    {
+        byte ch = buffer.get();
+        
+        if (_cr)
+        {
+            if (ch!=HttpTokens.LINE_FEED)
+                throw new BadMessage("Bad EOL");
+            _cr=false;
+            return ch;
+        }
+
+        if (ch>=0 && ch<HttpTokens.SPACE)
+        {
+            if (ch==HttpTokens.CARRIAGE_RETURN)
+            {
+                if (buffer.hasRemaining())
+                {
+                    if(_maxHeaderBytes>0 && _state.ordinal()<State.END.ordinal())
+                        _headerBytes++;
+                    ch=buffer.get();
+                    if (ch!=HttpTokens.LINE_FEED)
+                        throw new BadMessage("Bad EOL");
+                }
+                else
+                {
+                    _cr=true;
+                    // Can return 0 here to indicate the need for more characters, 
+                    // because a real 0 in the buffer would cause a BadMessage below 
+                    return 0;
+                }
+            }
+            // Only LF or TAB acceptable special characters
+            else if (!(ch==HttpTokens.LINE_FEED || ch==HttpTokens.TAB))
+                throw new BadMessage("Illegal character");
+        }
+        
+        return ch;
+    }
+    
+    /* ------------------------------------------------------------------------------- */
+    /* Quick lookahead for the start state looking for a request method or a HTTP version,
+     * otherwise skip white space until something else to parse.
+     */
+    private boolean quickStart(ByteBuffer buffer)
+    {          
+        if (_requestHandler!=null)
+        {
+            _method = HttpMethod.lookAheadGet(buffer);
+            if (_method!=null)
+            {
+                _methodString = _method.asString();
+                buffer.position(buffer.position()+_methodString.length()+1);
+                
+                setState(State.SPACE1);
+                return false;
+            }
+        }
+        else if (_responseHandler!=null)
+        {
+            _version = HttpVersion.lookAheadGet(buffer);
+            if (_version!=null)
+            {
+                buffer.position(buffer.position()+_version.asString().length()+1);
+                setState(State.SPACE1);
+                return false;
+            }
+        }
+        
+        // Quick start look
+        while (_state==State.START && buffer.hasRemaining())
+        {
+            int ch=next(buffer);
+
+            if (ch > HttpTokens.SPACE)
+            {
+                _string.setLength(0);
+                _string.append((char)ch);
+                setState(_requestHandler!=null?State.METHOD:State.RESPONSE_VERSION);
+                return false;
+            }
+            else if (ch==0)
+                break;
+            else if (ch<0)
+                throw new BadMessage();
+            
+            // 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);
+            }
+        }
+        return false;
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    private void setString(String s)
+    {
+        _string.setLength(0);
+        _string.append(s);
+        _length=s.length();
+    }
+    
+    /* ------------------------------------------------------------------------------- */
+    private String takeString()
+    {
+        _string.setLength(_length);
+        String s =_string.toString();
+        _string.setLength(0);
+        _length=-1;
+        return s;
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    /* Parse a request or response line
+     */
+    private boolean parseLine(ByteBuffer buffer)
+    {
+        boolean handle=false;
+
+        // Process headers
+        while (_state.ordinal()<State.HEADER.ordinal() && buffer.hasRemaining() && !handle)
+        {
+            // process each character
+            byte ch=next(buffer);
+            if (ch==0)
+                break;
+
+            if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes)
+            {
+                if (_state==State.URI)
+                {
+                    LOG.warn("URI is too large >"+_maxHeaderBytes);
+                    throw new BadMessage(HttpStatus.REQUEST_URI_TOO_LONG_414);
+                }
+                else
+                {
+                    if (_requestHandler!=null)
+                        LOG.warn("request is too large >"+_maxHeaderBytes);
+                    else
+                        LOG.warn("response is too large >"+_maxHeaderBytes);
+                    throw new BadMessage(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413);
+                }
+            }
+
+            switch (_state)
+            {
+                case METHOD:
+                    if (ch == HttpTokens.SPACE)
+                    {
+                        _length=_string.length();
+                        _methodString=takeString();
+                        HttpMethod method=HttpMethod.CACHE.get(_methodString);
+                        if (method!=null && !_strict)
+                            _methodString=method.asString();
+                        setState(State.SPACE1);
+                    }
+                    else if (ch < HttpTokens.SPACE)
+                        throw new BadMessage(ch<0?"Illegal character":"No URI");
+                    else
+                        _string.append((char)ch);
+                    break;
+
+                case RESPONSE_VERSION:
+                    if (ch == HttpTokens.SPACE)
+                    {
+                        _length=_string.length();
+                        String version=takeString();
+                        _version=HttpVersion.CACHE.get(version);
+                        if (_version==null)
+                            throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Unknown Version");
+                        setState(State.SPACE1);
+                    }
+                    else if (ch < HttpTokens.SPACE)
+                        throw new BadMessage(ch<0?"Illegal character":"No Status");
+                    else
+                        _string.append((char)ch);
+                    break;
+
+                case SPACE1:
+                    if (ch > HttpTokens.SPACE || ch<0)
+                    {
+                        if (_responseHandler!=null)
+                        {
+                            setState(State.STATUS);
+                            setResponseStatus(ch-'0');
+                        }
+                        else
+                        {
+                            _uri.clear();
+                            setState(State.URI);
+                            // quick scan for space or EoBuffer
+                            if (buffer.hasArray())
+                            {
+                                byte[] array=buffer.array();
+                                int p=buffer.arrayOffset()+buffer.position();
+                                int l=buffer.arrayOffset()+buffer.limit();
+                                int i=p;
+                                while (i<l && array[i]>HttpTokens.SPACE)
+                                    i++;
+
+                                int len=i-p;
+                                _headerBytes+=len;
+                                
+                                if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes)
+                                {
+                                    LOG.warn("URI is too large >"+_maxHeaderBytes);
+                                    throw new BadMessage(HttpStatus.REQUEST_URI_TOO_LONG_414);
+                                }
+                                if (_uri.remaining()<=len)
+                                {
+                                    ByteBuffer uri = ByteBuffer.allocate(_uri.capacity()+2*len);
+                                    _uri.flip();
+                                    uri.put(_uri);
+                                    _uri=uri;
+                                }
+                                _uri.put(array,p-1,len+1);
+                                buffer.position(i-buffer.arrayOffset());
+                            }
+                            else
+                                _uri.put(ch);
+                        }
+                    }
+                    else if (ch < HttpTokens.SPACE)
+                    {
+                        throw new BadMessage(HttpStatus.BAD_REQUEST_400,_requestHandler!=null?"No URI":"No Status");
+                    }
+                    break;
+
+                case STATUS:
+                    if (ch == HttpTokens.SPACE)
+                    {
+                        setState(State.SPACE2);
+                    }
+                    else if (ch>='0' && ch<='9')
+                    {
+                        _responseStatus=_responseStatus*10+(ch-'0');
+                    }
+                    else if (ch < HttpTokens.SPACE && ch>=0)
+                    {
+                        handle=_responseHandler.startResponse(_version, _responseStatus, null)||handle;
+                        setState(State.HEADER);
+                    }
+                    else
+                    {
+                        throw new BadMessage();
+                    }
+                    break;
+
+                case URI:
+                    if (ch == HttpTokens.SPACE)
+                    {
+                        setState(State.SPACE2);
+                    }
+                    else if (ch < HttpTokens.SPACE && ch>=0)
+                    {
+                        // HTTP/0.9
+                        _uri.flip();
+                        handle=_requestHandler.startRequest(_method,_methodString,_uri,null)||handle;
+                        setState(State.END);
+                        BufferUtil.clear(buffer);
+                        handle=_handler.headerComplete()||handle;
+                        handle=_handler.messageComplete()||handle;
+                    }
+                    else
+                    {
+                        if (!_uri.hasRemaining())
+                        {
+                            ByteBuffer uri = ByteBuffer.allocate(_uri.capacity()*2);
+                            _uri.flip();
+                            uri.put(_uri);
+                            _uri=uri;
+                        }
+                        _uri.put(ch);
+                    }
+                    break;
+
+                case SPACE2:
+                    if (ch > HttpTokens.SPACE)
+                    {
+                        _string.setLength(0);
+                        _string.append((char)ch);
+                        if (_responseHandler!=null)
+                        {
+                            _length=1;
+                            setState(State.REASON);
+                        }
+                        else
+                        {
+                            setState(State.REQUEST_VERSION);
+
+                            // try quick look ahead for HTTP Version
+                            HttpVersion version;
+                            if (buffer.position()>0 && buffer.hasArray())
+                                version=HttpVersion.lookAheadGet(buffer.array(),buffer.arrayOffset()+buffer.position()-1,buffer.arrayOffset()+buffer.limit());
+                            else
+                                version=HttpVersion.CACHE.getBest(buffer,0,buffer.remaining());
+                            if (version==null)
+                            {
+                                if (_method==HttpMethod.PROXY)
+                                {
+                                    if (!(_requestHandler instanceof ProxyHandler))
+                                        throw new BadMessage();
+                                    
+                                    _uri.flip();
+                                    String protocol=BufferUtil.toString(_uri);
+                                    // This is the proxy protocol, so we can assume entire first line is in buffer else 400
+                                    buffer.position(buffer.position()-1);
+                                    String sAddr = getProxyField(buffer);
+                                    String dAddr = getProxyField(buffer);
+                                    int sPort = BufferUtil.takeInt(buffer);
+                                    next(buffer);
+                                    int dPort = BufferUtil.takeInt(buffer);
+                                    next(buffer);
+                                    _state=State.START;
+                                    ((ProxyHandler)_requestHandler).proxied(protocol,sAddr,dAddr,sPort,dPort);
+                                    return false;
+                                }
+                            }
+                            else
+                            {
+                                int pos = buffer.position()+version.asString().length()-1;
+                                if (pos<buffer.limit())
+                                {
+                                    byte n=buffer.get(pos);
+                                    if (n==HttpTokens.CARRIAGE_RETURN)
+                                    {
+                                        _cr=true;
+                                        _version=version;
+                                        _string.setLength(0);
+                                        buffer.position(pos+1);
+                                    }
+                                    else if (n==HttpTokens.LINE_FEED)
+                                    {
+                                        _version=version;
+                                        _string.setLength(0);
+                                        buffer.position(pos);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    else if (ch == HttpTokens.LINE_FEED)
+                    {
+                        if (_responseHandler!=null)
+                        {
+                            handle=_responseHandler.startResponse(_version, _responseStatus, null)||handle;
+                            setState(State.HEADER);
+                        }
+                        else
+                        {
+                            // HTTP/0.9
+                            _uri.flip();
+                            handle=_requestHandler.startRequest(_method,_methodString,_uri, null)||handle;
+                            setState(State.END);
+                            BufferUtil.clear(buffer);
+                            handle=_handler.headerComplete()||handle;
+                            handle=_handler.messageComplete()||handle;
+                        }
+                    }
+                    else if (ch<0)
+                        throw new BadMessage();
+                    break;
+
+                case REQUEST_VERSION:
+                    if (ch == HttpTokens.LINE_FEED)
+                    {
+                        if (_version==null)
+                        {
+                            _length=_string.length();
+                            _version=HttpVersion.CACHE.get(takeString());
+                        }
+                        if (_version==null)
+                            throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Unknown Version");
+                        
+                        // Should we try to cache header fields?
+                        if (_connectionFields==null && _version.getVersion()>=HttpVersion.HTTP_1_1.getVersion())
+                        {
+                            int header_cache = _handler.getHeaderCacheSize();
+                            _connectionFields=new ArrayTernaryTrie<>(header_cache);                            
+                        }
+
+                        setState(State.HEADER);
+                        _uri.flip();
+                        handle=_requestHandler.startRequest(_method,_methodString,_uri, _version)||handle;
+                        continue;
+                    }
+                    else if (ch>=HttpTokens.SPACE)
+                        _string.append((char)ch);
+                    else
+                        throw new BadMessage();
+
+                    break;
+
+                case REASON:
+                    if (ch == HttpTokens.LINE_FEED)
+                    {
+                        String reason=takeString();
+
+                        setState(State.HEADER);
+                        handle=_responseHandler.startResponse(_version, _responseStatus, reason)||handle;
+                        continue;
+                    }
+                    else if (ch>=HttpTokens.SPACE)
+                    {
+                        _string.append((char)ch);
+                        if (ch!=' '&&ch!='\t')
+                            _length=_string.length();
+                    } 
+                    else
+                        throw new BadMessage();
+                    break;
+
+                default:
+                    throw new IllegalStateException(_state.toString());
+
+            }
+        }
+
+        return handle;
+    }
+
+    private boolean handleKnownHeaders(ByteBuffer buffer)
+    {
+        boolean add_to_connection_trie=false;
+        switch (_header)
+        {
+            case CONTENT_LENGTH:
+                if (_endOfContent != EndOfContent.CHUNKED_CONTENT)
+                {
+                    try
+                    {
+                        _contentLength=Long.parseLong(_valueString);
+                    }
+                    catch(NumberFormatException e)
+                    {
+                        LOG.ignore(e);
+                        throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad Content-Length");
+                    }
+                    if (_contentLength <= 0)
+                        _endOfContent=EndOfContent.NO_CONTENT;
+                    else
+                        _endOfContent=EndOfContent.CONTENT_LENGTH;
+                }
+                break;
+
+            case TRANSFER_ENCODING:
+                if (_value==HttpHeaderValue.CHUNKED)
+                    _endOfContent=EndOfContent.CHUNKED_CONTENT;
+                else
+                {
+                    if (_valueString.endsWith(HttpHeaderValue.CHUNKED.toString()))
+                        _endOfContent=EndOfContent.CHUNKED_CONTENT;
+                    else if (_valueString.contains(HttpHeaderValue.CHUNKED.toString()))
+                    {
+                        throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad chunking");
+                    }
+                }
+                break;
+
+            case HOST:
+                add_to_connection_trie=_connectionFields!=null && _field==null;
+                _host=true;
+                String host=_valueString;
+                int port=0;
+                if (host==null || host.length()==0)
+                {
+                    throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad Host header");
+                }
+
+                int len=host.length();
+                loop: for (int i = len; i-- > 0;)
+                {
+                    char c2 = (char)(0xff & host.charAt(i));
+                    switch (c2)
+                    {
+                        case ']':
+                            break loop;
+
+                        case ':':
+                            try
+                            {
+                                len=i;
+                                port = StringUtil.toInt(host.substring(i+1));
+                            }
+                            catch (NumberFormatException e)
+                            {
+                                if (DEBUG)
+                                    LOG.debug(e);
+                                throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad Host header");
+                            }
+                            break loop;
+                    }
+                }
+                if (host.charAt(0)=='[')
+                {
+                    if (host.charAt(len-1)!=']') 
+                    {
+                        throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad IPv6 Host header");
+                    }
+                    host = host.substring(1,len-1);
+                }
+                else if (len!=host.length())
+                    host = host.substring(0,len);
+                
+                if (_requestHandler!=null)
+                    _requestHandler.parsedHostHeader(host,port);
+                
+              break;
+              
+            case CONNECTION:
+                // Don't cache if not persistent
+                if (_valueString!=null && _valueString.contains("close"))
+                {
+                    _closed=true;
+                    _connectionFields=null;
+                }
+                break;
+
+            case AUTHORIZATION:
+            case ACCEPT:
+            case ACCEPT_CHARSET:
+            case ACCEPT_ENCODING:
+            case ACCEPT_LANGUAGE:
+            case COOKIE:
+            case CACHE_CONTROL:
+            case USER_AGENT:
+                add_to_connection_trie=_connectionFields!=null && _field==null;
+                break;
+                
+            default: break;
+        }
+    
+        if (add_to_connection_trie && !_connectionFields.isFull() && _header!=null && _valueString!=null)
+        {
+            _field=new HttpField(_header,_valueString);
+            _connectionFields.put(_field);
+        }
+        
+        return false;
+    }
+    
+    
+    /* ------------------------------------------------------------------------------- */
+    /*
+     * Parse the message headers and return true if the handler has signaled for a return
+     */
+    protected boolean parseHeaders(ByteBuffer buffer)
+    {
+        boolean handle=false;
+
+        // Process headers
+        while (_state.ordinal()<State.CONTENT.ordinal() && buffer.hasRemaining() && !handle)
+        {
+            // process each character
+            byte ch=next(buffer);
+            if (ch==0)
+                break;
+            
+            if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes)
+            {
+                LOG.warn("Header is too large >"+_maxHeaderBytes);
+                throw new BadMessage(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413);
+            }
+
+            switch (_state)
+            {
+                case HEADER:
+                    switch(ch)
+                    {
+                        case HttpTokens.COLON:
+                        case HttpTokens.SPACE:
+                        case HttpTokens.TAB:
+                        {
+                            // header value without name - continuation?
+                            if (_valueString==null)
+                            {
+                                _string.setLength(0);
+                                _length=0;
+                            }
+                            else
+                            {
+                                setString(_valueString);
+                                _string.append(' ');
+                                _length++;
+                                _valueString=null;
+                            }
+                            setState(State.HEADER_VALUE);
+                            break;
+                        }
+
+                        default:
+                        {
+                            // handler last header if any.  Delayed to here just in case there was a continuation line (above)
+                            if (_headerString!=null || _valueString!=null)
+                            {
+                                // Handle known headers
+                                if (_header!=null && handleKnownHeaders(buffer))
+                                {
+                                    _headerString=_valueString=null;
+                                    _header=null;
+                                    _value=null;
+                                    _field=null;
+                                    return true;
+                                }
+                                handle=_handler.parsedHeader(_field!=null?_field:new HttpField(_header,_headerString,_valueString))||handle;
+                            }
+                            _headerString=_valueString=null;
+                            _header=null;
+                            _value=null;
+                            _field=null;
+
+                            // now handle the ch
+                            if (ch == HttpTokens.LINE_FEED)
+                            {
+                                _contentPosition=0;
+
+                                // End of headers!
+
+                                // Was there a required host header?
+                                if (!_host && _version!=HttpVersion.HTTP_1_0 && _requestHandler!=null)
+                                {
+                                    throw new BadMessage(HttpStatus.BAD_REQUEST_400,"No Host");
+                                }
+
+                                // is it a response that cannot have a body?
+                                if (_responseHandler !=null  && // response  
+                                    (_responseStatus == 304  || // not-modified response
+                                    _responseStatus == 204 || // no-content response
+                                    _responseStatus < 200)) // 1xx response
+                                    _endOfContent=EndOfContent.NO_CONTENT; // ignore any other headers set
+                                
+                                // else if we don't know framing
+                                else if (_endOfContent == EndOfContent.UNKNOWN_CONTENT)
+                                {
+                                    if (_responseStatus == 0  // request
+                                            || _responseStatus == 304 // not-modified response
+                                            || _responseStatus == 204 // no-content response
+                                            || _responseStatus < 200) // 1xx response
+                                        _endOfContent=EndOfContent.NO_CONTENT;
+                                    else
+                                        _endOfContent=EndOfContent.EOF_CONTENT;
+                                }
+
+                                // How is the message ended?
+                                switch (_endOfContent)
+                                {
+                                    case EOF_CONTENT:
+                                        setState(State.EOF_CONTENT);
+                                        handle=_handler.headerComplete()||handle;
+                                        break;
+
+                                    case CHUNKED_CONTENT:
+                                        setState(State.CHUNKED_CONTENT);
+                                        handle=_handler.headerComplete()||handle;
+                                        break;
+
+                                    case NO_CONTENT:
+                                        handle=_handler.headerComplete()||handle;
+                                        setState(State.END);
+                                        handle=_handler.messageComplete()||handle;
+                                        break;
+
+                                    default:
+                                        setState(State.CONTENT);
+                                        handle=_handler.headerComplete()||handle;
+                                        break;
+                                }
+                            }
+                            else if (ch<=HttpTokens.SPACE)
+                                throw new BadMessage();
+                            else
+                            {
+                                if (buffer.hasRemaining())
+                                {
+                                    // Try a look ahead for the known header name and value.
+                                    HttpField field=_connectionFields==null?null:_connectionFields.getBest(buffer,-1,buffer.remaining());
+                                    if (field==null)
+                                        field=CACHE.getBest(buffer,-1,buffer.remaining());
+                                        
+                                    if (field!=null)
+                                    {
+                                        final String n;
+                                        final String v;
+
+                                        if (_strict)
+                                        {
+                                            // Have to get the fields exactly from the buffer to match case
+                                            String fn=field.getName();
+                                            String fv=field.getValue();
+                                            n=BufferUtil.toString(buffer,buffer.position()-1,fn.length(),StandardCharsets.US_ASCII);
+                                            if (fv==null)
+                                                v=null;
+                                            else
+                                            {
+                                                v=BufferUtil.toString(buffer,buffer.position()+fn.length()+1,fv.length(),StandardCharsets.ISO_8859_1);
+                                                field=new HttpField(field.getHeader(),n,v);
+                                            }
+                                        }
+                                        else
+                                        {
+                                            n=field.getName();
+                                            v=field.getValue(); 
+                                        }
+                                        
+                                        _header=field.getHeader();
+                                        _headerString=n;
+         
+                                        if (v==null)
+                                        {
+                                            // Header only
+                                            setState(State.HEADER_VALUE);
+                                            _string.setLength(0);
+                                            _length=0;
+                                            buffer.position(buffer.position()+n.length()+1);
+                                            break;
+                                        }
+                                        else
+                                        {
+                                            // Header and value
+                                            int pos=buffer.position()+n.length()+v.length()+1;
+                                            byte b=buffer.get(pos);
+
+                                            if (b==HttpTokens.CARRIAGE_RETURN || b==HttpTokens.LINE_FEED)
+                                            {                     
+                                                _field=field;
+                                                _valueString=v;
+                                                setState(State.HEADER_IN_VALUE);
+
+                                                if (b==HttpTokens.CARRIAGE_RETURN)
+                                                {
+                                                    _cr=true;
+                                                    buffer.position(pos+1);
+                                                }
+                                                else
+                                                    buffer.position(pos);
+                                                break;
+                                            }
+                                            else
+                                            {
+                                                setState(State.HEADER_IN_VALUE);
+                                                setString(v);
+                                                buffer.position(pos);
+                                                break;
+                                            }
+                                        }
+                                    }
+                                }
+
+                                // New header
+                                setState(State.HEADER_IN_NAME);
+                                _string.setLength(0);
+                                _string.append((char)ch);
+                                _length=1;
+                            }
+                        }
+                    }
+                    break;
+
+                case HEADER_IN_NAME:
+                    if (ch==HttpTokens.COLON || ch==HttpTokens.LINE_FEED)
+                    {
+                        if (_headerString==null)
+                        {
+                            _headerString=takeString();
+                            _header=HttpHeader.CACHE.get(_headerString);
+                        }
+                        _length=-1;
+
+                        setState(ch==HttpTokens.LINE_FEED?State.HEADER:State.HEADER_VALUE);
+                        break;
+                    }
+                    
+                    if (ch>=HttpTokens.SPACE || ch==HttpTokens.TAB)
+                    {
+                        if (_header!=null)
+                        {
+                            setString(_header.asString());
+                            _header=null;
+                            _headerString=null;
+                        }
+
+                        _string.append((char)ch);
+                        if (ch>HttpTokens.SPACE)
+                            _length=_string.length();
+                        break;
+                    }
+                     
+                    throw new BadMessage("Illegal character");
+
+                case HEADER_VALUE:
+                    if (ch>HttpTokens.SPACE || ch<0)
+                    {
+                        _string.append((char)(0xff&ch));
+                        _length=_string.length();
+                        setState(State.HEADER_IN_VALUE);
+                        break;
+                    }
+                    
+                    if (ch==HttpTokens.SPACE || ch==HttpTokens.TAB)
+                        break;
+                    
+                    if (ch==HttpTokens.LINE_FEED)
+                    {
+                        if (_length > 0)
+                        {
+                            _value=null;
+                            _valueString=(_valueString==null)?takeString():(_valueString+" "+takeString());
+                        }
+                        setState(State.HEADER);
+                        break; 
+                    }
+
+                    throw new BadMessage("Illegal character");
+
+                case HEADER_IN_VALUE:
+                    if (ch>=HttpTokens.SPACE || ch<0 || ch==HttpTokens.TAB)
+                    {
+                        if (_valueString!=null)
+                        {
+                            setString(_valueString);
+                            _valueString=null;
+                            _field=null;
+                        }
+                        _string.append((char)(0xff&ch));
+                        if (ch>HttpTokens.SPACE || ch<0)
+                            _length=_string.length();
+                        break;
+                    }
+                    
+                    if (ch==HttpTokens.LINE_FEED)
+                    {
+                        if (_length > 0)
+                        {
+                            _value=null;
+                            _valueString=takeString();
+                            _length=-1;
+                        }
+                        setState(State.HEADER);
+                        break;
+                    }
+                    throw new BadMessage("Illegal character");
+                    
+                default:
+                    throw new IllegalStateException(_state.toString());
+
+            }
+        }
+
+        return handle;
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    /**
+     * Parse until next Event.
+     * @return True if an {@link RequestHandler} method was called and it returned true;
+     */
+    public boolean parseNext(ByteBuffer buffer)
+    {
+        if (DEBUG)
+            LOG.debug("parseNext s={} {}",_state,BufferUtil.toDetailString(buffer));
+        try
+        {
+            // Start a request/response
+            if (_state==State.START)
+            {
+                _version=null;
+                _method=null;
+                _methodString=null;
+                _endOfContent=EndOfContent.UNKNOWN_CONTENT;
+                _header=null;
+                if (quickStart(buffer))
+                    return true;
+            }
+            
+            // Request/response line
+            if (_state.ordinal()>= State.START.ordinal() && _state.ordinal()<State.HEADER.ordinal())
+            {
+                if (parseLine(buffer))
+                    return true;
+            }
+
+            // parse headers
+            if (_state.ordinal()>= State.HEADER.ordinal() && _state.ordinal()<State.CONTENT.ordinal())
+            {
+                if (parseHeaders(buffer))
+                    return true;
+            }
+            
+            // parse content
+            if (_state.ordinal()>= State.CONTENT.ordinal() && _state.ordinal()<State.END.ordinal())
+            {
+                // Handle HEAD response
+                if (_responseStatus>0 && _headResponse)
+                {
+                    setState(State.END);
+                    if (_handler.messageComplete())
+                        return true;
+                }
+                else
+                {
+                    if (parseContent(buffer))
+                        return true;
+                }
+            }
+            
+            // handle end states
+            if (_state==State.END)
+            {
+                // eat white space
+                while (buffer.remaining()>0 && buffer.get(buffer.position())<=HttpTokens.SPACE)
+                    buffer.get();
+            }
+            else if (_state==State.CLOSED)
+            {
+                if (BufferUtil.hasContent(buffer))
+                {
+                    // Just ignore data when closed
+                    _headerBytes+=buffer.remaining();
+                    BufferUtil.clear(buffer);
+                    if (_headerBytes>_maxHeaderBytes)
+                    {
+                        // Don't want to waste time reading data of a closed request
+                        throw new IllegalStateException("too much data after closed");
+                    }
+                }
+            }
+            
+            // Handle EOF
+            if (_eof && !buffer.hasRemaining())
+            {
+                switch(_state)
+                {
+                    case CLOSED:
+                        break;
+                        
+                    case START:
+                        setState(State.CLOSED);
+                        _handler.earlyEOF();
+                        break;
+                        
+                    case END:
+                        setState(State.CLOSED);
+                        break;
+                        
+                    case EOF_CONTENT:
+                        setState(State.CLOSED);
+                        return _handler.messageComplete();
+
+                    case  CONTENT:
+                    case  CHUNKED_CONTENT:
+                    case  CHUNK_SIZE:
+                    case  CHUNK_PARAMS:
+                    case  CHUNK:
+                        setState(State.CLOSED);
+                        _handler.earlyEOF();
+                        break;
+
+                    default:
+                        if (DEBUG)
+                            LOG.debug("{} EOF in {}",this,_state);
+                        setState(State.CLOSED);
+                        _handler.badMessage(400,null);
+                        break;
+                }
+            }
+            
+            return false;
+        }
+        catch(BadMessage e)
+        {
+            BufferUtil.clear(buffer);
+
+            LOG.warn("badMessage: "+e._code+(e._message!=null?" "+e._message:"")+" for "+_handler);
+            if (DEBUG)
+                LOG.debug(e);
+            setState(State.CLOSED);
+            _handler.badMessage(e._code, e._message);
+            return false;
+        }
+        catch(Exception e)
+        {
+            BufferUtil.clear(buffer);
+
+            LOG.warn("badMessage: "+e.toString()+" for "+_handler);
+            if (DEBUG)
+                LOG.debug(e);
+            
+            if (_state.ordinal()<=State.END.ordinal())
+            {
+                setState(State.CLOSED);
+                _handler.badMessage(400,null);
+            }
+            else
+            {
+                _handler.earlyEOF();
+                setState(State.CLOSED);
+            }
+
+            return false;
+        }
+    }
+
+    protected boolean parseContent(ByteBuffer buffer)
+    {
+        int remaining=buffer.remaining();
+        if (remaining==0 && _state==State.CONTENT)
+        {
+            long content=_contentLength - _contentPosition;
+            if (content == 0)
+            {
+                setState(State.END);
+                if (_handler.messageComplete())
+                    return true;
+            }
+        }
+        
+        // Handle _content
+        byte ch;
+        while (_state.ordinal() < State.END.ordinal() && remaining>0)
+        {
+            switch (_state)
+            {
+                case EOF_CONTENT:
+                    _contentChunk=buffer.asReadOnlyBuffer();
+                    _contentPosition += remaining;
+                    buffer.position(buffer.position()+remaining);
+                    if (_handler.content(_contentChunk))
+                        return true;
+                    break;
+
+                case CONTENT:
+                {
+                    long content=_contentLength - _contentPosition;
+                    if (content == 0)
+                    {
+                        setState(State.END);
+                        if (_handler.messageComplete())
+                            return true;
+                    }
+                    else
+                    {
+                        _contentChunk=buffer.asReadOnlyBuffer();
+
+                        // limit content by expected size
+                        if (remaining > content)
+                        {
+                            // We can cast remaining to an int as we know that it is smaller than
+                            // or equal to length which is already an int.
+                            _contentChunk.limit(_contentChunk.position()+(int)content);
+                        }
+
+                        _contentPosition += _contentChunk.remaining();
+                        buffer.position(buffer.position()+_contentChunk.remaining());
+
+                        if (_handler.content(_contentChunk))
+                            return true;
+
+                        if(_contentPosition == _contentLength)
+                        {
+                            setState(State.END);
+                            if (_handler.messageComplete())
+                                return true;
+                        }
+                    }
+                    break;
+                }
+
+                case CHUNKED_CONTENT:
+                {
+                    ch=next(buffer);
+                    if (ch>HttpTokens.SPACE)
+                    {
+                        _chunkLength=TypeUtil.convertHexDigit(ch);
+                        _chunkPosition=0;
+                        setState(State.CHUNK_SIZE);
+                    }
+
+                    break;
+                }
+
+                case CHUNK_SIZE:
+                {
+                    ch=next(buffer);
+                    if (ch==0)
+                        break;
+                    if (ch == HttpTokens.LINE_FEED)
+                    {
+                        if (_chunkLength == 0)
+                        {
+                            setState(State.END);
+                            if (_handler.messageComplete())
+                                return true;
+                        }
+                        else
+                            setState(State.CHUNK);
+                    }
+                    else if (ch <= HttpTokens.SPACE || ch == HttpTokens.SEMI_COLON)
+                        setState(State.CHUNK_PARAMS);
+                    else
+                        _chunkLength=_chunkLength * 16 + TypeUtil.convertHexDigit(ch);
+                    break;
+                }
+
+                case CHUNK_PARAMS:
+                {
+                    ch=next(buffer);
+                    if (ch == HttpTokens.LINE_FEED)
+                    {
+                        if (_chunkLength == 0)
+                        {
+                            setState(State.END);
+                            if (_handler.messageComplete())
+                                return true;
+                        }
+                        else
+                            setState(State.CHUNK);
+                    }
+                    break;
+                }
+
+                case CHUNK:
+                {
+                    int chunk=_chunkLength - _chunkPosition;
+                    if (chunk == 0)
+                    {
+                        setState(State.CHUNKED_CONTENT);
+                    }
+                    else
+                    {
+                        _contentChunk=buffer.asReadOnlyBuffer();
+
+                        if (remaining > chunk)
+                            _contentChunk.limit(_contentChunk.position()+chunk);
+                        chunk=_contentChunk.remaining();
+
+                        _contentPosition += chunk;
+                        _chunkPosition += chunk;
+                        buffer.position(buffer.position()+chunk);
+                        if (_handler.content(_contentChunk))
+                            return true;
+                    }
+                    break;
+                }
+                
+                case CLOSED:
+                {
+                    BufferUtil.clear(buffer);
+                    return false;
+                }
+
+                default: 
+                    break;
+                    
+            }
+            
+            remaining=buffer.remaining();
+        }
+        return false;
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    public boolean isAtEOF()
+    {
+        return _eof;
+    }
+    
+    /* ------------------------------------------------------------------------------- */
+    public void atEOF()
+
+    {        
+        if (DEBUG)
+            LOG.debug("atEOF {}", this);
+        _eof=true;
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    public void close()
+    {
+        if (DEBUG)
+            LOG.debug("close {}", this);
+        setState(State.CLOSED);
+    }
+    
+    /* ------------------------------------------------------------------------------- */
+    public void reset()
+    {
+        if (DEBUG)
+            LOG.debug("reset {}", this);
+        // reset state
+        if (_state==State.CLOSED)
+            return;
+        if (_closed)
+        {
+            setState(State.CLOSED);
+            return;
+        }
+        
+        setState(State.START);
+        _endOfContent=EndOfContent.UNKNOWN_CONTENT;
+        _contentLength=-1;
+        _contentPosition=0;
+        _responseStatus=0;
+        _contentChunk=null;
+        _headerBytes=0;
+        _host=false;
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    protected void setState(State state)
+    {
+        if (DEBUG)
+            LOG.debug("{} --> {}",_state,state);
+        _state=state;
+    }
+
+    /* ------------------------------------------------------------------------------- */
+    @Override
+    public String toString()
+    {
+        return String.format("%s{s=%s,%d of %d}",
+                getClass().getSimpleName(),
+                _state,
+                _contentPosition,
+                _contentLength);
+    }
+
+    /* ------------------------------------------------------------ */
+    /* ------------------------------------------------------------ */
+    /* ------------------------------------------------------------ */
+    /* Event Handler interface
+     * These methods return true if the caller should process the events
+     * so far received (eg return from parseNext and call HttpChannel.handle).
+     * If multiple callbacks are called in sequence (eg 
+     * headerComplete then messageComplete) from the same point in the parsing
+     * then it is sufficient for the caller to process the events only once.
+     */
+    public interface HttpHandler<T>
+    {
+        public boolean content(T item);
+
+        public boolean headerComplete();
+
+        public boolean messageComplete();
+
+        /**
+         * This is the method called by parser when a HTTP Header name and value is found
+         * @param field The field parsed
+         * @return True if the parser should return to its caller
+         */
+        public boolean parsedHeader(HttpField field);
+
+        /* ------------------------------------------------------------ */
+        /** Called to signal that an EOF was received unexpectedly
+         * during the parsing of a HTTP message
+         */
+        public void earlyEOF();
+
+        /* ------------------------------------------------------------ */
+        /** Called to signal that a bad HTTP message has been received.
+         * @param status The bad status to send
+         * @param reason The textual reason for badness
+         */
+        public void badMessage(int status, String reason);
+        
+        /* ------------------------------------------------------------ */
+        /** @return the size in bytes of the per parser header cache
+         */
+        public int getHeaderCacheSize();
+    }
+
+    public interface ProxyHandler 
+    {
+        void proxied(String protocol, String sAddr, String dAddr, int sPort, int dPort);
+    }
+    
+    public interface RequestHandler<T> extends HttpHandler<T>
+    {
+        /**
+         * This is the method called by parser when the HTTP request line is parsed
+         * @param method The method as enum if of a known type
+         * @param methodString The method as a string
+         * @param uri The raw bytes of the URI.  These are copied into a ByteBuffer that will not be changed until this parser is reset and reused.
+         * @param version
+         * @return true if handling parsing should return.
+         */
+        public abstract boolean startRequest(HttpMethod method, String methodString, ByteBuffer uri, HttpVersion version);
+
+        /**
+         * This is the method called by the parser after it has parsed the host header (and checked it's format). This is
+         * called after the {@link HttpHandler#parsedHeader(HttpField)} methods and before
+         * HttpHandler#headerComplete();
+         */
+        public abstract boolean parsedHostHeader(String host,int port);
+    }
+
+    public interface ResponseHandler<T> extends HttpHandler<T>
+    {
+        /**
+         * This is the method called by parser when the HTTP request line is parsed
+         */
+        public abstract boolean startResponse(HttpVersion version, int status, String reason);
+    }
+
+    public Trie<HttpField> getFieldCache()
+    {
+        return _connectionFields;
+    }
+
+    private String getProxyField(ByteBuffer buffer)
+    {
+        _string.setLength(0);
+        _length=0;
+        
+        while (buffer.hasRemaining())
+        {
+            // process each character
+            byte ch=next(buffer);
+            if (ch<=' ')
+                return _string.toString();
+            _string.append((char)ch);    
+        }
+        throw new BadMessage();
+    }
+}
diff --git a/lib/jetty/org/eclipse/jetty/http/HttpScheme.java b/lib/jetty/org/eclipse/jetty/http/HttpScheme.java
new file mode 100644 (file)
index 0000000..13f2a8d
--- /dev/null
@@ -0,0 +1,79 @@
+//
+//  ========================================================================
+//  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.http;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.jetty.util.ArrayTrie;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.Trie;
+
+/* ------------------------------------------------------------------------------- */
+/**
+ */
+public enum HttpScheme
+{
+    HTTP("http"),
+    HTTPS("https"),
+    WS("ws"),
+    WSS("wss");
+
+    /* ------------------------------------------------------------ */
+    public final static Trie<HttpScheme> CACHE= new ArrayTrie<HttpScheme>();
+    static
+    {
+        for (HttpScheme version : HttpScheme.values())
+            CACHE.put(version.asString(),version);
+    }
+
+    private final String _string;
+    private final ByteBuffer _buffer;
+
+    /* ------------------------------------------------------------ */
+    HttpScheme(String s)
+    {
+        _string=s;
+        _buffer=BufferUtil.toBuffer(s);
+    }
+
+    /* ------------------------------------------------------------ */
+    public ByteBuffer asByteBuffer()
+    {
+        return _buffer.asReadOnlyBuffer();
+    }
+
+    /* ------------------------------------------------------------ */
+    public boolean is(String s)
+    {
+        return _string.equalsIgnoreCase(s);
+    }
+
+    public String asString()
+    {
+        return _string;
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public String toString()
+    {
+        return _string;
+    }
+
+}
diff --git a/lib/jetty/org/eclipse/jetty/http/HttpStatus.java b/lib/jetty/org/eclipse/jetty/http/HttpStatus.java
new file mode 100644 (file)
index 0000000..e6ea1f7
--- /dev/null
@@ -0,0 +1,1037 @@
+//
+//  ========================================================================
+//  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.http;
+
+/**
+ * <p>
+ * HttpStatusCode enum class, for status codes based on various HTTP RFCs. (see
+ * table below)
+ * </p>
+ *
+ * <table border="1" cellpadding="5">
+ * <tr>
+ * <th>Enum</th>
+ * <th>Code</th>
+ * <th>Message</th>
+ * <th>
+ * <a href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a></th>
+ * <th>
+ * <a href="http://tools.ietf.org/html/rfc2616">RFC 2616 - HTTP/1.1</a></th>
+ * <th>
+ * <a href="http://tools.ietf.org/html/rfc2518">RFC 2518 - WEBDAV</a></th>
+ * </tr>
+ *
+ * <tr>
+ * <td><strong><code>Informational - 1xx</code></strong></td>
+ * <td colspan="5">{@link #isInformational(int)}</td>
+ * </tr>
+ *
+ * <tr>
+ * <td>{@link #CONTINUE_100}</td>
+ * <td>100</td>
+ * <td>Continue</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.1.1">Sec. 10.1.1</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #SWITCHING_PROTOCOLS_101}</td>
+ * <td>101</td>
+ * <td>Switching Protocols</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.1.2">Sec. 10.1.2</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #PROCESSING_102}</td>
+ * <td>102</td>
+ * <td>Processing</td>
+ * <td>&nbsp;</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2518#section-10.1">Sec. 10.1</a></td>
+ * </tr>
+ *
+ * <tr>
+ * <td><strong><code>Success - 2xx</code></strong></td>
+ * <td colspan="5">{@link #isSuccess(int)}</td>
+ * </tr>
+ *
+ * <tr>
+ * <td>{@link #OK_200}</td>
+ * <td>200</td>
+ * <td>OK</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc1945#section-9.2">Sec. 9.2</a></td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.2.1">Sec. 10.2.1</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #CREATED_201}</td>
+ * <td>201</td>
+ * <td>Created</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc1945#section-9.2">Sec. 9.2</a></td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.2.2">Sec. 10.2.2</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #ACCEPTED_202}</td>
+ * <td>202</td>
+ * <td>Accepted</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc1945#section-9.2">Sec. 9.2</a></td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.2.3">Sec. 10.2.3</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #NON_AUTHORITATIVE_INFORMATION_203}</td>
+ * <td>203</td>
+ * <td>Non Authoritative Information</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.2.4">Sec. 10.2.4</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #NO_CONTENT_204}</td>
+ * <td>204</td>
+ * <td>No Content</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc1945#section-9.2">Sec. 9.2</a></td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.2.5">Sec. 10.2.5</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #RESET_CONTENT_205}</td>
+ * <td>205</td>
+ * <td>Reset Content</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.2.6">Sec. 10.2.6</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #PARTIAL_CONTENT_206}</td>
+ * <td>206</td>
+ * <td>Partial Content</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.2.7">Sec. 10.2.7</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #MULTI_STATUS_207}</td>
+ * <td>207</td>
+ * <td>Multi-Status</td>
+ * <td>&nbsp;</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2518#section-10.2">Sec. 10.2</a></td>
+ * </tr>
+ * <tr>
+ * <td>&nbsp;</td>
+ * <td><strike>207</strike></td>
+ * <td><strike>Partial Update OK</strike></td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href=
+ * "http://www.w3.org/Protocols/HTTP/1.1/draft-ietf-http-v11-spec-rev-01.txt"
+ * >draft/01</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ *
+ * <tr>
+ * <td><strong><code>Redirection - 3xx</code></strong></td>
+ * <td colspan="5">{@link #isRedirection(int)}</td>
+ * </tr>
+ *
+ * <tr>
+ * <td>{@link #MULTIPLE_CHOICES_300}</td>
+ * <td>300</td>
+ * <td>Multiple Choices</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc1945#section-9.3">Sec. 9.3</a></td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.3.1">Sec. 10.3.1</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #MOVED_PERMANENTLY_301}</td>
+ * <td>301</td>
+ * <td>Moved Permanently</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc1945#section-9.3">Sec. 9.3</a></td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.3.2">Sec. 10.3.2</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #MOVED_TEMPORARILY_302}</td>
+ * <td>302</td>
+ * <td>Moved Temporarily</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc1945#section-9.3">Sec. 9.3</a></td>
+ * <td>(now "<code>302 Found</code>")</td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #FOUND_302}</td>
+ * <td>302</td>
+ * <td>Found</td>
+ * <td>(was "<code>302 Moved Temporarily</code>")</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.3.3">Sec. 10.3.3</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #SEE_OTHER_303}</td>
+ * <td>303</td>
+ * <td>See Other</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.3.4">Sec. 10.3.4</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #NOT_MODIFIED_304}</td>
+ * <td>304</td>
+ * <td>Not Modified</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc1945#section-9.3">Sec. 9.3</a></td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.3.5">Sec. 10.3.5</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #USE_PROXY_305}</td>
+ * <td>305</td>
+ * <td>Use Proxy</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.3.6">Sec. 10.3.6</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>&nbsp;</td>
+ * <td>306</td>
+ * <td><em>(Unused)</em></td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.3.7">Sec. 10.3.7</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #TEMPORARY_REDIRECT_307}</td>
+ * <td>307</td>
+ * <td>Temporary Redirect</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.3.8">Sec. 10.3.8</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ *
+ * <tr>
+ * <td><strong><code>Client Error - 4xx</code></strong></td>
+ * <td colspan="5">{@link #isClientError(int)}</td>
+ * </tr>
+ *
+ * <tr>
+ * <td>{@link #BAD_REQUEST_400}</td>
+ * <td>400</td>
+ * <td>Bad Request</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc1945#section-9.4">Sec. 9.4</a></td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.1">Sec. 10.4.1</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #UNAUTHORIZED_401}</td>
+ * <td>401</td>
+ * <td>Unauthorized</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc1945#section-9.4">Sec. 9.4</a></td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.2">Sec. 10.4.2</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #PAYMENT_REQUIRED_402}</td>
+ * <td>402</td>
+ * <td>Payment Required</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc1945#section-9.4">Sec. 9.4</a></td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.3">Sec. 10.4.3</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #FORBIDDEN_403}</td>
+ * <td>403</td>
+ * <td>Forbidden</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc1945#section-9.4">Sec. 9.4</a></td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.4">Sec. 10.4.4</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #NOT_FOUND_404}</td>
+ * <td>404</td>
+ * <td>Not Found</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc1945#section-9.4">Sec. 9.4</a></td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.5">Sec. 10.4.5</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #METHOD_NOT_ALLOWED_405}</td>
+ * <td>405</td>
+ * <td>Method Not Allowed</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.6">Sec. 10.4.6</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #NOT_ACCEPTABLE_406}</td>
+ * <td>406</td>
+ * <td>Not Acceptable</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.7">Sec. 10.4.7</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #PROXY_AUTHENTICATION_REQUIRED_407}</td>
+ * <td>407</td>
+ * <td>Proxy Authentication Required</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.8">Sec. 10.4.8</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #REQUEST_TIMEOUT_408}</td>
+ * <td>408</td>
+ * <td>Request Timeout</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.9">Sec. 10.4.9</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #CONFLICT_409}</td>
+ * <td>409</td>
+ * <td>Conflict</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.10">Sec. 10.4.10</a>
+ * </td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #GONE_410}</td>
+ * <td>410</td>
+ * <td>Gone</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.11">Sec. 10.4.11</a>
+ * </td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #LENGTH_REQUIRED_411}</td>
+ * <td>411</td>
+ * <td>Length Required</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.12">Sec. 10.4.12</a>
+ * </td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #PRECONDITION_FAILED_412}</td>
+ * <td>412</td>
+ * <td>Precondition Failed</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.13">Sec. 10.4.13</a>
+ * </td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #REQUEST_ENTITY_TOO_LARGE_413}</td>
+ * <td>413</td>
+ * <td>Request Entity Too Large</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.14">Sec. 10.4.14</a>
+ * </td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #REQUEST_URI_TOO_LONG_414}</td>
+ * <td>414</td>
+ * <td>Request-URI Too Long</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.15">Sec. 10.4.15</a>
+ * </td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #UNSUPPORTED_MEDIA_TYPE_415}</td>
+ * <td>415</td>
+ * <td>Unsupported Media Type</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.16">Sec. 10.4.16</a>
+ * </td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #REQUESTED_RANGE_NOT_SATISFIABLE_416}</td>
+ * <td>416</td>
+ * <td>Requested Range Not Satisfiable</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.17">Sec. 10.4.17</a>
+ * </td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #EXPECTATION_FAILED_417}</td>
+ * <td>417</td>
+ * <td>Expectation Failed</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.4.18">Sec. 10.4.18</a>
+ * </td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>&nbsp;</td>
+ * <td><strike>418</strike></td>
+ * <td><strike>Reauthentication Required</strike></td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href=
+ * "http://tools.ietf.org/html/draft-ietf-http-v11-spec-rev-01#section-10.4.19"
+ * >draft/01</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>&nbsp;</td>
+ * <td><strike>418</strike></td>
+ * <td><strike>Unprocessable Entity</strike></td>
+ * <td>&nbsp;</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href=
+ * "http://tools.ietf.org/html/draft-ietf-webdav-protocol-05#section-10.3"
+ * >draft/05</a></td>
+ * </tr>
+ * <tr>
+ * <td>&nbsp;</td>
+ * <td><strike>419</strike></td>
+ * <td><strike>Proxy Reauthentication Required</stike></td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href=
+ * "http://tools.ietf.org/html/draft-ietf-http-v11-spec-rev-01#section-10.4.20"
+ * >draft/01</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>&nbsp;</td>
+ * <td><strike>419</strike></td>
+ * <td><strike>Insufficient Space on Resource</stike></td>
+ * <td>&nbsp;</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href=
+ * "http://tools.ietf.org/html/draft-ietf-webdav-protocol-05#section-10.4"
+ * >draft/05</a></td>
+ * </tr>
+ * <tr>
+ * <td>&nbsp;</td>
+ * <td><strike>420</strike></td>
+ * <td><strike>Method Failure</strike></td>
+ * <td>&nbsp;</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href=
+ * "http://tools.ietf.org/html/draft-ietf-webdav-protocol-05#section-10.5"
+ * >draft/05</a></td>
+ * </tr>
+ * <tr>
+ * <td>&nbsp;</td>
+ * <td>421</td>
+ * <td><em>(Unused)</em></td>
+ * <td>&nbsp;</td>
+ * <td>&nbsp;</td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #UNPROCESSABLE_ENTITY_422}</td>
+ * <td>422</td>
+ * <td>Unprocessable Entity</td>
+ * <td>&nbsp;</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2518#section-10.3">Sec. 10.3</a></td>
+ * </tr>
+ * <tr>
+ * <td>{@link #LOCKED_423}</td>
+ * <td>423</td>
+ * <td>Locked</td>
+ * <td>&nbsp;</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2518#section-10.4">Sec. 10.4</a></td>
+ * </tr>
+ * <tr>
+ * <td>{@link #FAILED_DEPENDENCY_424}</td>
+ * <td>424</td>
+ * <td>Failed Dependency</td>
+ * <td>&nbsp;</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2518#section-10.5">Sec. 10.5</a></td>
+ * </tr>
+ *
+ * <tr>
+ * <td><strong><code>Server Error - 5xx</code></strong></td>
+ * <td colspan="5">{@link #isServerError(int)}</td>
+ * </tr>
+ *
+ * <tr>
+ * <td>{@link #INTERNAL_SERVER_ERROR_500}</td>
+ * <td>500</td>
+ * <td>Internal Server Error</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc1945#section-9.5">Sec. 9.5</a></td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.5.1">Sec. 10.5.1</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #NOT_IMPLEMENTED_501}</td>
+ * <td>501</td>
+ * <td>Not Implemented</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc1945#section-9.5">Sec. 9.5</a></td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.5.2">Sec. 10.5.2</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #BAD_GATEWAY_502}</td>
+ * <td>502</td>
+ * <td>Bad Gateway</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc1945#section-9.5">Sec. 9.5</a></td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.5.3">Sec. 10.5.3</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #SERVICE_UNAVAILABLE_503}</td>
+ * <td>503</td>
+ * <td>Service Unavailable</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc1945#section-9.5">Sec. 9.5</a></td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.5.4">Sec. 10.5.4</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #GATEWAY_TIMEOUT_504}</td>
+ * <td>504</td>
+ * <td>Gateway Timeout</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.5.5">Sec. 10.5.5</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #HTTP_VERSION_NOT_SUPPORTED_505}</td>
+ * <td>505</td>
+ * <td>HTTP Version Not Supported</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2616#section-10.5.6">Sec. 10.5.6</a></td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>&nbsp;</td>
+ * <td>506</td>
+ * <td><em>(Unused)</em></td>
+ * <td>&nbsp;</td>
+ * <td>&nbsp;</td>
+ * <td>&nbsp;</td>
+ * </tr>
+ * <tr>
+ * <td>{@link #INSUFFICIENT_STORAGE_507}</td>
+ * <td>507</td>
+ * <td>Insufficient Storage</td>
+ * <td>&nbsp;</td>
+ * <td>&nbsp;</td>
+ * <td>
+ * <a href="http://tools.ietf.org/html/rfc2518#section-10.6">Sec. 10.6</a></td>
+ * </tr>
+ *
+ * </table>
+ *
+ * @version $Id$
+ */
+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;
+
+    public final static int OK_200 = 200;
+    public final static int CREATED_201 = 201;
+    public final static int ACCEPTED_202 = 202;
+    public final static int NON_AUTHORITATIVE_INFORMATION_203 = 203;
+    public final static int NO_CONTENT_204 = 204;
+    public final static int RESET_CONTENT_205 = 205;
+    public final static int PARTIAL_CONTENT_206 = 206;
+    public final static int MULTI_STATUS_207 = 207;
+
+    public final static int MULTIPLE_CHOICES_300 = 300;
+    public final static int MOVED_PERMANENTLY_301 = 301;
+    public final static int MOVED_TEMPORARILY_302 = 302;
+    public final static int FOUND_302 = 302;
+    public final static int SEE_OTHER_303 = 303;
+    public final static int NOT_MODIFIED_304 = 304;
+    public final static int USE_PROXY_305 = 305;
+    public final static int TEMPORARY_REDIRECT_307 = 307;
+
+    public final static int BAD_REQUEST_400 = 400;
+    public final static int UNAUTHORIZED_401 = 401;
+    public final static int PAYMENT_REQUIRED_402 = 402;
+    public final static int FORBIDDEN_403 = 403;
+    public final static int NOT_FOUND_404 = 404;
+    public final static int METHOD_NOT_ALLOWED_405 = 405;
+    public final static int NOT_ACCEPTABLE_406 = 406;
+    public final static int PROXY_AUTHENTICATION_REQUIRED_407 = 407;
+    public final static int REQUEST_TIMEOUT_408 = 408;
+    public final static int CONFLICT_409 = 409;
+    public final static int GONE_410 = 410;
+    public final static int LENGTH_REQUIRED_411 = 411;
+    public final static int PRECONDITION_FAILED_412 = 412;
+    public final static int REQUEST_ENTITY_TOO_LARGE_413 = 413;
+    public final static int REQUEST_URI_TOO_LONG_414 = 414;
+    public final static int UNSUPPORTED_MEDIA_TYPE_415 = 415;
+    public final static int REQUESTED_RANGE_NOT_SATISFIABLE_416 = 416;
+    public final static int EXPECTATION_FAILED_417 = 417;
+    public final static int UNPROCESSABLE_ENTITY_422 = 422;
+    public final static int LOCKED_423 = 423;
+    public final static int FAILED_DEPENDENCY_424 = 424;
+
+    public final static int INTERNAL_SERVER_ERROR_500 = 500;
+    public final static int NOT_IMPLEMENTED_501 = 501;
+    public final static int BAD_GATEWAY_502 = 502;
+    public final static int SERVICE_UNAVAILABLE_503 = 503;
+    public final static int GATEWAY_TIMEOUT_504 = 504;
+    public final static int HTTP_VERSION_NOT_SUPPORTED_505 = 505;
+    public final static int INSUFFICIENT_STORAGE_507 = 507;
+
+    public static final int MAX_CODE = 507;
+
+
+    private static final Code[] codeMap = new Code[MAX_CODE+1];
+
+    static
+    {
+        for (Code code : Code.values())
+        {
+            codeMap[code._code] = code;
+        }
+    }
+
+
+    public enum Code
+    {
+        /*
+         * --------------------------------------------------------------------
+         * Informational messages in 1xx series. As defined by ... RFC 1945 -
+         * HTTP/1.0 RFC 2616 - HTTP/1.1 RFC 2518 - WebDAV
+         */
+
+        /** <code>100 Continue</code> */
+        CONTINUE(CONTINUE_100, "Continue"),
+        /** <code>101 Switching Protocols</code> */
+        SWITCHING_PROTOCOLS(SWITCHING_PROTOCOLS_101, "Switching Protocols"),
+        /** <code>102 Processing</code> */
+        PROCESSING(PROCESSING_102, "Processing"),
+
+        /*
+         * --------------------------------------------------------------------
+         * Success messages in 2xx series. As defined by ... RFC 1945 - HTTP/1.0
+         * RFC 2616 - HTTP/1.1 RFC 2518 - WebDAV
+         */
+
+        /** <code>200 OK</code> */
+        OK(OK_200, "OK"),
+        /** <code>201 Created</code> */
+        CREATED(CREATED_201, "Created"),
+        /** <code>202 Accepted</code> */
+        ACCEPTED(ACCEPTED_202, "Accepted"),
+        /** <code>203 Non Authoritative Information</code> */
+        NON_AUTHORITATIVE_INFORMATION(NON_AUTHORITATIVE_INFORMATION_203, "Non Authoritative Information"),
+        /** <code>204 No Content</code> */
+        NO_CONTENT(NO_CONTENT_204, "No Content"),
+        /** <code>205 Reset Content</code> */
+        RESET_CONTENT(RESET_CONTENT_205, "Reset Content"),
+        /** <code>206 Partial Content</code> */
+        PARTIAL_CONTENT(PARTIAL_CONTENT_206, "Partial Content"),
+        /** <code>207 Multi-Status</code> */
+        MULTI_STATUS(MULTI_STATUS_207, "Multi-Status"),
+
+        /*
+         * --------------------------------------------------------------------
+         * Redirection messages in 3xx series. As defined by ... RFC 1945 -
+         * HTTP/1.0 RFC 2616 - HTTP/1.1
+         */
+
+        /** <code>300 Mutliple Choices</code> */
+        MULTIPLE_CHOICES(MULTIPLE_CHOICES_300, "Multiple Choices"),
+        /** <code>301 Moved Permanently</code> */
+        MOVED_PERMANENTLY(MOVED_PERMANENTLY_301, "Moved Permanently"),
+        /** <code>302 Moved Temporarily</code> */
+        MOVED_TEMPORARILY(MOVED_TEMPORARILY_302, "Moved Temporarily"),
+        /** <code>302 Found</code> */
+        FOUND(FOUND_302, "Found"),
+        /** <code>303 See Other</code> */
+        SEE_OTHER(SEE_OTHER_303, "See Other"),
+        /** <code>304 Not Modified</code> */
+        NOT_MODIFIED(NOT_MODIFIED_304, "Not Modified"),
+        /** <code>305 Use Proxy</code> */
+        USE_PROXY(USE_PROXY_305, "Use Proxy"),
+        /** <code>307 Temporary Redirect</code> */
+        TEMPORARY_REDIRECT(TEMPORARY_REDIRECT_307, "Temporary Redirect"),
+
+        /*
+         * --------------------------------------------------------------------
+         * Client Error messages in 4xx series. As defined by ... RFC 1945 -
+         * HTTP/1.0 RFC 2616 - HTTP/1.1 RFC 2518 - WebDAV
+         */
+
+        /** <code>400 Bad Request</code> */
+        BAD_REQUEST(BAD_REQUEST_400, "Bad Request"),
+        /** <code>401 Unauthorized</code> */
+        UNAUTHORIZED(UNAUTHORIZED_401, "Unauthorized"),
+        /** <code>402 Payment Required</code> */
+        PAYMENT_REQUIRED(PAYMENT_REQUIRED_402, "Payment Required"),
+        /** <code>403 Forbidden</code> */
+        FORBIDDEN(FORBIDDEN_403, "Forbidden"),
+        /** <code>404 Not Found</code> */
+        NOT_FOUND(NOT_FOUND_404, "Not Found"),
+        /** <code>405 Method Not Allowed</code> */
+        METHOD_NOT_ALLOWED(METHOD_NOT_ALLOWED_405, "Method Not Allowed"),
+        /** <code>406 Not Acceptable</code> */
+        NOT_ACCEPTABLE(NOT_ACCEPTABLE_406, "Not Acceptable"),
+        /** <code>407 Proxy Authentication Required</code> */
+        PROXY_AUTHENTICATION_REQUIRED(PROXY_AUTHENTICATION_REQUIRED_407, "Proxy Authentication Required"),
+        /** <code>408 Request Timeout</code> */
+        REQUEST_TIMEOUT(REQUEST_TIMEOUT_408, "Request Timeout"),
+        /** <code>409 Conflict</code> */
+        CONFLICT(CONFLICT_409, "Conflict"),
+        /** <code>410 Gone</code> */
+        GONE(GONE_410, "Gone"),
+        /** <code>411 Length Required</code> */
+        LENGTH_REQUIRED(LENGTH_REQUIRED_411, "Length Required"),
+        /** <code>412 Precondition Failed</code> */
+        PRECONDITION_FAILED(PRECONDITION_FAILED_412, "Precondition Failed"),
+        /** <code>413 Request Entity Too Large</code> */
+        REQUEST_ENTITY_TOO_LARGE(REQUEST_ENTITY_TOO_LARGE_413, "Request Entity Too Large"),
+        /** <code>414 Request-URI Too Long</code> */
+        REQUEST_URI_TOO_LONG(REQUEST_URI_TOO_LONG_414, "Request-URI Too Long"),
+        /** <code>415 Unsupported Media Type</code> */
+        UNSUPPORTED_MEDIA_TYPE(UNSUPPORTED_MEDIA_TYPE_415, "Unsupported Media Type"),
+        /** <code>416 Requested Range Not Satisfiable</code> */
+        REQUESTED_RANGE_NOT_SATISFIABLE(REQUESTED_RANGE_NOT_SATISFIABLE_416, "Requested Range Not Satisfiable"),
+        /** <code>417 Expectation Failed</code> */
+        EXPECTATION_FAILED(EXPECTATION_FAILED_417, "Expectation Failed"),
+        /** <code>422 Unprocessable Entity</code> */
+        UNPROCESSABLE_ENTITY(UNPROCESSABLE_ENTITY_422, "Unprocessable Entity"),
+        /** <code>423 Locked</code> */
+        LOCKED(LOCKED_423, "Locked"),
+        /** <code>424 Failed Dependency</code> */
+        FAILED_DEPENDENCY(FAILED_DEPENDENCY_424, "Failed Dependency"),
+
+        /*
+         * --------------------------------------------------------------------
+         * Server Error messages in 5xx series. As defined by ... RFC 1945 -
+         * HTTP/1.0 RFC 2616 - HTTP/1.1 RFC 2518 - WebDAV
+         */
+
+        /** <code>500 Server Error</code> */
+        INTERNAL_SERVER_ERROR(INTERNAL_SERVER_ERROR_500, "Server Error"),
+        /** <code>501 Not Implemented</code> */
+        NOT_IMPLEMENTED(NOT_IMPLEMENTED_501, "Not Implemented"),
+        /** <code>502 Bad Gateway</code> */
+        BAD_GATEWAY(BAD_GATEWAY_502, "Bad Gateway"),
+        /** <code>503 Service Unavailable</code> */
+        SERVICE_UNAVAILABLE(SERVICE_UNAVAILABLE_503, "Service Unavailable"),
+        /** <code>504 Gateway Timeout</code> */
+        GATEWAY_TIMEOUT(GATEWAY_TIMEOUT_504, "Gateway Timeout"),
+        /** <code>505 HTTP Version Not Supported</code> */
+        HTTP_VERSION_NOT_SUPPORTED(HTTP_VERSION_NOT_SUPPORTED_505, "HTTP Version Not Supported"),
+        /** <code>507 Insufficient Storage</code> */
+        INSUFFICIENT_STORAGE(INSUFFICIENT_STORAGE_507, "Insufficient Storage");
+
+        private final int _code;
+        private final String _message;
+
+        private Code(int code, String message)
+        {
+            this._code = code;
+            _message=message;
+        }
+
+        public int getCode()
+        {
+            return _code;
+        }
+
+        public String getMessage()
+        {
+            return _message;
+        }
+
+
+        public boolean equals(int code)
+        {
+            return (this._code == code);
+        }
+
+        @Override
+        public String toString()
+        {
+            return String.format("[%03d %s]",this._code,this.getMessage());
+        }
+
+        /**
+         * Simple test against an code to determine if it falls into the
+         * <code>Informational</code> message category as defined in the <a
+         * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>,
+         * and <a href="http://tools.ietf.org/html/rfc2616">RFC 2616 -
+         * HTTP/1.1</a>.
+         *
+         * @return true if within range of codes that belongs to
+         *         <code>Informational</code> messages.
+         */
+        public boolean isInformational()
+        {
+            return HttpStatus.isInformational(this._code);
+        }
+
+        /**
+         * Simple test against an code to determine if it falls into the
+         * <code>Success</code> message category as defined in the <a
+         * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>,
+         * and <a href="http://tools.ietf.org/html/rfc2616">RFC 2616 -
+         * HTTP/1.1</a>.
+         *
+         * @return true if within range of codes that belongs to
+         *         <code>Success</code> messages.
+         */
+        public boolean isSuccess()
+        {
+            return HttpStatus.isSuccess(this._code);
+        }
+
+        /**
+         * Simple test against an code to determine if it falls into the
+         * <code>Redirection</code> message category as defined in the <a
+         * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>,
+         * and <a href="http://tools.ietf.org/html/rfc2616">RFC 2616 -
+         * HTTP/1.1</a>.
+         *
+         * @return true if within range of codes that belongs to
+         *         <code>Redirection</code> messages.
+         */
+        public boolean isRedirection()
+        {
+            return HttpStatus.isRedirection(this._code);
+        }
+
+        /**
+         * Simple test against an code to determine if it falls into the
+         * <code>Client Error</code> message category as defined in the <a
+         * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>,
+         * and <a href="http://tools.ietf.org/html/rfc2616">RFC 2616 -
+         * HTTP/1.1</a>.
+         *
+         * @return true if within range of codes that belongs to
+         *         <code>Client Error</code> messages.
+         */
+        public boolean isClientError()
+        {
+            return HttpStatus.isClientError(this._code);
+        }
+
+        /**
+         * Simple test against an code to determine if it falls into the
+         * <code>Server Error</code> message category as defined in the <a
+         * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>,
+         * and <a href="http://tools.ietf.org/html/rfc2616">RFC 2616 -
+         * HTTP/1.1</a>.
+         *
+         * @return true if within range of codes that belongs to
+         *         <code>Server Error</code> messages.
+         */
+        public boolean isServerError()
+        {
+            return HttpStatus.isServerError(this._code);
+        }
+    }
+
+
+    /**
+     * Get the HttpStatusCode for a specific code
+     *
+     * @param code
+     *            the code to lookup.
+     * @return the {@link HttpStatus} if found, or null if not found.
+     */
+    public static Code getCode(int code)
+    {
+        if (code <= MAX_CODE)
+        {
+            return codeMap[code];
+        }
+        return null;
+    }
+
+    /**
+     * Get the status message for a specific code.
+     *
+     * @param code
+     *            the code to look up
+     * @return the specific message, or the code number itself if code
+     *         does not match known list.
+     */
+    public static String getMessage(int code)
+    {
+        Code codeEnum = getCode(code);
+        if (codeEnum != null)
+        {
+            return codeEnum.getMessage();
+        }
+        else
+        {
+            return Integer.toString(code);
+        }
+    }
+
+    /**
+     * Simple test against an code to determine if it falls into the
+     * <code>Informational</code> message category as defined in the <a
+     * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>, and <a
+     * href="http://tools.ietf.org/html/rfc2616">RFC 2616 - HTTP/1.1</a>.
+     *
+     * @param code
+     *            the code to test.
+     * @return true if within range of codes that belongs to
+     *         <code>Informational</code> messages.
+     */
+    public static boolean isInformational(int code)
+    {
+        return ((100 <= code) && (code <= 199));
+    }
+
+    /**
+     * Simple test against an code to determine if it falls into the
+     * <code>Success</code> message category as defined in the <a
+     * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>, and <a
+     * href="http://tools.ietf.org/html/rfc2616">RFC 2616 - HTTP/1.1</a>.
+     *
+     * @param code
+     *            the code to test.
+     * @return true if within range of codes that belongs to
+     *         <code>Success</code> messages.
+     */
+    public static boolean isSuccess(int code)
+    {
+        return ((200 <= code) && (code <= 299));
+    }
+
+    /**
+     * Simple test against an code to determine if it falls into the
+     * <code>Redirection</code> message category as defined in the <a
+     * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>, and <a
+     * href="http://tools.ietf.org/html/rfc2616">RFC 2616 - HTTP/1.1</a>.
+     *
+     * @param code
+     *            the code to test.
+     * @return true if within range of codes that belongs to
+     *         <code>Redirection</code> messages.
+     */
+    public static boolean isRedirection(int code)
+    {
+        return ((300 <= code) && (code <= 399));
+    }
+
+    /**
+     * Simple test against an code to determine if it falls into the
+     * <code>Client Error</code> message category as defined in the <a
+     * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>, and <a
+     * href="http://tools.ietf.org/html/rfc2616">RFC 2616 - HTTP/1.1</a>.
+     *
+     * @param code
+     *            the code to test.
+     * @return true if within range of codes that belongs to
+     *         <code>Client Error</code> messages.
+     */
+    public static boolean isClientError(int code)
+    {
+        return ((400 <= code) && (code <= 499));
+    }
+
+    /**
+     * Simple test against an code to determine if it falls into the
+     * <code>Server Error</code> message category as defined in the <a
+     * href="http://tools.ietf.org/html/rfc1945">RFC 1945 - HTTP/1.0</a>, and <a
+     * href="http://tools.ietf.org/html/rfc2616">RFC 2616 - HTTP/1.1</a>.
+     *
+     * @param code
+     *            the code to test.
+     * @return true if within range of codes that belongs to
+     *         <code>Server Error</code> messages.
+     */
+    public static boolean isServerError(int code)
+    {
+        return ((500 <= code) && (code <= 599));
+    }
+}
diff --git a/lib/jetty/org/eclipse/jetty/http/HttpTester.java b/lib/jetty/org/eclipse/jetty/http/HttpTester.java
new file mode 100644 (file)
index 0000000..537c457
--- /dev/null
@@ -0,0 +1,367 @@
+//
+//  ========================================================================
+//  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.http;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+
+import org.eclipse.jetty.http.HttpGenerator.RequestInfo;
+import org.eclipse.jetty.http.HttpGenerator.ResponseInfo;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.StringUtil;
+
+public class HttpTester
+{
+    private HttpTester()
+    {
+    }
+
+    public static Request newRequest()
+    {
+        return new Request();
+    }
+
+    public static Request parseRequest(String request)
+    {
+        Request r=new Request();
+        HttpParser parser =new HttpParser(r);
+        parser.parseNext(BufferUtil.toBuffer(request));
+        return r;
+    }
+
+    public static Request parseRequest(ByteBuffer request)
+    {
+        Request r=new Request();
+        HttpParser parser =new HttpParser(r);
+        parser.parseNext(request);
+        return r;
+    }
+
+    public static Response parseResponse(String response)
+    {
+        Response r=new Response();
+        HttpParser parser =new HttpParser(r);
+        parser.parseNext(BufferUtil.toBuffer(response));
+        return r;
+    }
+
+    public static Response parseResponse(ByteBuffer response)
+    {
+        Response r=new Response();
+        HttpParser parser =new HttpParser(r);
+        parser.parseNext(response);
+        return r;
+    }
+
+
+    public abstract static class Message extends HttpFields implements HttpParser.HttpHandler<ByteBuffer>
+    {
+        ByteArrayOutputStream _content;
+        HttpVersion _version=HttpVersion.HTTP_1_0;
+
+        public HttpVersion getVersion()
+        {
+            return _version;
+        }
+
+        public void setVersion(String version)
+        {
+            setVersion(HttpVersion.CACHE.get(version));
+        }
+
+        public void setVersion(HttpVersion version)
+        {
+            _version=version;
+        }
+
+        public void setContent(byte[] bytes)
+        {
+            try
+            {
+                _content=new ByteArrayOutputStream();
+                _content.write(bytes);
+            }
+            catch (IOException e)
+            {
+                throw new RuntimeException(e);
+            }
+        }
+
+        public void setContent(String content)
+        {
+            try
+            {
+                _content=new ByteArrayOutputStream();
+                _content.write(StringUtil.getBytes(content));
+            }
+            catch (IOException e)
+            {
+                throw new RuntimeException(e);
+            }
+        }
+
+        public void setContent(ByteBuffer content)
+        {
+            try
+            {
+                _content=new ByteArrayOutputStream();
+                _content.write(BufferUtil.toArray(content));
+            }
+            catch (IOException e)
+            {
+                throw new RuntimeException(e);
+            }
+        }
+        @Override
+        public boolean parsedHeader(HttpField field)
+        {
+            put(field.getName(),field.getValue());
+            return false;
+        }
+
+        @Override
+        public boolean messageComplete()
+        {
+            return true;
+        }
+
+        @Override
+        public boolean headerComplete()
+        {
+            _content=new ByteArrayOutputStream();
+            return false;
+        }
+
+        @Override
+        public void earlyEOF()
+        {
+        }
+
+        @Override
+        public boolean content(ByteBuffer ref)
+        {
+            try
+            {
+                _content.write(BufferUtil.toArray(ref));
+            }
+            catch (IOException e)
+            {
+                throw new RuntimeException(e);
+            }
+            return false;
+        }
+
+        @Override
+        public void badMessage(int status, String reason)
+        {
+            throw new RuntimeException(reason);
+        }
+
+        public ByteBuffer generate()
+        {
+            try
+            {
+                HttpGenerator generator = new HttpGenerator();
+                HttpGenerator.Info info = getInfo();
+                // System.err.println(info.getClass());
+                // System.err.println(info);
+
+                ByteArrayOutputStream out = new ByteArrayOutputStream();
+                ByteBuffer header=null;
+                ByteBuffer chunk=null;
+                ByteBuffer content=_content==null?null:ByteBuffer.wrap(_content.toByteArray());
+
+
+                loop: while(!generator.isEnd())
+                {
+                    HttpGenerator.Result result =  info instanceof RequestInfo
+                        ?generator.generateRequest((RequestInfo)info,header,chunk,content,true)
+                        :generator.generateResponse((ResponseInfo)info,header,chunk,content,true);
+                    switch(result)
+                    {
+                        case NEED_HEADER:
+                            header=BufferUtil.allocate(8192);
+                            continue;
+
+                        case NEED_CHUNK:
+                            chunk=BufferUtil.allocate(HttpGenerator.CHUNK_SIZE);
+                            continue;
+
+                        case NEED_INFO:
+                            throw new IllegalStateException();
+
+                        case FLUSH:
+                            if (BufferUtil.hasContent(header))
+                            {
+                                out.write(BufferUtil.toArray(header));
+                                BufferUtil.clear(header);
+                            }
+                            if (BufferUtil.hasContent(chunk))
+                            {
+                                out.write(BufferUtil.toArray(chunk));
+                                BufferUtil.clear(chunk);
+                            }
+                            if (BufferUtil.hasContent(content))
+                            {
+                                out.write(BufferUtil.toArray(content));
+                                BufferUtil.clear(content);
+                            }
+                            break;
+
+                        case SHUTDOWN_OUT:
+                            break loop;
+                    }
+                }
+
+                return ByteBuffer.wrap(out.toByteArray());
+            }
+            catch (IOException e)
+            {
+                throw new RuntimeException(e);
+            }
+
+        }
+        abstract public HttpGenerator.Info getInfo();
+
+        @Override
+        public int getHeaderCacheSize()
+        {
+            return 0;
+        }
+
+    }
+
+    public static class Request extends Message implements HttpParser.RequestHandler<ByteBuffer>
+    {
+        private String _method;
+        private String _uri;
+
+        @Override
+        public boolean startRequest(HttpMethod method, String methodString, ByteBuffer uri, HttpVersion version)
+        {
+            _method=methodString;
+            _uri=BufferUtil.toUTF8String(uri);
+            _version=version;
+            return false;
+        }
+
+        public String getMethod()
+        {
+            return _method;
+        }
+
+        public String getUri()
+        {
+            return _uri;
+        }
+
+        public void setMethod(String method)
+        {
+            _method=method;
+        }
+
+        public void setURI(String uri)
+        {
+            _uri=uri;
+        }
+
+        @Override
+        public HttpGenerator.RequestInfo getInfo()
+        {
+            return new HttpGenerator.RequestInfo(_version,this,_content==null?0:_content.size(),_method,_uri);
+        }
+
+        @Override
+        public String toString()
+        {
+            return String.format("%s %s %s\n%s\n",_method,_uri,_version,super.toString());
+        }
+
+        public void setHeader(String name, String value)
+        {
+            put(name,value);
+        }
+
+        @Override
+        public boolean parsedHostHeader(String host,int port)
+        {
+            return false;
+        }
+    }
+
+    public static class Response extends Message implements HttpParser.ResponseHandler<ByteBuffer>
+    {
+        private int _status;
+        private String _reason;
+
+        @Override
+        public boolean startResponse(HttpVersion version, int status, String reason)
+        {
+            _version=version;
+            _status=status;
+            _reason=reason;
+            return false;
+        }
+
+        public int getStatus()
+        {
+            return _status;
+        }
+
+        public String getReason()
+        {
+            return _reason;
+        }
+
+        public byte[] getContentBytes()
+        {
+            if (_content==null)
+                return null;
+            return _content.toByteArray();
+        }
+
+        public String getContent()
+        {
+            if (_content==null)
+                return null;
+            byte[] bytes=_content.toByteArray();
+
+            String content_type=get(HttpHeader.CONTENT_TYPE);
+            String encoding=MimeTypes.getCharsetFromContentType(content_type);
+            Charset charset=encoding==null?StandardCharsets.UTF_8:Charset.forName(encoding);
+
+            return new String(bytes,charset);
+        }
+
+        @Override
+        public HttpGenerator.ResponseInfo getInfo()
+        {
+            return new HttpGenerator.ResponseInfo(_version,this,_content==null?-1:_content.size(),_status,_reason,false);
+        }
+
+        @Override
+        public String toString()
+        {
+            return String.format("%s %s %s\n%s\n",_version,_status,_reason,super.toString());
+        }
+    }
+}
diff --git a/lib/jetty/org/eclipse/jetty/http/HttpTokens.java b/lib/jetty/org/eclipse/jetty/http/HttpTokens.java
new file mode 100644 (file)
index 0000000..4138334
--- /dev/null
@@ -0,0 +1,38 @@
+//
+//  ========================================================================
+//  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.http;
+
+/**
+ * HTTP constants
+ */
+public interface HttpTokens
+{
+    // Terminal symbols.
+    static final byte COLON= (byte)':';
+    static final byte TAB= 0x09;
+    static final byte LINE_FEED= 0x0A;
+    static final byte CARRIAGE_RETURN= 0x0D;
+    static final byte SPACE= 0x20;
+    static final byte[] CRLF = {CARRIAGE_RETURN,LINE_FEED};
+    static final byte SEMI_COLON= (byte)';';
+
+    public enum EndOfContent { UNKNOWN_CONTENT,NO_CONTENT,EOF_CONTENT,CONTENT_LENGTH,CHUNKED_CONTENT,SELF_DEFINING_CONTENT }
+
+}
+
diff --git a/lib/jetty/org/eclipse/jetty/http/HttpURI.java b/lib/jetty/org/eclipse/jetty/http/HttpURI.java
new file mode 100644 (file)
index 0000000..afe925e
--- /dev/null
@@ -0,0 +1,784 @@
+//
+//  ========================================================================
+//  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.http;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+
+import org.eclipse.jetty.util.MultiMap;
+import org.eclipse.jetty.util.StringUtil;
+import org.eclipse.jetty.util.TypeUtil;
+import org.eclipse.jetty.util.URIUtil;
+import org.eclipse.jetty.util.UrlEncoded;
+import org.eclipse.jetty.util.Utf8StringBuilder;
+
+
+/* ------------------------------------------------------------ */
+/** Http URI.
+ * Parse a HTTP URI from a string or byte array.  Given a URI
+ * <code>http://user@host:port/path/info;param?query#fragment</code>
+ * this class will split it into the following undecoded optional elements:<ul>
+ * <li>{@link #getScheme()} - http:</li>
+ * <li>{@link #getAuthority()} - //name@host:port</li>
+ * <li>{@link #getHost()} - host</li>
+ * <li>{@link #getPort()} - port</li>
+ * <li>{@link #getPath()} - /path/info</li>
+ * <li>{@link #getParam()} - param</li>
+ * <li>{@link #getQuery()} - query</li>
+ * <li>{@link #getFragment()} - fragment</li>
+ * </ul>
+ *
+ */
+public class HttpURI
+{
+    private static final byte[] __empty={};
+    private final static int
+    START=0,
+    AUTH_OR_PATH=1,
+    SCHEME_OR_PATH=2,
+    AUTH=4,
+    IPV6=5,
+    PORT=6,
+    PATH=7,
+    PARAM=8,
+    QUERY=9,
+    ASTERISK=10;
+
+    final Charset _charset;
+    boolean _partial=false;
+    byte[] _raw=__empty;
+    String _rawString;
+    int _scheme;
+    int _authority;
+    int _host;
+    int _port;
+    int _portValue;
+    int _path;
+    int _param;
+    int _query;
+    int _fragment;
+    int _end;
+    boolean _encoded=false;
+
+    public HttpURI()
+    {
+        _charset = URIUtil.__CHARSET;
+    }
+
+    public HttpURI(Charset charset)
+    {
+        _charset = charset;
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @param parsePartialAuth If True, parse auth without prior scheme, else treat all URIs starting with / as paths
+     */
+    public HttpURI(boolean parsePartialAuth)
+    {
+        _partial=parsePartialAuth;
+        _charset = URIUtil.__CHARSET;
+    }
+
+    public HttpURI(String raw)
+    {
+        _rawString=raw;
+        byte[] b = raw.getBytes(StandardCharsets.UTF_8);
+        parse(b,0,b.length);
+        _charset = URIUtil.__CHARSET;
+    }
+
+    public HttpURI(byte[] raw,int offset, int length)
+    {
+        parse2(raw,offset,length);
+        _charset = URIUtil.__CHARSET;
+    }
+
+    public HttpURI(URI uri)
+    {
+        parse(uri.toASCIIString());
+        _charset = URIUtil.__CHARSET;
+    }
+
+    public void parse(String raw)
+    {
+        byte[] b = StringUtil.getUtf8Bytes(raw);
+        parse2(b,0,b.length);
+        _rawString=raw;
+    }
+
+    public void parseConnect(String raw)
+    {
+        byte[] b = StringUtil.getBytes(raw);
+        parseConnect(b,0,b.length);
+        _rawString=raw;
+    }
+
+    public void parse(byte[] raw,int offset, int length)
+    {
+        _rawString=null;
+        parse2(raw,offset,length);
+    }
+
+
+    public void parseConnect(byte[] raw,int offset, int length)
+    {
+        _rawString=null;
+        _encoded=false;
+        _raw=raw;
+        int i=offset;
+        int e=offset+length;
+        int state=AUTH;
+        _end=offset+length;
+        _scheme=offset;
+        _authority=offset;
+        _host=offset;
+        _port=_end;
+        _portValue=-1;
+        _path=_end;
+        _param=_end;
+        _query=_end;
+        _fragment=_end;
+
+        loop: while (i<e)
+        {
+            char c=(char)(0xff&_raw[i]);
+            int s=i++;
+
+            switch (state)
+            {
+                case AUTH:
+                {
+                    switch (c)
+                    {
+                        case ':':
+                        {
+                            _port = s;
+                            break loop;
+                        }
+                        case '[':
+                        {
+                            state = IPV6;
+                            break;
+                        }
+                    }
+                    continue;
+                }
+
+                case IPV6:
+                {
+                    switch (c)
+                    {
+                        case '/':
+                        {
+                            throw new IllegalArgumentException("No closing ']' for " + new String(_raw,offset,length,_charset));
+                        }
+                        case ']':
+                        {
+                            state = AUTH;
+                            break;
+                        }
+                    }
+
+                    continue;
+                }
+            }
+        }
+
+        if (_port<_path)
+            _portValue=TypeUtil.parseInt(_raw, _port+1, _path-_port-1,10);
+        else
+            throw new IllegalArgumentException("No port");
+        _path=offset;
+    }
+
+
+    private void parse2(byte[] raw,int offset, int length)
+    {
+        _encoded=false;
+        _raw=raw;
+        int i=offset;
+        int e=offset+length;
+        int state=START;
+        int m=offset;
+        _end=offset+length;
+        _scheme=offset;
+        _authority=offset;
+        _host=offset;
+        _port=offset;
+        _portValue=-1;
+        _path=offset;
+        _param=_end;
+        _query=_end;
+        _fragment=_end;
+        while (i<e)
+        {
+            char c=(char)(0xff&_raw[i]);
+            int s=i++;
+
+            state: switch (state)
+            {
+                case START:
+                {
+                    m=s;
+                    switch(c)
+                    {
+                        case '/':
+                            state=AUTH_OR_PATH;
+                            break;
+                        case ';':
+                            _param=s;
+                            state=PARAM;
+                            break;
+                        case '?':
+                            _param=s;
+                            _query=s;
+                            state=QUERY;
+                            break;
+                        case '#':
+                            _param=s;
+                            _query=s;
+                            _fragment=s;
+                            break;
+                        case '*':
+                            _path=s;
+                            state=ASTERISK;
+                            break;
+
+                        default:
+                            state=SCHEME_OR_PATH;
+                    }
+
+                    continue;
+                }
+
+                case AUTH_OR_PATH:
+                {
+                    if ((_partial||_scheme!=_authority) && c=='/')
+                    {
+                        _host=i;
+                        _port=_end;
+                        _path=_end;
+                        state=AUTH;
+                    }
+                    else if (c==';' || c=='?' || c=='#')
+                    {
+                        i--;
+                        state=PATH;
+                    }
+                    else
+                    {
+                        _host=m;
+                        _port=m;
+                        state=PATH;
+                    }
+                    continue;
+                }
+
+                case SCHEME_OR_PATH:
+                {
+                    // short cut for http and https
+                    if (length>6 && c=='t')
+                    {
+                        if (_raw[offset+3]==':')
+                        {
+                            s=offset+3;
+                            i=offset+4;
+                            c=':';
+                        }
+                        else if (_raw[offset+4]==':')
+                        {
+                            s=offset+4;
+                            i=offset+5;
+                            c=':';
+                        }
+                        else if (_raw[offset+5]==':')
+                        {
+                            s=offset+5;
+                            i=offset+6;
+                            c=':';
+                        }
+                    }
+
+                    switch (c)
+                    {
+                        case ':':
+                        {
+                            m = i++;
+                            _authority = m;
+                            _path = m;
+                            c = (char)(0xff & _raw[i]);
+                            if (c == '/')
+                                state = AUTH_OR_PATH;
+                            else
+                            {
+                                _host = m;
+                                _port = m;
+                                state = PATH;
+                            }
+                            break;
+                        }
+
+                        case '/':
+                        {
+                            state = PATH;
+                            break;
+                        }
+
+                        case ';':
+                        {
+                            _param = s;
+                            state = PARAM;
+                            break;
+                        }
+
+                        case '?':
+                        {
+                            _param = s;
+                            _query = s;
+                            state = QUERY;
+                            break;
+                        }
+
+                        case '#':
+                        {
+                            _param = s;
+                            _query = s;
+                            _fragment = s;
+                            break;
+                        }
+                    }
+                    continue;
+                }
+
+                case AUTH:
+                {
+                    switch (c)
+                    {
+
+                        case '/':
+                        {
+                            m = s;
+                            _path = m;
+                            _port = _path;
+                            state = PATH;
+                            break;
+                        }
+                        case '@':
+                        {
+                            _host = i;
+                            break;
+                        }
+                        case ':':
+                        {
+                            _port = s;
+                            state = PORT;
+                            break;
+                        }
+                        case '[':
+                        {
+                            state = IPV6;
+                            break;
+                        }
+                    }
+                    continue;
+                }
+
+                case IPV6:
+                {
+                    switch (c)
+                    {
+                        case '/':
+                        {
+                            throw new IllegalArgumentException("No closing ']' for " + new String(_raw,offset,length,_charset));
+                        }
+                        case ']':
+                        {
+                            state = AUTH;
+                            break;
+                        }
+                    }
+
+                    continue;
+                }
+
+                case PORT:
+                {
+